I'm trying to make a function to delete a record in my database with flask and the extension for SQLAlchemy. Problem is, instead of deleting just one row, it deletes all of them. Can someone tell me what's wrong with my code?
#app.route('/admin/delete/<int:page_id>', methods=['GET','POST'])
#requires_auth
def delete_page(page_id):
page = Page.query.get(page_id)
if not page:
abort(404)
if page.children:
flash('You can not delete a page with child pages. Delete them, or assign them a different parent.',
'error')
return redirect(url_for('admin_page'))
if request.method == 'POST':
Page.query.get(page_id).query.delete()
db.session.commit()
flash('Page was deleted successfully', 'success')
return redirect(url_for('admin_page'))
return render_template('admin_delete.html', page_title=page.title, page_id=page_id)
Thanks in advance!
I suspect that this line does not what you think.
Page.query.get(page_id).query.delete()
You're getting a single instance (which you already did before), and by using query you actually issue a new query over all objects without filtering and therefore deleting all of them.
Probably what you want to do is this:
db.session.delete(page)
Related
I want to have a Flask route that deletes all instances of a SQLAlchemy model, VisitLog. I call VisitLog.query.delete(), then redirect back to the page, but the old entries are still present. There was no error. Why weren't they deleted?
#app.route('/log')
def log():
final_list = VisitLog.query.all()
return render_template('log.html', loging=final_list)
#app.route('/logclear')
def logclear():
VisitLog.query.delete()
return redirect("log.html", code=302)
Clear database
Just like other write operations, you must commit the session after executing a bulk delete.
VisitLog.query.delete()
db.session.commit()
I have a page (corresponding to the detail view) displaying a list of items, each with an associated check box. There is a button on the page which when submitted adds to request.POST the list of checked items, and signifies that they should be deleted. Upon deletion, I want to redirect back to the same view - detail.
First two lines of the detail view:
def detail(request, inventory_id, category_id=None):
check_POST_and_update(request, inventory_id, category_id)
Here is the relevant part of the check_POST_and_update method.
def check_POST_and_update(request, inventory_id=None, category_id=None):
if request.method=='POST' and request.user.is_authenticated():
r = request.POST
if r.get('delete_items', None) and r.get('select_item', None):
for item_id in r.getlist('select_item'):
Item.objects.get(pk=item_id).delete()
return redirect('inventory:detail', inventory_id, category_id)
The deletion and redirect seem to be working fine. I select a few items, click on the "Delete selected items" button and the same page is returned, with the selected items now gone from the list. However, if I then refresh the page at this point, I get "DoesNotExist ... Item matching query does not exist". ie the old POST object is being resubmitted. I can confirm this:
<QueryDict: {u'select_item': [u'149'], u'csrfmiddlewaretoken': [u'MASoSxSn2hmwgFKf95WcWjnVa6GYUnPe'], u'delete_items': [u'Delete selected items']}>
Why is this happening? I thought that the redirect method was supposed to prevent this sort of problem. How can I fix the code to make sure that the old POST object does not get resubmitted when refreshing the page?
Thanks in advance and sincere apologies if I have made a silly error somewhere!
You are not returning the response from check_POST_and_update in the detail view, so the view will continue to be processed and will eventually return a different response.
Normally you would do return check_POST_and_update, but I don't think that will work, because I think there's a bit of the detail view that you haven't shown.
You could check the result of the method before returning it as follows :
def detail(request, inventory_id, category_id=None):
response = check_POST_and_update(request, inventory_id, category_id)
if response is not None:
return response
...
I don't like this approach, it seems quite hacky. The code might be easier to understand if you return a boolean from the check_POST_and_update method, and generate the response in the main view.
I'm new to both web development and django so maybe that's a noob question.
I want to do the following:
Ask user to fill some form and submit it.
Then, parse and format the content and display it back to the user to let him verify it.
User can accept the result or go back to the previous view, update data and resend.
This is as far as I can think:
views.py
def add_content(request):
if request.method == 'POST':
form = AddContentForm(request.POST)
if form.is_valid():
content = form.save(commit=False)
return verify_content(request, content)
else:
form = AddContentForm()
return render(request, 'myapp/add_content.html', {'form' : form})
def verify_content(request, content):
return render(request, 'myapp/verify_content.html', {'content' : content})
The verify_content template will obviously contain two buttons ('back', 'ok'), but I don't know how to pass the content object to a view for saving it in the db, or send it back to the previous view from there. Should I use js? Can i do it with just server side code?
Maybe my whole logic is wrong. Should I save the object in the db before verification and then delete it if needed (sounds ugly)? What is a good way to implement this?
Thanks in advance for your time.
You could use the users session for this:
request.session['content'] = content
and in the view where the user should verify his input do:
content = request.session['content']
and voilá you got the content between 2 views.
Django also secures that users can't tinker with its data by either saving it server side, or in a signed cookie.
I would save the form with commit=True in the add_content view, and would add a verified field or something to the model. Then you can append the pk as GET parameter to the link which will get you back to add_content view from verify. You can extract the parameter from request.GET dict.
I have a form (done in Flask) where text and image data are inputted. I'm confused as to where and how I should place the function that extracts the image's file name, then dumps the data into my sqlite database. I've included relevant snippets.
The Main file:
#app.route('/dform', methods=['GET', 'POST'])
def dform():
form = DForm()
return render_template('dform.html', form=form)
#app.route('/adddf', methods=['POST'])
def add_dfentry():
g.db.execute('insert into dfentries (name, cover) values (?, ?)',
(request.form['name'], request.form['cover']))
#app.route('/dfoutput')
def dfoutput():
cur = g.db.execute('select name, cover from dfentries order by id desc')
dfentries = cur.fetchall()
return render_template('dfoutput.html', dfentries=dfentries)
The Form's file:
class DForm(Form):
name = TextField(u"Name")
cover = FileField(u"Cover Image")
So, how I would get the file name from the above file field, and store it into (and retrieve it from) the database? Thank you for the help and sorry for the possibly stupid question. I am using this program to learn python.
In Flask, the uploads are stored in request.files, not request.form. You would basically look at file.filename and read it into your table as a blob.
See http://flask.pocoo.org/docs/patterns/fileuploads/ for more information.
Don't forget all security and validation considerations.
And since you're using WTForms probably, see http://wtforms.simplecodes.com/docs/0.6/fields.html#wtforms.fields.FileField which teaches you how to actually process it via the Form.
This also pertains to your submit in general, if you're using the form, you shouldn't be accessing the request object directly. If you're using Flask-WTF use form.validate_on_submit(), if you're using vanilla forms use request.method == 'POST' and form.validate() instead.
Read up on correct usage at http://wtforms.simplecodes.com/docs/1.0.1/crash_course.html or https://flask-wtf.readthedocs.org/en/latest/quickstart.html
I have a threaded comment system which works fine 99.9% of the time, but very occasionally the tree breaks down and left/right values get duplicated.
I have discovered that this happens when two posts happen at the same time (within a second of each other), and presumably what is happening is that the second post is updating the left/right values of the tree before the first has completed doing so.
My comment insert code from views.py is the following:
#login_required
#transaction.autocommit
def comment(request, post_id):
parent = get_object_or_404(Post, pk=post_id)
if request.method == 'POST':
form = PostForm(request.POST)
form.parent = post_id
if form.is_valid():
new_post = newPost(request.user, form.cleaned_data['subject'], form.cleaned_data['body'])
new_post.insert_at(parent, 'last-child', save=True)
return HttpResponseRedirect('/posts/')
else:
form = PostForm()
return render_to_response('posts/reply.html', {'requestPost': request.POST, 'form': form, 'parent': parent}, context_instance=RequestContext(request))
What is the correct approach to dealing with this? Is there a django way to ensure that the second view does not get called until the first database transaction is complete? Or should I rebuild the tree after each insert to ensure integrity? Or is there a better insert method to be using?
Thanks!
edit: I'm using MySQL.
transaction.autocommit() is a standard django behavior. You decorator does nothing, if global transaction behavior was not redefined.
Use should use commit_on_success() decorator. All db operations in view will be in one transaction.
You can read more on https://docs.djangoproject.com/en/1.5/topics/db/transactions/
PS: In django 1.6 transaction management will be updated, be attentive.