【问题标题】:Django preventing a book from being submitted twiceDjango阻止一本书被提交两次
【发布时间】:2018-12-12 01:57:16
【问题描述】:

我有以下表格和模型:

class Book(models.Model):
    name = models.CharField(max_length=128, null=True, blank=True)
    author = models.CharField(max_length=128, null=True, blank=True)
    borrower = models.ForeignKey('core.User')
class BookForm(forms.ModelForm)
    class Meta:
        model = Book
        fields = ("name", "author", "borrower")
@login_required
def private(request):
    if request.method == 'POST':
        form = BookForm(request.POST)
        if form.is_valid():
            book = form.save(commit=False)
            book.save()
    else:
        form = BookForm()
    return render(request, 'borrow.html', {'form': form, })

该网站允许用户将新书提交到他们自己的私人页面。当用户尝试提交同一用户之前提交过的图书时,就会出现问题。 应该在哪里实施验证以及如何实施?
- 如果我选择在表单 clean 方法中验证它,那么我无法获取请求以查看它是哪个用户。
- 如果我选择在视图中进行验证,那么表单已经验证后如何使表单失效?

【问题讨论】:

    标签: django django-forms django-views


    【解决方案1】:

    有几种方法可以做到这一点,但我在下面列出了 2 种最简单的方法:

    1. 使用form.add_error(field, error)向表单域添加错误
    2. 使用messages 框架添加错误消息


    方法一

    在您看来,您可以进行所需的验证,如果验证失败,即。用户尝试提交两次图书,您可以使用(假设您的表单名为form,就像在您的代码中一样,title 是您要添加错误消息的字段,第二个参数是您希望在该字段旁边显示的错误消息):

    form.add_error('title', 'Book already taken out')
    

    方法二

    你可以做验证,如果失败了,你可以做

    messages.add_message(request, messages.WARNING, 'Book already taken out')
    

    然后在你的模板中,你可以做

    <ul class="messages">
        {% for message in messages %}
        <li{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</li>
        {% endfor %}
    </ul>
    

    此外,您可以检查是否为message.tags == DEFAULT_MESSAGE_LEVELS.ERROR,然后添加一个额外的类,将字体样式设置为红色文本,以便用户更清楚地知道这是一个错误。

    请务必添加

    from django.contrib import messages
    

    到您的进口清单。


    请参阅https://docs.djangoproject.com/en/2.1/ref/contrib/messages/ 了解更多信息。

    【讨论】:

      【解决方案2】:

      对我来说,保持视图简单几乎总是更好。

      您可以在表单中使用 clean 方法,例如:

      class BookForm(forms.ModelForm):
          class Meta:
              model = Book
              fields = ("name", "author", "borrower")
      
          def __init__(self, *args, **kwargs):
              #add the request in the ModelForm
              self.request = kwargs.pop('request', None)
              #call the default super
              super(BookForm, self).__init__(*args, **kwargs)
      
          def clean(self):
              #call the default clean method
              cleaned_data = super(BookForm, self).clean()
              #get the diffrents cleanned fields
              name = cleaned_data.get('name')
              author = cleaned_data.get('author')
              #get the user from the request
              borrower = self.request.user
              #try to get the book submited by the user from the database
              try:
                  Book.objects.get(name=name, author=author, borrower=borrower)
      
              #if their is an error, that mean the book doesn't exist in the database at the moment
              #so we can return the cleaned data
              except Book.DoesNotExist:
                  return cleaned_data
      
              #otherwise raise an error that could be display directly in the template in the non_field_error
              else:
                  raise ValidationError(_('The borrower already have this book'), code='book_already_exist')
      

      请注意,由您的 Form.clean() 覆盖引发的任何错误都不会与任何特定字段相关联。它们进入一个特殊的“字段”(称为 all),如果需要,您可以通过 non_field_errors() 方法访问该字段。如果要将错误附加到表单中的特定字段,则需要调用 add_error()。

      【讨论】:

      • 这对我不起作用,因为我写了第一个项目符号。用户是从请求中获取的,而不是从数据表单中获取的
      • 我只是编辑我的代码,基本上你需要在表单中从 init 获取请求,然后你可以在你的 clean 方法中使用它,比如 self.request
      猜你喜欢
      • 1970-01-01
      • 2014-04-27
      • 1970-01-01
      • 1970-01-01
      • 2019-05-13
      • 1970-01-01
      • 2012-09-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多