Добавление множества полевых данных ManyToMany между моделями

#python #django #django-models

#питон #django #django-модели

Вопрос:

Я знаю, что подобные вопросы задавались раньше, но я не смог найти четкого ответа, поэтому любая помощь будет с благодарностью принята 🙂

Я хочу добавить предопределенный список объектов из одной модели в другую, используя поле ManyToMany. Однако я не уверен в лучших практиках или в том, как именно это сделать.

Например:

 #models.py
class Book(models.Model):
    BOOKS = (
        ('b1','Secret Life of Bees'),
        ('b2','Pride and Prejudice')
        )
    name = models.CharField(max_length=100, choices=BOOKS)
    def __str__(self):
        return self.name

class Library(models.Model):
    librarian = models.OneToOneField(UserProfile, on_delete=models.CASCADE, primary_key=True)
    books = models.ManyToManyField(Book)
 
 #views.py
def create_library(request):
    if request.method == 'POST':
        form = LibraryCreateForm(request.POST)
        if form.is_valid():
            library = form.save(commit=False)
            listOfBooks = request.POST.getlist('books')
            library.save()
            return redirect('home')
    else:
        form = LibraryCreateForm()
    return render(request, 'create_library.html', {'form':form})
 
 #forms.py
class LibraryCreateForm(forms.ModelForm):
    class Meta:
        model = Library
        fields = ['books']
 
 #create_library.html
<form method="POST">
    {% csrf_token %}
    <input type="checkbox" value="b1" name="books">
    <input type="checkbox" value="b2" name="books">
</form>
 

У меня это не работает, и я не знаю, как это правильно исправить.
Чтобы быть более конкретным, я хотел бы по существу сделать эквивалент этого в python, но с DJango:

 class Person:
    def __init__(self, name):
        self.name = name
        self.skills = [] 


class Skill:
    def __init__(self, name):
        self.name = name


programmingSkillOne = Skill("C  ")
programmingSkillTwo = Skill("Java")
programmingSkillThree = Skill("QML")

listOfSkills = []
listOfSkills.append(programmingSkillOne)
listOfSkills.append(programmingSkillTwo)
listOfSkills.append(programmingSkillThree)

personOne = Person("Stephanie")

personOne.skills = listOfSkills

personTwo = Person("Lizzy")
personTwo.skills.append(Skill("C  "))

people = [personOne, personTwo]

print ("n")

for person in people:
    print(person.name   "'s skills are: n")
    for s in person.skills:
        print(s.name)

    print("n")
 

Моя проблема заключается в добавлении книг в библиотечную модель на основе того, что выбирает пользователь.
Я прочитал https://docs.djangoproject.com/en/3.1/topics/db/examples/many_to_many / но я все еще борюсь.

Комментарии:

1.Вам нужно вызвать form.save_m2m() , чтобы сохранить данные «многие ко многим», если вы перешли commit=False к form.save docs.djangoproject.com/en/3.1/topics/forms/modelforms /…

2. value="b1" Более того, часть не будет работать, поскольку это не первичный ключ книги.

3. Обратите внимание, что вы можете работать с виджетом для отображения флажков, нет необходимости вручную отображать это в шаблоне.

4. @IainShelvington Я должен вызывать form.save_m2m() после library.save() верно? По какой-то причине данные по-прежнему не сохраняются.

5. @WillemVanOnsem Что я должен вместо этого указать для значения? Пример был бы действительно полезен!

Ответ №1:

Обновление для всех, кто застрянет на этом в будущем: в вашей функции просмотра вам нужно получить или создать объект book и сохранить его в соответствующей библиотеке. Вам также необходимо удалить книги из полей в формах.

 #views.py
...
        if form.is_valid():
            library = form.save()
            books = request.POST.getlist('books')
            for b in books:
                b = Book.objects.get_or_create(name=b)[0]
                b.save()
                library.books.add(b)
            return redirect('browse')
    else:
...
 

И вы также можете убедиться, что это легко работает в вашем html со следующим:

 #create_library.html
    <form method="POST">
        {% csrf_token %}
        {% for book in booklist %}
        {{ book.get_name_display }}
        <input type="checkbox" value="{{ book.name }}" name="books">
        <br>
        {% endfor %}
        <button type="submit">Submit</button>
    </form>