python - with - many to many sql




Quelles sont les étapes pour faire fonctionner un ModelForm avec une relation ManyToMany avec un modèle intermédiaire dans Django? (4)

  • J'ai un client et un modèle de groupe .
  • Un client peut faire partie de plusieurs groupes .
  • Les clients faisant partie d'un groupe peuvent utiliser le tarif de location gratuit de leur groupe à tout moment, mais une seule fois. C'est là qu'intervient le modèle intermédiaire ( ClientGroupe ) avec ces données supplémentaires.

Pour l'instant, quand j'essaye de sauvegarder les données m2m, ça meurt et dit que je devrais utiliser le gestionnaire ClientGroupe ... alors qu'est-ce qui manque?

Voici mes modèles:

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'

et voici ma vue:

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 :

et voici le code ClientForm:

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

EDIT # 2 : voici le message d'erreur:

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

Je propose une solution alternative en raison de problèmes rencontrés avec forms_valid qui n’est pas appelé:

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

J'ai copié la logique de djangos forms / models.py, mon champ Genres est un multipletomany avec une table intermédiaire - je l'exclus de la sauvegarde_instance et l'enregistre ensuite séparément.


Lorsque vous enregistrez votre formulaire, vous enregistrez l'objet client. Maintenant, si vous souhaitez affecter le client au groupe, vous devez le faire:

clientgroupe = ClientGroupe.objects.create(client=client_instance, groupe=groupe_instance, dt=datetime.datetime.now())

où client_instance et groupe_instance vos objets client et groupe.


Vous devez probablement supprimer le champ ManyToMany de votre modèle Client ou l'exclure soigneusement de votre formulaire. Malheureusement, le widget par défaut pour le champ ManyToMany ne peut pas remplir correctement le modèle ClientGroupe (même si le champ manquant, dt, a été défini sur autonow = True). C’est quelque chose que vous devrez soit diviser en une autre forme, soit gérer à votre avis.


…
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()
    …