Working with Django 1.2 I am making a wine review site. A user should only be able to review each wine once, but should be able to go back and re-review a wine without raising an error.
Using the get_or_create method seems the most rational solution but I have been running into various problems implementing it. Searching I found this article which looked promising:
Correct way to use get_or_create?
and of course the django documentation on it:
http://docs.djangoproject.com/en/1.2/ref/models/querysets/#get-or-create
But didn’t seem to answer my question. Here is my code:
Views.py
@login_required
def wine_review_page(request, wine_id):
wine = get_object_or_404(Wine, pk=wine_id)
if request.method == 'POST':
form = WineReviewForm(request.POST)
if form.is_valid():
review, created = Review.objects.get_or_create(
user = request.user,
wine = wine,
like_dislike = form.cleaned_data['like_dislike'],
...
)
variables = RequestContext(request, {
'wine': wine
})
review.save()
return HttpResponseRedirect(
'/detail/%s/' % wine_id
)
else:
form = WineReviewForm()
variables = RequestContext(request, {
'form': form,
'wine': wine
})
return render_to_response('wine_review_page.html', variables)
Models.py
class Review(models.Model):
wine = models.ForeignKey(Wine, unique=True)
user = models.ForeignKey(User, unique=True)
like_dislike = models.CharField(max_length=7, unique=True)
...
If I understand how to use get_or_create correctly, since I am not matching on all the values like_dislike, etc… then django perceives it to be unique. I tried removing the other form parameters, but then they are not submitted with the post request.
Suggestions would be greatly appreciated.
I came across this too when making a CRUD based app. I’m not sure if there’s a better way but the way I ended up getting doing was using a
exists()to check if an entry … exists.You can use get_or_create within the is_valid() scope, however, you need to check if the review exists before displaying your form in order to load instance data into the form in the case that the review already exists.
Your models.py might look like this:
Your forms.py might look like this:
Using get_or_create will let you do this if used like so:
Doing creates a review just by visiting the page and requires that the other information either have a default or are allowed to be blank at the model level.
With
exists(), you get two db hits if the review exists, however you don’t create an object unless the user submits a valid form:I used
exists()but I think that this might be better?Hopefully someone with more experience will chime in.
Edit:
Here is a fairly old post from Daniel Roseman’s
Blog. I don’t know if it is still applicable, but might be relevant to your question.