Deleting an object Django- code seems right but is not working? - django

I have been working on this for far too long, and despite all of my research cannot find out what is wrong. Admittedly, I am new to django.
I have a ticket app that uses forms to create, edit and update tickets. I'm now trying to delete them, based on the ticket_id which is a primary key.
In my view I have:
def deleteTicket(request, ticket_id):
ticket = Ticket.objects.get(pk=ticket_id)
ticket.delete.all()
redirect_to = 'project/tickets.html'
return HttpResponseRedirect(redirect_to)
In my urls.py:
(r'^(?P<project_slug>[^\.^/]+)/tickets/(?P<ticket_id>\d+)$', views.deleteTicket),
When I open a ticket and click on the link that should call this view the expected page appears but the ticket I just tried to delete is still listed. I'm not getting any errors anywhere, but this code is doing nothing. Why?
Thanks for your help! It has been driving me crazy.

I'm going to assume your indentation is correct.
Pretty sure you're just supposed to go ticket.delete() since it's an object you're deleting, not an entire queryset, you don't need the .all(). Actually, to delete multiple objects you'd write Ticket.objects.all().delete(), so the syntax you're using is just plain wrong and I'm surprised it's not throwing an exception.
Also, you shouldn't delete via GET requests, only POST.
Lastly, you should use reverse for your redirect, or at least an absolute URL.

Related

Is it possible to make 'cart' with django Class Based View?

I am trying to make a simple e-commerce website and followed some tutorials.
However, the author of the book used complicated function based view to make cart function..
there are bunch of session stuffs.. and I don't understand the logic..
and I am trying to think the other way..
what about using database to store all the cart related data, and
use CBV to build it?
for example,
CartListView to see the contents of the cart, and CartUpdateView to change the quantity..
then are they going to be two different pages? separated page that user should go to the
different page to change the value??
please help me T T
You can access the session in any sort of CBV as self.request.session and a "shopping cart" is normally stored therein.
You'll certainly need to implement a CartListView to see what's in it, or possibly a CartEditView to show the cart with options to edit the quantities and delete anything that shouldn't be in there.
Adding products to the cart may well be an "Add" button on a ProductDetailView or lots of add buttons in a ProductListView. You might add a POST handler method to these views which are otherwise read-only (GET-only) bt default. Or you might make them FormViews, even though the form would be hidden and filled/POSTed by JS rather than the shopper doing anything other than clicking "add".
And then there will be a CheckoutView.
Check https://djangopackages.org/ (put "cart" in the search box). this will throw up several shopping cart things which might be the code you want, or the source of which might be a valuable learning resource before you end up rolling your own.

Django adding new attribute to WSGIRequest

Hey im kinda new to Django and the whole Views/Request process.
So I noticed i got the auth_user inside the request object due to the User middleware I had inside the settings file, and anywhere i have the request, i can call the user object with request.user
I kinda have a similar modal/object that is pretty important and I saw how to create a basic middleware but I'm not for sure how to replicate similar functionality where I'd be able to access that specific object inside the request like "request.object"
Edit: Okay i figured it out, but now the question is how do i reinitialize the process request in a view based on different conditions.
For example:
It starts off as a default of
def process_request(self,request):
request.object = Object.objects.get(id=1)
But based on a specific thing that happens in the views, i want it to change to a different id?

GET requests to a POST handling view

I have a view intended to deal only with POST requests that starts with
user = User.objects.get(username=request.POST['name'])
Do I need to ensure the view is not invoked with a GET request? Not sure if I'm thinking about good practice/security-type things or being OCD.
I'm using the #require_POST decorator because invoking the view with GET results in "Key 'name' not found in <QueryDict: {}> and a 500 error.
I suppose the only chance of this happening is if a user looked at the HTML of the page and for some reason thought to try the action attribute of the form in the address bar -which seems unlikely.
I've tried this myself with a couple of sites and got a error page, rather than a blank page with 405 error that #require_POST gives me.
Perhaps it's good practice to guard against GET requests in case a template designer mistakenly makes a hyperlink to my view or forgets method="post"? (In which case, I suppose I should use get_object_or_404 above)
I assume adding #require_GET to views that are only designed to deal with GET requests is unnesessary?
It seems like you understand why you would want to use #requirePOST. Another option, if you did not want to cause an error on GET, is to use something along these lines:
def view(request):
if request.method == 'POST':
..code for post..
else:
*redirect, or other code*
As to whether or not you need to use #requireGET, the only way it could hurt is if you need a view to perform both GET and POST. ie a form that causes action on POST, but is simply displayed for the user on GET. But if you are requiring GET then there should not be anything in the view that could be compromised via a POST.
Do I need to ensure the view is not invoked with a GET request? Not
sure if I'm thinking about good practice/security-type things or being
OCD.
Yes. I think you touch on answering your own question. your view requires request.POST a get request errors. If you wnat to create bug free code you will ensure that no get requests access this view. Django provides a convenient, pythonic, decorator to do this. I don't think you are being OCD at all. Also, I don't know how expensive it is to trigger an error in production (emails you, logs it, etc) but that is something to consider.
I suppose the only chance of this happening is if a user looked at the HTML of the page and for some reason thought to try the action
attribute of the form in the address bar -which seems unlikely.
I dont think it matters HOW a user could make a GET request to this, i think it only matters that this view MUST be a post request.
Perhaps it's good practice to guard against GET requests in case a
template designer mistakenly makes a hyperlink to my view or forgets
method="post"? (In which case, I suppose I should use
get_object_or_404 above)
In this case i dont' think thinking about the many ways a get request could be made to this view is important. The important part is it REQUIRES a Post request. You can use the tools at your disposal to ensure that all requests entering the function are post requests.
One thing is, name is not assumed. You could still get a KeyError. Even though you are ensuring that the request is POST you can't ensure that the post request will have a parameter name
that is why get is used so frequently
if not request.POST.get('name'):
# raise some sort of error?
user = User.objects.get(username=request.POST['name'])

