Django保存相关的ManyToMany模型

时间:2017-11-08 23:23:54

标签: django django-forms django-views

我有两个与ManyToMany关系的模型:

class Subject(models.Model):
    teachers = models.ManyToManyField(
        Teacher
    )
    subject = models.CharField(
       'Materia',
       max_length = 50,
       unique = True
   )
   level = models.CharField(
       'Nivel',
       max_length = 3,
       choices = LEVEL_CHOICES
   )

class Teacher(Person):
    # fields definition

Following the docs我知道我可以在不保存教师字段的情况下保存主题模型。没关系。

现在我想向教师添加一个主题,所以我需要一个包含所选教师的表单,以及一个包含所有主题的选择字段。

I found this question与我想要完成的事情相关,但我认为它并没有解决我正在寻找的问题。

首先,我填充主题选择字段,如下面的ModelForm代码所示。

forms.py

class SubjectTeacherForm(ModelForm):
    subject = forms.ChoiceField(choices=[(m.id, m.subject) for m in Subject.objects.all()])

    class Meta:
        model = Subject
        fields = ['teachers', 'subject']

urls.py

#here I send the teacher id to the view
url(r'^materias/asignar/profesor/(?P<teacher_id>\d+)/$',MateriaTeacherCreateView.as_view(), name='materia-create-teacher'),

views.py

class SubjectTeacherCreateView(SuccessMessageMixin, CreateView):
    model = Subject
    template_name = 'edu/subject/subject_create.html'
    form_class = SubjectTeacherForm

    def form_valid(self, form):
        # here I want to add the relation
        teacher = Teacher.objects.get(pk=self.kwargs['teacher_id'])
        # I understad that object here is the ModelForm, not the Model, so this is wrong
        self.object.teachers.add(teacher)
        return redirect(self.get_success_url())

    def get_context_data(self, **kwargs):
        context = super(SubjectTeacherCreateView, self).get_context_data(**kwargs)
        # here I define the selected teacher to pass to the template
        context['teacher'] = Teacher.objects.get(pk=self.kwargs['teacher_id'])
        return context

模板

<form method="post" class="form-horizontal">
    {% csrf_token %}
    {{ form.teacher }}
    {{ form.subject }}

正如预期的那样,这不起作用,表单没有保存,它会抛出错误:

AttributeError at /edu/materias/asignar/profesor/11/
'NoneType' object has no attribute 'teachers'

所以,显然我做错了什么。

我的问题是我是否可以使用基于类的视图来完成此任务,或者我应该编写一个方法来保存关系,以及我应该在代码中更改什么。

我希望自己足够清楚,谢谢。

2 个答案:

答案 0 :(得分:1)

您需要在super(SubjectTeacherCreateView, self).form_valid(form)中拨打form_valid,然后在覆盖之前获取self.object,这是源form_vaild方法:

def form_valid(self, form):
    """
    If the form is valid, save the associated model.
    """
    self.object = form.save()
    return super(ModelFormMixin, self).form_valid(form)

但作为你的条件,这是正确的方法:

def form_valid(self, form):
    try:
        subject = Subject.object.get(id=form.cleaned_data['subject'])
        teacher = Teacher.objects.get(pk=self.kwargs['teacher_id'])
        subject.teachers.add(teacher)
    except Subject.DoesNotExist:
        # handle it youself
    return redirect(self.get_success_url()

答案 1 :(得分:0)

我认为您需要一个特定的get_object()才能从subject中找到teacher_id的对象。

def get_object(self):
    teacher_id = self.kwargs['teacher_id']
    subject = get_object_or_404(self.model, teachers__id=teacher_id)
    return subject

并且,如果self.object.teachers.add(teacher)不起作用,请尝试将其指定为列表self.object.teachers.add([teacher])

相关问题