Проблема Django Form ModelMultipleChoiceField с сохранением данных в БД

Я создаю свое первое полноценное приложение Django. Это система управления библиотекой. У меня три модели:

      class Authors(models.Model):
    firstName = models.CharField(max_length=20)
    lastName = models.CharField(max_length=20)
    
    def __str__(self):
        return f"{self.firstName.title()} {self.lastName.title()}"
    
    def save(self):
        self.firstName = self.firstName.casefold()
        self.lastName = self.lastName.casefold()
        super().save()
    
class Books(models.Model):
    isbn = models.BigIntegerField(primary_key=True, validators=[
        MinValueValidator(9780000000000),
        MaxValueValidator(9799999999999),
    ])
    bookName = models.CharField(max_length=50)
    authors = models.ManyToManyField(Authors, through='BookAuth')
    pubName = models.CharField(max_length=20)
    inventory = models.IntegerField(default=0)
    
    def __str__(self):
        return f"{self.pk} || {self.getName()}"
    
    def getName(self):
        name, bname = self.bookName.split(), ""
        for x in name:
            bname += x[0].upper() + x[1:] + " "
        return bname[:-1]
    
    def getAuthors(self):
        bookAuths = BookAuth.objects.filter(isbn=self.isbn)
        auth = ""
        for bookAuth in bookAuths:
            auth += f"{bookAuth.getAuth()}, "
        return auth[:-2]
    
    def save(self):
        self.bookName = self.bookName.casefold()
        self.pubName = self.pubName.casefold()
        super().save()

class BookAuth(models.Model):
    isbn = models.ForeignKey(Books, on_delete=models.CASCADE)
    auth = models.ForeignKey(Authors, on_delete=models.CASCADE)
    
    def getAuth(self):
        return Authors.objects.get(id=self.auth.id)
    
    def __str__(self):
        return f"{self.auth} - {self.isbn}"

Здесь я храню книги и авторов отдельно и использую модель BookAuth для установления связи ManyToMany. У меня возникли проблемы с добавлением новой книги. Для этого у меня есть две формы: одна для добавления нового автора, а другая для добавления новой книги. Файл form.py выглядит следующим образом:

      class AddAuthors(forms.ModelForm):
    class Meta:
        model = Authors
        fields = ("__all__")

class AddBooks(forms.ModelForm):
    author = forms.ModelMultipleChoiceField(
        queryset=Authors.objects.all(),
        widget=CheckboxSelectMultiple,
        )
    class Meta:
        model = Books
        fields = ('isbn', 'bookName', 'authors', 'pubName', 'inventory')

Я хочу иметь поле с множественным выбором для атрибута автора, чтобы добавить одного или нескольких авторов в новую книгу. Я обрабатываю эту форму, используя следующее представление:

      def books(request):
    if request.method == "GET":
        cont1 = footer_counter() # returns a dictionary with total no of members, books and total inventory
        cont2 = {'bookform': AddBooks(), 'authform': AddAuthors(), 'books': Books.objects.all()}
        return render(request, 'books.html', {**cont1,**cont2})
    if request.method == "POST":
        authData = AddAuthors(request.POST)
        bookData = AddBooks(request.POST)
        if authData.is_valid():
            authData.save()
        elif bookData.is_valid():
            bookData.save()
        return redirect(books)

Но моя проблема в том, что после отправки формы никакие данные не сохраняются в модели (Book или BookAuth). Django выдает следующие сообщения журнала:[27/Apr/2023 14:13:03] "POST /books/ HTTP/1.1" 302 0 [27/Apr/2023 14:13:03] "GET /books/ HTTP/1.1" 200 8009

Как я могу это исправить? Спасибо.

Дополнительно: язык шаблонов Django для формы:

      <div class="col-md-6 text-center">
  <form method="post" autocomplete="off">
  {% csrf_token %}
    <table class="table text-center">
      <thead class="table-dark">
        <tr><th colspan="2">Add a new Book</th></tr>
      </thead>
      <tbody>
        <tr>
          <td class="col-4"><label for="{{ bookform.isbn.id_for_label }}" class="form-label text-white">ISBN</label></td>
          <td class="col-8">{{ bookform.isbn }}</td>
        </tr>
        <tr>
          <td><label for="{{ bookform.bookName.id_for_label }}" class="form-label text-white">Book Name</label></td>
          <td>{{ bookform.bookName }}</td>
        </tr>
        <tr>
          <td><label for="{{ bookform.author.id_for_label }}" class="form-label text-white control-label">Authors</label>
          </td>
          <td>{{ bookform.author }}</td>
        </tr>
        <tr>
          <td><label for="{{ bookform.pubName.id_for_label }}" class="form-label text-white">Publisher Name</label></td>
          <td>{{ bookform.pubName }}</td>
        </tr>
        <tr>
          <td><label for="{{ bookform.inventory.id_for_label }}" class="form-label text-white">Inventory</label></td>
          <td>{{ bookform.inventory }}</td>
        </tr>
      </tbody>
    </table>
    <button type="submit" class="btn btn-primary mx-auto">Add Book</button>
  </form>
</div>

После отправки данные не сохраняются в БД. Он работает так, как должен, но не сохраняет данные в модель. (Я проверил, используя переменную флага и операторы печати, и bookform.is_valid() возвращает false, даже когда я ввожу правильные значения)

1 ответ

Ваша проблема связана с названием поля в вашей форме.

Ваше поле в форме называется автором, но в полях указаны авторы (из модели).

Просто отредактируйте форму следующим образом:

      class AddBooks(forms.ModelForm):
authors = forms.ModelMultipleChoiceField(
    queryset=Authors.objects.all(),
    widget=CheckboxSelectMultiple,
    )
class Meta:
    model = Books
    fields = ('isbn', 'bookName', 'authors', 'pubName', 'inventory')

И это должно работать

Другие вопросы по тегам