什么是创建或覆盖记录的最Django / pythonic方式?

时间:2011-04-07 02:22:19

标签: django-models django-forms django-views

使用Django 1.2我正在制作葡萄酒评论网站。用户应该只能查看一次葡萄酒,但应该能够返回并重新检查葡萄酒而不会产生错误。

使用get_or_create方法似乎是最合理的解决方案,但我遇到了实现它的各种问题。搜索我发现这篇看起来很有前途的文章: Correct way to use get_or_create?

当然还有关于它的django文档: http://docs.djangoproject.com/en/1.2/ref/models/querysets/#get-or-create

但似乎没有回答我的问题。这是我的代码:

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)
  ...

如果我理解如何正确使用get_or_create,因为我不匹配所有值like_dislike等...然后django认为它是唯一的。我尝试删除其他表单参数,但随后它们不会与post请求一起提交。

建议将不胜感激。

1 个答案:

答案 0 :(得分:0)

在制作基于CRUD的应用时,我也遇到过这种情况。我不确定是否有更好的方法,但我最终做的方法是使用exists()来检查条目是否存在。

您可以在is_valid()范围内使用get_or_create,但是,在显示表单之前,您需要检查审核是否存在,以便在审核已存在的情况下将实例数据加载到表单中。

您的models.py可能如下所示:

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

您的forms.py可能如下所示:

from django import forms

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

如果像这样使用,使用get_or_create将允许你这样做:

@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) 

只需访问该页面即可创建评论,并要求其他信息具有默认值或在模型级别允许为空白。

使用exists(),如果审核存在,则会获得两次db命中,但是除非用户提交有效的表单,否则不会创建对象:

@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)

我使用exists(),但我认为这可能更好?

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

希望有经验的人会参与进来。


修改

丹尼尔罗斯曼的Blog这是一篇相当古老的帖子。我不知道它是否仍然适用,但可能与您的问题有关。