Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django: get_object_or_404 not the right solution, but what is?

Tags:

django

I'm struggling to work out the correct solution for what I'm trying to do here and would really appreciate some help.

At the moment, I have a working system which takes a "Special" from the db and displays it in the browser. The user is able to edit that "Special" in the browser and submit it to the db. That change is then shown to the user.

The problem is that the "Special" will not update if there is no pre-existing "Special" in the db. In my views.py I have:

def changeSpecialOffer(theRequest):
    myProductUuid = theRequest.POST['myProductUuid']
    myNewSpecialOffer = theRequest.POST['myNewSpecialOffer']
    myProduct = get_object_or_404(Product, uuid=myProductUuid)
    myActiveSpecial = get_object_or_404(SpecialOffer.objects.filter(product=myProduct).filter(
                                                            active=True))
    try:
        myActiveSpecial.special = myNewSpecialOffer
        myActiveSpecial.save()
    except:
        return HttpResponse(myActiveSpecial, mimetype='text/plain')
    myActiveSpecial = SpecialOffer.objects.filter(product=myProduct).filter(
                                                            active=True)
    return HttpResponse(myActiveSpecial, mimetype='text/plain')

I know that the reason the updating of the "Special" does not work is because the get_object_or_404 is correctly returning a 404 error as there is no pre-existing "Special" in the db.

I've been trying for a while to work out the best way to get around this problem without breaking the function in cases where there is an existing "Special" in the db.

So far, I've tried replacing the get_object_or_404 with try and except, but I then run into problems with the save function, such as 'unicode' has no attribute 'save()'.

like image 223
Erve1879 Avatar asked Oct 06 '22 22:10

Erve1879


2 Answers

Try to replace:

myActiveSpecial = get_object_or_404(SpecialOffer.objects.filter(product=myProduct).filter(
                                                    active=True))

with:

myActiveSpecial, just_created = SpecialOffer.objects.get_or_create(product=myProduct, active=True)

Or you could try something like this:

try:
    myActiveSpecial = SpecialOffer.objects.get(product=myProduct, active=True)
except SpecialOffer.DoesNotExist:
    myActiveSpecial = SpecialOffer.objects.create(product=myProduct, active=True, ...something.more...)

if you need to do something more with the just-created object.

EDIT:

Just a thought... It's a bit puzzling to send a Model to HttpResponse. Maybe you will want to manually create a string that you wish to return in HttpResponse. Of course, current code also works. It implicitly calls the __unicode__ method of your model.

Another thing - what is the reason for re-fetching the myActiveSpecial just before the return? I don't see any effect this may have.

like image 151
frnhr Avatar answered Oct 13 '22 03:10

frnhr


The way get_object_or_404 works is by passing in the model, and then some lookups. It is the same as if you said SpecialOffer.objects.get() but instead of raising an exception, it raises 404.

You used it correctly the first time, but not the second instance.

Try this instead:

myProduct = get_object_or_404(Product, uuid=myProductUuid) # this is correct
myActiveSpecial = SpecialOffer.objects.filter(product=myProduct).filter(active=True))

if myActiveSpecial.count():
  # There is one or more active specials!
else:
  # There are no active specials for this product

You can also use the reverse lookup trick (depending on how your models are set up).

myActiveSpecial = myProduct.specialoffer_set.filter(active=True)
like image 45
Burhan Khalid Avatar answered Oct 13 '22 04:10

Burhan Khalid