Django m2m form save “through” table

У меня возникают проблемы с сохранением данных m2m, содержащих таблицу classов «через». Я хочу сохранить все выбранные элементы (выбранные в форме) в сквозной таблице. Но я не знаю, как инициализировать таблицу «через» в представлении.

мой код:

class Classroom(models.Model): user = models.ForeignKey(User, related_name = 'classroom_creator') classname = models.CharField(max_length=140, unique = True) date = models.DateTimeField(auto_now=True) open_class = models.BooleanField(default=True) members = models.ManyToManyField(User,related_name="list of invited members", through = 'Membership') class Membership(models.Model): accept = models.BooleanField(User) date = models.DateTimeField(auto_now = True) classroom = models.ForeignKey(Classroom, related_name = 'classroom_membership') member = models.ForeignKey(User, related_name = 'user_membership') 

и в перспективе:

 def save_classroom(request): classroom_instance = Classroom() if request.method == 'POST': form = ClassroomForm(request.POST, request.FILES, user = request.user) if form.is_valid(): new_obj = form.save(commit=False) new_obj.user = request.user new_obj.save() membership = Membership(member = HERE SELECTED ITEMS FROM FORM,classroom=new_obj) membership.save() 

Как я должен правильно инициализировать членство в таблице членства?

В случае использования нормального отношения m2m (а не через промежуточную таблицу) вы можете заменить:

 membership = Membership(member = HERE SELECTED ITEMS FROM FORM,classroom=new_obj) membership.save() 

с

 form.save_m2m() 

Но в случае использования промежуточных таблиц вам необходимо вручную обрабатывать данные POST и создавать объекты Membership со всеми обязательными полями ( аналогичная проблема ). Самое основное решение – изменить ваше представление на что-то вроде:

 def save_classroom(request): if request.method == 'POST': form = ClassroomForm(request.POST, request.FILES) if form.is_valid(): new_obj = form.save(commit=False) new_obj.user = request.user new_obj.save() for member_id in request.POST.getlist('members'): membership = Membership.objects.create(member_id = int(member_id), classroom = new_obj) return HttpResponseRedirect('/') else: form = ClassroomForm() return render_to_response('save_classroom.html', locals()) 

Обратите внимание, как обрабатывается request.POST (.getlist). Это связано с тем, что post и get являются объектами QueryDict, которые имеют некоторые последствия (request.POST [‘members’] всегда возвращает один объект!).

Вы можете изменить этот код, чтобы повысить его надежность (обработка ошибок и т. Д.) И более подробные, например:

 member = get_object_or_404(User, pk = member_id) membership = Membership.objects.create(member = member , classroom = new_obj) 

Но обратите внимание, что вы выполняете некоторые запросы db в цикле, что не является хорошей идеей в целом (с точки зрения производительности).

Как и dzida, но используйте form.cleaned_data вместо request.post:

 def save_classroom(request): if request.method == 'POST': form = ClassroomForm(request.POST, request.FILES) if form.is_valid(): new_obj = form.save(commit=False) new_obj.user = request.user new_obj.save() for member in form.cleaned_data['members'].all(): Membership.objects.create(member = member, classroom = new_obj) return HttpResponseRedirect('/') else: form = ClassroomForm() return render_to_response('save_classroom.html', locals()) 

Вам также необходимо учитывать, что некоторые членства могут быть удалены, поэтому:

 def save_classroom(request): if request.method == 'POST': form = ClassroomForm(request.POST, request.FILES) if form.is_valid(): new_obj = form.save(commit=False) new_obj.user = request.user new_obj.save() final_members = form.cleaned_data['members'].all() initial_members = form.initial['members'].all() # create and save new members for member in final_members: if member not in initial_members: Membership.objects.create(member = member, classroom = new_obj) # delete old members that were removed from the form for member in initial_members: if member not in final_members: Membership.objects.filter(member = member, classroom = new_obj).delete() return HttpResponseRedirect('/') else: form = ClassroomForm() return render_to_response('save_classroom.html', locals()) 

Если вы используете модельные формы (например, в общем CBV: form_class=ClassroomForm ), переопределите и поместите логику сохранения выше в метод save , например:

 ClassroomForm(forms.ModelForm): members = ModelMultipleChoiceField( queryset=Classroom.objects.all(), widget=SelectMultiple ) def save(self, commit=True): classroom = super().save(commit=False) if commit: classroom.save() if 'members' in self.changed_data: final_members = form.cleaned_data['members'].all() initial_members = form.initial['members'].all() # create and save new members for member in final_members: if member not in initial_members: Membership.objects.create(member = member, classroom = new_obj) # delete old members that were removed from the form for member in initial_members: if member not in final_members: Membership.objects.filter(member = member, classroom = new_obj).delete() return classroom 

Вам также необходимо указать class для членства:

 membership = Membership(member = request.user, classroom=new_obj) #if new_obj if your classroom membership.save() 

Я думаю, вы также должны удалить User в accept = models.BooleanField(User) . Не нужно устанавливать дату при сохранении, если вы используете auto_now ! Но, возможно, `auto_now_add более вероятно, что вам нужно ( http://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.DateField )

Так я сделал это в общем представлении classа UpdateForm (django 1.8) для аналогичного, но другого приложения, использующего метод form_valid.

 def form_valid(self, form): """ If the form is valid, save the associated model. """ self.object.members.clear() self.object = form.save(commit=False) self.object.user = self.request.user self.object.save() list_of_members = form.cleaned_data['members'] ClassRoom.objects.bulk_create([ Membership( Course=self.object, member=member_person, order=num) for num, member_person in enumerate(list_of_members) ]) return super(ModelFormMixin, self).form_valid(form) 
Interesting Posts

Мой жесткий диск не работает?

Рисование символа в VGA-памяти с встроенной сборкой GNU C

MongoDB, удалять объект из массива

Закрытие соединений JDBC в пуле

Как добавить изображение в папку «drawable» в Android Studio?

сюжеты, создаваемые «сюжет» и «ggplot» бок о бок

JSON.net: как десериализовать без использования конструктора по умолчанию?

Pen Drive автоматически получил защиту от записи

Как я имитирую статические методы в classе с помощью easymock?

Не используйте опцию «Безопасное удаление» в лотке для устройств хранения USB

Как виртуальное наследование разрешает двусмысленность «бриллиантов» (множественное наследование)?

Может ли модуль тестирования проекта загрузить файл app.config целевого приложения?

Как подключиться к точке доступа по BSSID вместо ESSID в Windows 7?

Динамически создавать столбцы для кросс-таблицы в PostgreSQL

Повторение ввода пользователя во всех документах Microsoft Word

Давайте будем гением компьютера.