2009-06-05 11 views
2

Je sais que cette question a été postée plusieurs fois, mais je ne pouvais toujours pas trouver une réponse définitive à ce problème. Donc, ici je vais:Django enregistrer personnalisé avec problème ManyToManyField

class Invoice(models.Model): 
    program = models.ForeignKey(Program) 
    customer = models.ForeignKey(Customer, related_name='invoices') 
    participants = models.ManyToManyField(Participant, related_name='participants_set') 
    subtotal = models.DecimalField(max_digits=10, decimal_places=2, default='0.00', blank=True, null=False) 
    pst = models.DecimalField("PST", max_digits=10, decimal_places=2, default='0.00', blank=True, null=False) 
    gst = models.DecimalField("GST", max_digits=10, decimal_places=2, default='0.00', blank=True, null=False) 
    total = models.DecimalField(max_digits=10, decimal_places=2, default='0.00', blank=True, null=False) 

    def save(self, **kwargs): 
     super(Invoice, self).save(**kwargs) 
     items = self.participants.count() 
     subtotal = Decimal(self.program.fee) * items 
     pst = self.program.is_pst and Decimal(PST)*subtotal or Decimal('0.00') 
     gst = self.program.is_gst and Decimal(GST)*subtotal or Decimal('0.00') 
     total = (subtotal + pst) + gst 
     self.subtotal = subtotal 
     self.pst = pst 
     self.gst = gst 
     self.total = total 
     super(Invoice, self).save(**kwargs) 

Tout fonctionne bien sauf que self.participants.count() ne fonctionne pas. Toute idée de ce qui pourrait être le problème. Toute aide très appréciée.

+1

Quelle version de Django? Votre appel à self.participants.count() devrait fonctionner. – Harold

+0

La méthode count génère-t-elle une exception ou donne-t-elle une valeur erronée? –

Répondre

0

Au lieu de surcharger la méthode de sauvegarde, je recommande d'utiliser le pre-save signal. En plus de rendre votre code un peu plus propre, cela évite les problèmes étranges comme ceux-ci :)

0

Je pense que ce qui se passe est parce que vous essayez de compter un nombre de participants lors d'une sauvegarde, la requête peut ne pas être tout trouver. Si vous dépendez de ce nombre lors de la création de la base de données, je ne pense pas que la table many-to-many sera synchronisée correctement car le Invoice n'a pas encore d'ID affecté. Par contre, les autres participants peuvent ne pas être enregistrés dans la base de données. Inversement, les autres participants peuvent ne pas être enregistrés dans la base de données. De toute façon, en fonction de ce nombre lors d'une sauvegarde ne fonctionnera pas, indépendamment de l'utilisation de signaux. Je recommanderais d'avoir une méthode séparée qui fait ce calcul. Il est plus propre, améliore les performances de sauvegarde et vous pouvez l'appeler sans enregistrer.

+0

Cela semble être une bonne idée de séparer complètement les participants et d'enregistrer simplement la quantité (nombre de participants). De cette façon, le modèle Facture serait plus générique. –

0

J'ai eu un problème similaire. J'avais un modèle qui supportait les tags de style del.icio.us. La fonction save analysera une liste des étiquettes (par exemple "python django web") et les convertira en instances d'objet tag individuelles en appelant une fonction auxiliaire update_tags() (voir ci-dessous pour un exemple simplifié). Toutefois, ManyToManyField ne refléterait pas les modifications lorsque j'ai modifié l'objet dans l'interface d'administration.

class Article(models.Model): 
    tag_string = models.CharField(max_length=255, null=True, blank=True) #del.icio.us style tags, like: django python software 
    tags = models.ManyToManyField(Tag, blank=True) 

    def save(self, force_insert=False, force_update=False): 
     super(Article, self).save(force_insert, force_update) 

     self.update_tags() #The result of this function didn't seem to be saved in the ManyToManyField 

Il s'avère que l'interface d'administration remplaçait les modifications apportées à ManyToManyField. La solution était tout simplement de retirer le ManyToManyField du admin.ModelAdmin:

class ArticleAdmin(admin.ModelAdmin): 
    exclude = ['tags']