python through - Was sind die Schritte, um ein ModelForm mit einer ManyToMany-Beziehung mit einem intermediären Modell in Django zu arbeiten?




one filter (5)

Wenn du jetzt die Speichermethode verwendest, wird Django versuchen, mit dem Manager zu speichern (was Django nicht erlaubt). Leider ist das Verhalten, das Sie wollen, ein wenig komplizierter als das, was ModelForm standardmäßig tut. Was Sie tun müssen, ist ein Formularsatz erstellen.

Zuallererst müssen Sie die Optionen Ihrer ClientForm damit das Attribut groupes nicht angezeigt wird.

class ClientForm(ModelForm):
    class Meta:
        model = Client
        exclude = ('groupes',)

Als Nächstes müssen Sie die Ansicht ändern, um das Formset anzuzeigen:

from django.forms.models import inlineformset_factory

def modifier(request, id):
    client = Client.objects.get(id=id)    
    form = ClientForm(instance = client)
    # Create the formset class
    GroupeFormset = inlineformset_factory(Client, Groupe)
    # Create the formset
    formset = GroupeFormset(instance = client)

    dict = {
        "form": form
        , "formset" : formset
        , "instance" : client
    }

    if request.method == "POST":
        form = ClientForm(request.POST, instance = client)
        formset = GroupeFormset(request.POST, instance = client)

        if form.is_valid() and formset.is_valid():
            client_mod = form.save()
            formset.save()

            id = client_mod.id
            return HttpResponseRedirect(
                "/client/%(id)s/?err=success" % {"id" : id}
            )
        else:
            return HttpResponseRedirect(
                "/client/%(id)s/?err=warning" % {"id" : id}
            )

    return render_to_response(
        "client/modifier.html"
        , dict
        , context_instance=RequestContext(request)
    )

Und natürlich müssen Sie auch Ihre Vorlage optimieren, um das Formset zu rendern.

Weitere Informationen zu Formsets finden Sie in folgenden Artikeln:

Modellformsätze
Formsets

  • Ich habe ein Client- und Groupe- Modell.
  • Ein Client kann Teil mehrerer Gruppen sein .
  • Kunden , die Teil einer Gruppe sind, können den kostenlosen Mietpreis ihrer Gruppe jederzeit aber nur einmal nutzen. Hier kommt das Zwischenmodell ( ClientGroupe ) mit diesen zusätzlichen Daten ins Spiel .

Für den Moment, wenn ich versuche, die m2m-Daten zu speichern, stirbt es einfach und sagt, ich sollte den ClientGroupe-Manager verwenden ... Was fehlt also?

Hier sind meine Modelle:

class Groupe(models.Model):
    nom = models.CharField(max_length=1500, blank=True)

class Client(models.Model):
    nom = models.CharField(max_length=450, blank=True)
    prenom = models.CharField(max_length=450, blank=True)
    groupes = models.ManyToManyField(Groupe, null = True, blank = True, through='ClientGroupe')

class ClientGroupe(models.Model):
    client = models.ForeignKey(Client)
    groupe = models.ForeignKey(Groupe)
    dt = models.DateField(null=True, blank=True) # the date the client is using its group's free rental rate    

    class Meta:
        db_table = u'clients_groupes'

und hier ist meine Ansicht:

def modifier(request, id):
    client = Client.objects.get(id=id)    
    form = ClientForm(instance = client)

    dict = {
        "form": form
        , "instance" : client
    }

    if request.method == "POST":
        form = ClientForm(request.POST, instance = client)

        if form.is_valid():
            client_mod = form.save()

            id = client_mod.id
            return HttpResponseRedirect(
                "/client/%(id)s/?err=success" % {"id" : id}
            )
        else:
            return HttpResponseRedirect(
                "/client/%(id)s/?err=warning" % {"id" : id}
            )

    return render_to_response(
        "client/modifier.html"
        , dict
        , context_instance=RequestContext(request)
    )

EDIT :

und hier ist der ClientForm-Code:

class ClientForm(ModelForm):
    class Meta:
        model = Client

EDIT # 2 : Hier ist die Fehlermeldung:

AttributeError at /client/445/

Cannot set values on a ManyToManyField which specifies an intermediary model. Use ClientGroupe's Manager instead.

Request Method:     POST
Request URL:    http://localhost/client/445/
Exception Type:     AttributeError
Exception Value:    Cannot set values on a ManyToManyField which specifies an intermediary model.  Use ClientGroupe's Manager instead.

Exception Location:     C:\Python25\lib\site-packages\django\db\models\fields\related.py  in __set__, line 574
Python Executable:  C:\xampp\apache\bin\apache.exe
Python Version:     2.5.2

Wahrscheinlich müssen Sie das Feld ManyToMany aus Ihrem Client-Modell entfernen oder es sorgfältig aus Ihrem Formular ausschließen. Leider kann das Standard-Widget für das Feld ManyToMany das ClientGroupe-Modell nicht ordnungsgemäß ausfüllen (auch wenn das fehlende Feld dt auf autonow = True gesetzt wurde). Dies ist etwas, das Sie entweder in ein anderes Formular ausbrechen müssen oder in Ihrer Sicht handhaben müssen.


…
if form.is_valid():
    client_mod = form.save(commit=False)
    client_mod.save()
    for groupe in form.cleaned_data.get('groupes'):
        clientgroupe = ClientGroupe(client=client_mod, groupe=groupe)
        clientgroupe.save()
    …

Ich biete eine alternative Lösung aufgrund von Problemen, die ich bei nicht aufgerufenem forms_valid festgestellt habe:

class SplingCreate(forms.ModelForm):
class Meta:
    model = SplingModel
    fields = ('Link', 'Genres', 'Image', 'ImageURL',)

def save(self, commit=True):
    from django.forms.models import save_instance

    if self.instance.pk is None:
        fail_message = 'created'
    else:
        fail_message = 'changed'
    fields = set(self._meta.fields) - set(('Genres',))
    instance = save_instance(self, self.instance, fields,
                             fail_message, commit, construct=False)

    genres = self.cleaned_data.get('Genres')
    for genre in genres:
        SplingGenreModel.objects.get_or_create(spling=instance, genre=genre)

    return instance

Ich habe die Logik von djangos forms / models.py kopiert, mein Feld Genres ist ein Vielfaches mit einer Zwischentabelle - ich schließe es aus der save_instance aus und speichere es dann separat.


Ich bin auch auf dieses Problem gestoßen. Ich benutze Nginx mit HHVM, unten behobene Lösung mein Problem:

sudo semanage fcontext -a -t httpd_sys_rw_content_t "/etc/nginx/fastcgi_temp(/.*)?"

sudo restorecon -R -v /etc/nginx/fastcgi_temp




python django django-models django-templates django-forms