Проблема 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')
И это должно работать