web-dev-qa-db-fra.com

Substitution de la méthode de sauvegarde dans Django ModelForm

J'ai du mal à remplacer une méthode de sauvegarde ModelForm. Voici l'erreur que je reçois:

Exception Type:     TypeError  
Exception Value:    save() got an unexpected keyword argument 'commit'

Mes intentions sont d'avoir un formulaire soumettant de nombreuses valeurs pour 3 champs, puis de créer un objet pour chaque combinaison de ces champs et d'enregistrer chacun de ces objets. Un coup de pouce utile dans la bonne direction serait un as.

Fichier models.py

class CallResultType(models.Model):
    id = models.AutoField(db_column='icontact_result_code_type_id', primary_key=True)
    callResult = models.ForeignKey('CallResult', db_column='icontact_result_code_id')
    campaign = models.ForeignKey('Campaign', db_column='icampaign_id')
    callType = models.ForeignKey('CallType', db_column='icall_type_id')
    agent = models.BooleanField(db_column='bagent', default=True)
    teamLeader = models.BooleanField(db_column='bTeamLeader', default=True)
    active = models.BooleanField(db_column='bactive', default=True)

Fichier forms.py

from Django.forms import ModelForm, ModelMultipleChoiceField
from callresults.models import *

class CallResultTypeForm(ModelForm):
    callResult = ModelMultipleChoiceField(queryset=CallResult.objects.all())
    campaign = ModelMultipleChoiceField(queryset=Campaign.objects.all())
    callType = ModelMultipleChoiceField(queryset=CallType.objects.all())

    def save(self, force_insert=False, force_update=False):
        for cr in self.callResult:
            for c in self.campain:
                for ct in self.callType:
                    m = CallResultType(self) # this line is probably wrong
                    m.callResult = cr
                    m.campaign = c
                    m.calltype = ct
                    m.save()

    class Meta:
        model = CallResultType

Fichier admin.py

class CallResultTypeAdmin(admin.ModelAdmin):
    form = CallResultTypeForm
58
Josh Smeaton

Dans votre save, vous devez avoir l'argument commit. Si quelque chose remplace votre formulaire ou souhaite modifier ce qu'il enregistre, il fera save(commit=False), modifiera la sortie, puis l'enregistrera lui-même.

En outre, votre ModelForm doit renvoyer le modèle qu'il enregistre. Habituellement, le save d'un ModelForm ressemblera à quelque chose comme:

def save(self, commit=True):
    m = super(CallResultTypeForm, self).save(commit=False)
    # do custom stuff
    if commit:
        m.save()
    return m

Lisez sur la méthode save .

Enfin, une grande partie de ce ModelForm ne fonctionnera pas simplement à cause de la façon dont vous accédez aux choses. Au lieu de self.callResult, vous devez utiliser self.fields['callResult'].

[~ # ~] mise à jour [~ # ~] : En réponse à votre réponse:

Mis à part: Pourquoi ne pas simplement utiliser ManyToManyFields dans le modèle pour ne pas avoir à le faire? On dirait que vous stockez des données redondantes et que vous travaillez davantage pour vous (et moi :P).

from Django.db.models import AutoField  
def copy_model_instance(obj):  
    """
    Create a copy of a model instance. 
    M2M relationships are currently not handled, i.e. they are not copied. (Fortunately, you don't have any in this case)
    See also Django #4027. From http://blog.elsdoerfer.name/2008/09/09/making-a-copy-of-a-model-instance/
    """  
    initial = dict([(f.name, getattr(obj, f.name)) for f in obj._meta.fields if not isinstance(f, AutoField) and not f in obj._meta.parents.values()])  
    return obj.__class__(**initial)  

class CallResultTypeForm(ModelForm):
    callResult = ModelMultipleChoiceField(queryset=CallResult.objects.all())
    campaign = ModelMultipleChoiceField(queryset=Campaign.objects.all())
    callType = ModelMultipleChoiceField(queryset=CallType.objects.all())

    def save(self, commit=True, *args, **kwargs):
        m = super(CallResultTypeForm, self).save(commit=False, *args, **kwargs)
        results = []
        for cr in self.callResult:
            for c in self.campain:
                for ct in self.callType:
                    m_new = copy_model_instance(m)
                    m_new.callResult = cr
                    m_new.campaign = c
                    m_new.calltype = ct
                    if commit:
                        m_new.save()
                    results.append(m_new)
         return results

Cela permet l'héritage de CallResultTypeForm, juste au cas où cela serait nécessaire.

138
tghw