Какой Django / Pythonic способ создать или перезаписать запись? - PullRequest
1 голос
/ 07 апреля 2011

Работа с Django 1.2. Я делаю сайт по обзору вин. Пользователь должен иметь возможность просмотреть каждое вино только один раз, но должен иметь возможность вернуться и повторно просмотреть вино без появления ошибки.

Использование метода get_or_create представляется наиболее рациональным решением, но я сталкивался с различными проблемами при его реализации. Поиск я нашел эту статью, которая выглядела многообещающе: Правильный способ использования 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 воспринимает его как уникальное. Я попытался удалить другие параметры формы, но затем они не были отправлены с запросом на публикацию.

Предложения будут с благодарностью.

1 Ответ

0 голосов
/ 07 апреля 2011

Я тоже сталкивался с этим при создании приложения на основе CRUD. Я не уверен, что есть лучший способ, но в итоге я использовал exists(), чтобы проверить, существует ли запись ...

Вы можете использовать get_or_create в области видимости is_valid (), однако вам необходимо проверить, существует ли обзор, прежде чем отображать вашу форму, чтобы загрузить данные экземпляра в форму в случае, если обзор уже существует.

Ваш 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() вы получите два удара в дБ, если обзор существует, однако вы не создадите объект, если пользователь не отправит действительную форму:

@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

Надеюсь, кто-то с большим опытом присоединится.


Edit:

Вот довольно старый пост Даниэля Роземана Blog. Я не знаю, применимо ли оно до сих пор, но может иметь отношение к вашему вопросу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...