storing original upload filename (web2py) - python

I'm attempting to do something simple and documented well, except for that it's not working on my web app.
essentally i want to save some extra attributes for the uploaded files, like original filename, email of user and also the upload date.
Now following the web2py documentation i've created this submit view. It is almost word for word copied from the documentation section here
I have a controller data.py
def submit():
import datetime
form = SQLFORM(db.uploads, fields=['up_file'], deletable=True)
form.vars.up_date = datetime.datetime.now()
form.vars.username = auth.user.email
if request.vars.up_file != None:
form.vars.filename = request.vars.up_file.filename
if form.process().accepted:
redirect(URL('data', 'index'))
elif form.errors:
response.flash = "form has errors"
and my db.py excerpt:
db.define_table('uploads',
Field('username', 'string'),
Field('filename', represent = lambda x, row: "None" if x == None else x[:45]),
Field('up_file', 'upload', uploadseparate=True, requires=[IS_NOT_EMPTY(), IS_UPLOAD_FILENAME(extension=ext_regex)]),
Field('up_date', 'datetime'),
Field('up_size', 'integer', represent= lambda x, row: quikr_utils.sizeof_fmt(x) ),
Field('notes', 'text'))
Currently the validation doesn't appear to do anything, when I submit my function, the filename isn't getting saved for some reason, and i get an error elsewhere because the value is None

You need to do something like this :
DB :
db.define_table('t_filetable',
Field('f_filename', type='string', label=T('File Name')),
Field('f_filedescription', type='text',
represent=lambda x, row: MARKMIN(x),
comment='WIKI (markmin)',
label=T('Description')),
Field('f_filebinary', type='upload', notnull=True, uploadseparate=True,
label=T('File Binary')),
auth.signature,
format='%(f_filename)s',
migrate=settings.migrate)
Controller : (default.py)
#auth.requires_login()
def addfile():
form = SQLFORM(db.t_filetable, upload=URL('download'))
if form.process(onvalidation=validate_filename).accepted:
response.flash = 'success'
elif form.errors:
response.flash = 'form has errors'
return dict(form=form)
def validate_filename(form):
if form.vars.f_filename == "":
form.vars.f_filename = request.vars.f_filebinary.filename
Function validate_filename is called AFTER the form has been validated, so form.vars should be available to use here. Function validate_filename checks if form.vars.f_filename has any value other than "" (blank) ; if not, it reads the filename from the request.vars.f_filebinary and assigns it to the form.vars.f_filename . This way you can allow users to provide an optional field for filename. If they leave it blank, and just upload the file, the f_filename in DB will be the original filename.

I tried your pasting your code into web2py to see where it goes wrong and it actually worked for me (at least the file names saved). Maybe the problem is elsewhere?

Related

Python Flask SqlAlchemy Add Database Model Name dynamically in For Loop

I am not that familiar with Python and SQLAlchemy so please be patient :)
I need to capture if, within a FORM that holds multiple ICONS(files), one or more ICONS have been changed when editing the record.
To see which ICONS have been changed I created an Object holding the changes with "Database Model Name" as the "Key" and its "Value"
{'icon': <FileStorage: 'fire.png' ('image/png')>}
key = used as database model name
value = file.filename
now when I try the get the data within a for loop and add this data to the Database model, nothing happens and it looks like I am not really accessing variable "k" in the loop.
for k, v in notequalat.items():
responseteamdata.k = v.filename
My question is, how can I combine the Database model class "responseteamdata" and the variable "k" so that I can add the changes to the database model dynamically.
here is the full code:
if not notequalat:
try:
responseteamdata.title = title
responseteamdata.abbreviation = abbreviation
responseteamdata.isfireteam = booleanisfireteam
responseteamdata.iconposition = newlatlng
db.session.commit()
except IntegrityError:
db.session.rollback()
db.session.close()
res = make_response(jsonify("message ", "Error Updating the Team"), 500)
return res
else:
responseteamdata.title = title
responseteamdata.abbreviation = abbreviation
responseteamdata.isfireteam = booleanisfireteam
responseteamdata.iconposition = newlatlng
for k, v in notequalat.items():
responseteamdata.k = v.filename
db.session.commit()
dbevent = "updated"
db.session.close()
To be able to dynamically assign the Table Column Name the following command has been working for me:
setattr(DB-Object, ColumnName, Value)
which means in my case:
setattr(responseteamdata, k, v.filename)

