2017-11-08 3 views
0

Ich habe zwei Modelle mit ManyToMany Beziehung wie folgt aus:Django Speichern Ähnliche ManyToMany Modell

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 Ich weiß, dass ich, ohne zu speichern Lehrer Feld Betreff Modell speichern. Das ist gut.

Jetzt möchte ich ein Thema zum Lehrer hinzufügen, so brauche ich ein Formular mit ausgewählten Lehrer und ein Auswahlfeld mit allen Themen.

I found this question das bezieht sich auf das, was ich erreichen möchte, aber ich denke, dass es nicht adressiert, was ich suche.

Zuerst befülle ich das Subjektauswahlfeld, wie in dem ModelForm-Code unten gezeigt.

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 

die Vorlage

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

Wie erwartet, das funktioniert nicht, wird das Formular nicht speichern, wirft sie den Fehler:

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

Also, natürlich etwas mache ich falsch.

Meine Frage ist, ob ich Klassenbasierte Ansichten verwenden kann, um dies zu erreichen, oder ich sollte eine Methode schreiben, um die Beziehung zu speichern, und was soll ich in meinem Code ändern.

Ich erwarte, dass ich mich klar genug gemacht habe, danke.

Antwort

1

Sie super(SubjectTeacherCreateView, self).form_valid(form) in Ihrem form_valid anrufen müssen, dann können Sie self.object bekommen, ist dies Quelle form_vaild Methode, bevor Sie außer Kraft setzen:

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) 

aber als Bedingung, dies ist der richtige Weg:

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() 
+0

Das ist, wonach ich gesucht habe. Aber ein Detail, das ich jetzt feststelle, ist, dass ich den Eingabe-Lehrer in der Vorlage nicht brauche, da ich es in einer Ansicht fangen und handhaben kann. Also, was funktioniert hat, ist Lehrer = Teacher.objects.get (pk = self.kwargs ['teacher_id']) versuchen: materia = Materia.objects.get (id = Formular.cleaned_data ['materia']) materia.teachers.add (Lehrer) ' –

+0

Warum wählen Sie nicht gleichzeitig mehrere Lehrer? – Ykh

+0

Meine Logik ist, dass ich einen bestimmten Lehrer auswähle, und dann füge ich die Themen hinzu. Beziehen Sie sich darauf? –

0

Ich denke, Sie brauchen eine spezifische get_object(), um das Objekt subject von der teacher_id zu finden.

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

und auch, wenn self.object.teachers.add(teacher) nicht funktioniert, versuchen Sie als Liste self.object.teachers.add([teacher]) zuzuordnen.

Verwandte Themen