Django предотвращает двойную подачу книги - PullRequest
0 голосов
/ 11 декабря 2018

У меня есть следующая форма и модель:

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, })

Веб-сайт позволяет пользователю отправить новую книгу на свою личную страницу.Проблема возникает, когда пользователь пытается отправить книгу, которая была передана ранее тем же пользователем.Где и как должна осуществляться проверка?
- Если я решу проверить ее в чистом методе формы, у меня не будет возможности получить запрос, чтобы узнать, каким пользователем он был.
- Если я решу проверитьэто в представлении, тогда как я могу сделать форму недействительной после того, как она уже была проверена?

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

Для меня почти всегда лучше сохранять простоту представления.

Вы можете использовать чистый метод в вашей форме, например:

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

0 голосов
/ 11 декабря 2018

Есть несколько способов сделать это, но я перечислил 2 простых способа ниже:

  1. Добавление ошибки в поле формы с помощью form.add_error(field, error)
  2. Добавление сообщения об ошибке с использованием messages framework

Метод 1 :

По вашему мнению, вы можете выполнить необходимую проверку, и если эта проверка не пройдена, т.е.пользователь пытается отправить книгу дважды, которую вы можете использовать (при условии, что ваша форма называется form, как и в вашем коде, title - это поле, в которое вы хотите добавить сообщение об ошибке, а второй параметр - этосообщение об ошибке, которое вы хотите отобразить рядом с этим полем):

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

Метод 2 :

Вы можете выполнить проверку, и если это не удастся, выможет сделать

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/ для получения дополнительной информации.

...