开发者

Whats the most Django/pythonic way to create or overwrite a record?

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 开发者_JAVA技巧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:

from django.db import models
from django.contrib.auth.models import User

class Wine(models.Model):
    name = models.CharField()

class Review(models.Model):
    wine = models.ForeignKey(Wine)
    user = models.ForeignKey(User)
    like = models.BooleanField(null=True, blank=True) # if null, unrated

Your forms.py might look like this:

from django import forms

class WineReviewForm(forms.ModelForm):
    class Meta:
        model = Review
        fields = ['like',] # excludes the user and wine field from the form

Using get_or_create will let you do this if used like so:

@login_required
def wine_review_page(request, wine_id):
    wine = get_object_or_404(Wine, pk=wine_id)

    review, created = Review.objects.get_or_create(user=request.user, wine=wine)

    if request.method == 'POST':
        form = WineReviewForm(request.POST, instance=review)
        if form.is_valid():
            form.save()   
            return HttpResponseRedirect('/detail/%s/' % wine_id )
    else:
        form = WineReviewForm(instance=review)

    variables = RequestContext(request, {'form': form, 'wine': wine })
    return render_to_response('wine_review_page.html', variables) 

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:

@login_required
def wine_review_page(request, wine_id):
    wine = get_object_or_404(Wine, pk=wine_id)

    review = None
    if Review.objects.filter(user=request.user, wine=wine).exists():
        review = Review.objects.get(user=request.user, wine=wine)

    if request.method == 'POST':
        form = WineReviewForm(request.POST, instance=review)
        if form.is_valid():
            form.save()   
            return HttpResponseRedirect('/detail/%s/' % wine_id )
    else:
        form = WineReviewForm(instance=review)

    variables = RequestContext(request, {'form': form, 'wine': wine })
    return render_to_response('wine_review_page.html', variables)

I used exists() but I think that this might be better?

try:
    review = Review.objects.get(user=request.user, wine=wine)
except Review.DoesNotExist:
    review = None

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