Short description isn't working for delete selected (delete_selected.short_description isn't changing the name)

I am currently trying to change the name of the "Delete Selected" admin action. I have already effectively override the default (so I can store some data before completely deleting it), but now I want to change the option from the vague "Deleted selected" to something more specific like "Deleted all selected registrations." Or, at least, for it to say, "Deleted selected registrations" like it did before I overwrote the function.
I have so far tried this:
delete_selected.short_description = 'Delete all selected registrations'
But the option is still "Deleted selected." Is there a way to fix this?
Here's my code:
def delete_selected(modeladmin, request, queryset):
"""
This overrides the defult deleted_selected because we want to gather the data from the registration and create a
DeletedRegistration object before we delete it.
"""
for registration in queryset:
reg = registration.get_registrant()
if registration.payment_delegation:
delegate_name = registration.payment_delegation.name
delegate_email = registration.payment_delegation.email
else:
delegate_name = None
delegate_email = None
registration_to_delete = DeletedRegistration.objects.create(
registrant_name = reg.full_name(),
registrant_email = reg.email,
registrant_phone_num = reg.phone,
delegate_name = delegate_name,
delegate_email = delegate_email,
# Filtering out people (with True) who couldn't participate in events because we are only interested in the people
# we had to reserve space and prepare materials for.
num_of_participants = registration.get_num_party_members(True),
special_event = registration.sibs_event,
)
registration.delete()
delete_selected.short_description = 'Delete all selected registrations'
edit: just tried delete_selected.list_display that didn't work either
You can't have it in the function, so I just had to tab it back one space and it worked.
example:
def delete_selected(modeladmin, request, queryset)
code
delete_selected.short_description = "preferred name"
thanks.

Django - checking if instance exists results in internal server error 500

I am trying to check if I have an entry in my database using this code:
def device_update(request):
json_data = json.loads(request.body)
email = json_data['email']
imei = json_data['imei']
sdk_version = json_data['sdk_version']
date = json_data['updateDate']
rule = json_data['ruleName']
group_name = json_data['group']
if Group.objects.filter(group=group_name).exists():
print("group does exists")
else:
print("group doesn't exists")
return HttpResponse("Successful")
However, when the code reaches the if statement to check if the group exists, it returns error 500.
I tried to check with two groups one that exists and another one that doesn't, in both cases I got error 500.
How can I fix this and why is this happening?
The logic for checking if a Group exists, i.e. the line:
if Group.objects.filter(group=group_name).exists()
is not throwing the error here. It is likely that json_data is missing one of the keys you expect it to have, for example, 'group'.
I'd recommend using the get method that dictionaries have. This provides default values when the specified key is not present in the dictionary. You should also have error handling for when the request body is not in valid JSON format.
Here's an example:
def device_update(request):
try:
json_data = json.loads(request.body)
except json.JSONDecodeError:
return HttpResponse('Request body must be in valid JSON format')
email = json_data.get('email', '')
imei = json_data.get('imei', '')
sdk_version = json_data.get('sdk_version', '')
date = json_data.get('updateDate', '')
rule = json_data.get('ruleName', '')
group_name = json_data.get('group', '')
if Group.objects.filter(group=group_name).exists():
print("group does exists")
else:
print("group doesn't exists")
return HttpResponse("Successful")
I set the defaults to the empty string '', but you may want to change that.
Your view doesn't have any error handling. Looking at it quickly, at least two things could go wrong. The request body might not be valid json, and if it is valid json, it might not contain the required keys.
def device_update(request):
try:
json_data = json.loads(request.body)
except ValueError:
return HttpResponse("Invalid json")
try:
email = json_data['email']
imei = json_data['imei']
sdk_version = json_data['sdk_version']
date = json_data['updateDate']
rule = json_data['ruleName']
group_name = json_data['group']
except KeyError as e:
return HttpResponse("Missing Key %s" % e[0])
...
Writing your own validation for a single view like this is ok. As it gets more complicated, you might want to look at django rest framework. It has serializers which will help you manage validation.
Alasdair/Keselme, looks that your view is correct.
Try to put the ipdb into your code in order to debug your code, and than you can print the request.data and see what is comming in the request.

Updating a specific row with Flask SQLAlchemy