Django add contrib.messages from custom middleware

I have implemented a custom middleware that check for certain fields in a user's profile. The fields are not required at sign up (in order to make it quick and easy for a user to sign up), however, I would prefer that they fill them out.
My middleware checks if they are set. If not, it notifies the user via a message. I ran into two problems.
Whenever I submit a posted form, because no template displays the messages, the middleware would add the message a second time since the middleware was called when the message was posted and after the redirect it was called again.
I solved this problem by iterating through the messages in my middleware and checking if the message I am about to add is already in there. If yes, it doesn't add it again.
When a user fixes the problem by updating their profile, on the very next page load, the messages are still there. After that though, everything works. At the beginning of my middleware, I actually put a check that returns None if the request was posted (I would have thought this would solve both problems, but it didn't solve either).
Any idea how to solve the 2nd issue? Is there a better way to solve my first one?
Thanks.
Edit:
Is there a way to clear the messages in a view? I've tried iterating through them (without storage.used=False) and they are still there. I would expect that this would solve both my problems.
Yoy can use sticky messages of https://github.com/AliLozano/django-messages-extends that is one storage that only keeps messages in request instead save in session
So, are you using django.contrib.messages to store permanent notices? It's intended for showing one-time notifications, where the user sees the message once and then it goes away. The type of things it's meant for are messages like, "Form edited successfully."
As far as getting rid of messages in a user's message stack are concerned: any time you use a RequestContext (discussed here) to render a template, all messages will be flushed (whether they are actually shown on the page or not).
I'm not totally sure this is the answer you're actually after, and I'm a bit confused by your question. However, I'm somewhat sure you're using messages outside its intended purpose, which is likely why you're running into trouble.
You could use process_reponse() method of Middleware to add the message. By that time, you would know whether to show the message to user or not depending on whether his profile now has the field filled in.
Consider using django.contrib.messages. May be you do not want to show "fill in the XYZ field" message on all requests, but only on few pages, say whenever user logs in or views his profile page.
Just place logic that creates messages to context processor instead of middleware. Modify request and return empty dict.

How to override/update information from POST when creating model

I have a view that handles a POST request and attempts to create a new object. However, I know that some of the POST'd data is invalid... But I want to fix it and go ahead and create the object.
The only way I can figure out to be able to 'fix' data in a ModelForm is to create a 'is_valid()' form. To do this, I can either create the form with the POST data, or I can create it with an already existing instance. Unfortunately, if I use the POST data, because some of it is invalid, the form won't validate and I am thus unable to get to the data in the form to fix it. If I create it with an already existing instance, this works, but when the form is displayed, any remaining errors are for whatever reason ignored (and thus don't show up on the web page.) I've tried a combination of creating the the Model form from the POST data and giving it an instance, but this doesn't seem to help. Additionally, I've tried modifying (a copy of) the POST data, fixing it, and then creating the ModelForm from the 'fixed' POST data. This sort of works, with the exception that I have some ImageFields in my form, and they seem to just be ignored.
Any help would be greatly appreciated. I have looked at every good page that I can find to no avail.
Perhaps there is a better way to do this? The problem I'm trying to solve is that I want to have a model that contains ImageFields. The first time I put up the form, the user needs to 'upload' images for each of the fields. However, if he doesn't update an image for one of the fields, I want the new form to come up with a Image upload button on the fields where images have not been uploaded, and just a text field with the image name for images that have been uploaded.
Edit 9/15/2010:
Ok, I think I can simplify all of the above question into this:
def testing( request ) :
test_form = UserProfileForm()
valid = test_form.is_valid()
return render( 'testing.tmpl', locals(), request )
When the above code is rendered, the 'valid' shows as False (as one might expect), but the 'test_form' renders without any errors. I've read through (if perhaps not understood?) the documentation on Models and ModelForms, and I see that most of the time a ModelForm (in my case: UserProfileForm) is created with a specified 'instance'. However, 1) I don't have an instance yet, 2) I would still expect the non-instance'd Form to display errors. I'm sure there is something I am missing. Please illuminate. :)
One more thing, which perhaps the answer to the above will answer anyway, but as far as I can tell, the is_valid() call is supposed to call the 'clean()' function I defined for the UserProfileForm. However, (not being a python guru) I placed 'raise ValidationError()' at the top of clean(), and when I run the code, no error is shown. Thoughts?
Update: I figured out the problem and the answer is below. Thanks!
You should have a look at how to clean form fields in django. You could either manipulate the data returned from the form there or make any kind of validation!
If your ImageFields are optional then you can still validate them (that they are otherwise correct).
Then it's a matter of adjusting your template to show either the uploaded file name or an file upload field depending on whether they've already uploaded one or not. Actually, it would probably be better to give them both fields in the first case. That's what the automatic admin does (the upload field is labeled "Change").
Well, after figuring out how to use the python debugger (pdb) and the fact that within emacs it kind of 'just works' (wow!?) I was able to find that my (empty) form was not bound. Googling bound forms pointed me to this page:
http://docs.djangoproject.com/en/dev/ref/forms/api/
RTFM'ing I find that I can pass an empty dictionary to my form and then everything starts to behave as I would expect. So, to summarize, there is a big difference between:
test_form = UserProfileForm()
and
test_form = UserProfileForm( {} )
The second version causes the rendering of the form to show all the errors (and to call 'clean()').
With risk of having this deleted by the moderator ;) Thank you to all those who commented and for your patience with a new django developer.