2010-10-19 20 views
2

Tenir compte que je l'ai défini les modèles suivants:Comment remplacer correctement la méthode save() ModelForm pour un modèle avec ManyToManyField

class Tag(models.Model): 
    name = models.CharField(max_length=20) 

class Entry(models.Model): 
    title = models.CharField(max_length=100) 
    date = models.DateField() 
    tags = models.ManyToManyField(Tag) 

et le formulaire de modèle suivant:

class EntryForm(forms.ModelForm): 
    tags = CharField(max_length=100, label='Tags', required=False) 
    class Meta: 
    model = Entry 

Fondamentalement, j'ai une entrée avec Mots clés. Les tags ne sont pas nécessairement déjà créés. Je dois recevoir un formulaire d'inscription rempli et le sauvegarder avec des tags.

Je peux le faire facilement si je n'ai pas la relation ManyToMany dans l'entrée. Mais avec cela, je dois d'abord enregistrer les étiquettes, puis ajouter les étiquettes enregistrées à l'entrée, puis enregistrer l'entrée. Ce qui signifie que je dois remplacer la méthode save() d'EntryForm.

J'ai déjà vu la question this, mais elle a l'air différente. Dans mon cas, je n'ai besoin de sauvegarder que les tags, et le reste devrait pouvoir utiliser save() par défaut de ModelForm.

J'ai présenté un exemple simplifié. En vrai, j'ai beaucoup plus de champs dans l'entrée. Quelle est votre recommandation pour écrire la méthode save() d'EntryForm d'une manière django?

Répondre

1

La meilleure et bonne option serait ici pour ajouter la méthode clean_tags à la forme, ne pas passer outre la sauvegarde() dans le modèle.

def clean_tags(self): 
    tags = self.cleaned_data.get('tags', None) 

    clean_tags = [] 


    tags = [tag.strip() for tag in tags.split(',') if tags] 

    for tag in tags: 
     t, created = Tag.objects.get_or_create(title=tag) 
     t.count = F('count') + 1 
     t.user.add(self.cleaned_data['user']) 
     t.save() 
     clean_tags.append(t) 

    return clean_tags 
+0

Oui, cela ressemble vraiment à une meilleure solution. – grigy

3

Je pense que vous pouvez appeler super après avoir sauvegardé les tags. Peut-être que vous devez ajouter à l'entrée après que l'entrée est créée.

def save(self, commit=True): 
    # do custom stuff 
    tags =[] 
    for t in self.cleaned_data['tags'].split(','): 
     tags.append(Tag.objects.get_or_create(name=t)) 
    # save entry 
    e = super(EntryForm, self).save(commit=commit) 

    for t in tags: 
     e.tags.add(t) 
+0

Merci. Mais un problème. Comment puis-je empêcher la sauvegarde initiale du champ des balises à super (EntryForm, self) .save()? – grigy

+1

Bonne question. Vous pouvez également enregistrer l'entrée manuellement. Si vous obtenez l'instance, 'Entry.objects.get (id = instance.id)', puis mettez à jour les champs, sinon 'Entry.objects.create (title = ..., date = ...)'. Ensuite, ajoutez les tags. C'est si peu de travail que l'utilisation de la sauvegarde du formulaire peut ne pas en valoir la peine. – OmerGertel

+0

Une correction: get_or_create renvoie un tuple - (tag, créé), donc nous devons prendre seulement la première partie – grigy