I have this app with a profile and I want to update only a specific row based on its account id. Inserting the data works, but updating a specific row doesn't and I'm not sure which part is wrong with my code.
#app.route('/edit_parent/<int:acc_id>', methods=['GET','POST'])
def edit_parent(acc_id):
myParent = Parent.query.filter_by(acc_id=int(acc_id)).first()
if request.method == "POST":
myParent.fname_p = request.form['fname_p']
myParent.lname_p = request.form['lname_p']
myParent.bday_p = request.form['bday_p']
myParent.add_p = request.form['add_p']
db.session.commit()
print "hello success"
return redirect(url_for('parent', acc_id=int(acc_id)))
if request.method == "GET":
return render_template('edit_p.html', acc_id=int(acc_id))
It prints the "hello success" and redirects to the parent url but returns an error 302 and still no changes in the db.
I don't think you are updating a specific row at all, but instead you are just inserting new one each time with:
myParent = Parent(request.form['fname_p'], request.form['lname_p'],
request.form['bday_p'], request.form['add_p']).where(acc_id=acc_id)
db.session.add(myParent)`
So, what you are supposed to do instead is:
myParent = Parent.query.filter_by(acc_id=acc_id)
assuming your Parent db has the following attributes:
myParent.fname = request.form['fname_p']
myParent.lname = request.form['lname_p']
myParent.bday = request.form['bday_p']
myParent.add = request.form['add_p']
db.session.commit()
solved it by adding:
myParent = db.session.merge(myParent)
this way it merges the current session with the previous one. It still returns a 302 but the data on the db has been successfully updated.

Modified django form cleand_data do is not renedered in data

I want to add data to submitted data in a django form.
Until now I did something like this:
form = NewADServiceAccount(data=request.POST)
if form.is_valid():
data=request.POST.copy()
if not 'SVC' in data['Account_Name']:
data['Account_Name'] = 'SVC_'+data['Account_Name']
form = NewADServiceAccount(data=data)
This works, but I would like to do this check in a clean method, so I defined:
def clean_Account_Name(self):
data = self.cleaned_data['Account_Name']
if not 'SVC' in self.cleaned_data['Account_Name']:
data = 'SVC' + data
return data
However, when I run this code with the clean method, I see that clean_data does not match data,
and my rendered form does not contain a correct Account_Name (e.g. it does not have SVC in it):
ipdb> p form.cleaned_data['Account_Name']
u'SVCoz123'
ipdb> p form.data['Account_Name']
u'oz123'
The Account_Name from data is the one rendered to HTML, how can I fix this, so that Account_Name from cleaned_data is rendered?
update:
I found another way to do it, but I am still not sure it is the right way:
# inside forms.py
class NewADServiceAccount(NewAccount):
Account_Name = forms.CharField(min_length=3, max_length=21, required=True,
#initial="Please write desired name of "
#+ "this service account.",
help_text="Please write the desired name "
+ "of this account. The prefix 'SVC_' will"
+ " be added to this name",)
def set_prefix(self, prefix='SVC_'):
data = self.data.copy()
data['Account_Name'] = prefix+data['Account_Name']
self.data = data
# in views.py:
if form.is_valid():
form.set_prefix()
second update:
After looking at my solution I decided my clean method can be a bit better, so I did:
def clean_Account_Name(self):
data = self.data.copy()
if not 'SVC' in data['Account_Name']:
data['Account_Name'] = 'SVC' + data['Account_Name']
self.data = data
the above solution works, although the django documentation says:
Always return the cleaned data, whether you have changed it or not.
So, now I am quite confused.
I found a solution, but I need reaffirming it is a valid and good one. I would be happy if someone comments here about it.
If I understood you have been attempts uses the clean method. If I right, you did it a little wrong. Try use def clean() with a form's field:
forms.py
class AccountNameField(forms.CharField):
def clean(self, value):
value = u'SVC' + value
return value
class NewADServiceAccount(forms.Form):
Account_Name = AccountNameField(min_length=3, max_length=21, required=True,
#initial="Please write desired name of "
#+ "this service account.",
help_text="Please write the desired name "
+ "of this account. The prefix 'SVC_' will"
+ " be added to this name",)
views.py
form = NewADServiceAccount(request.POST or None)
if form.is_valid():
...
prefix is used only into a forms. If I am not mistaken prefix would be assign each fields of the form as prefix-namefield

Categories