2012-08-03 17 views
6

Quiero crear una relación simétrica en mi modelo y también añadir un campo en la relación. Me encontré con this blog (y también this another blog) y seguido los pasos en la creación de mis propios modelos.¿Cómo crear automáticamente objetos simétricos en ManyToManyField de Django?

class CreditCardIssuer(models.Model): 
    name = models.CharField(_('name'), max_length=256) 
    transfer_limits = models.ManyToManyField('self', through='Balancetransfer', related_name='no_transfer_allowed+', symmetrical=False, help_text=_('List of issuers to which balance transfer is not allowed.')) 

    def add_balancetransfer(self, creditcardissuer, until): 
     balance_transfer, _newly_created = Balancetransfer.objects.get_or_create(
      no_transfer_from=self, 
      no_transfer_to=creditcardissuer, 
      until=until) 
     balance_transfer, _newly_created = Balancetransfer.objects.get_or_create(
      no_transfer_from=creditcardissuer, 
      no_transfer_to=self, 
      until=until) 
     return balance_transfer 

    def remove_balancetransfer(self, creditcardissuer, until): 
     Balancetransfer.objects.filter(
      no_transfer_from=self, 
      no_transfer_to=creditcardissuer, 
      until=until).delete() 
     Balancetransfer.objects.filter(
      no_transfer_from=self, 
      no_transfer_to=creditcardissuer, 
      until=until).delete() 
     return 

    def get_transfer_limits(self, until): 
     return self.transfer_limits.filter(
      no_transfer_to__until=until, 
      no_transfer_to__no_transfer_from=self) 


class Balancetransfer(models.Model): 
    no_transfer_from = models.ForeignKey('CreditCardIssuer', related_name='no_transfer_from') 
    no_transfer_to = models.ForeignKey('CreditCardIssuer', related_name='no_transfer_to') 
    until = models.IntegerField(blank=True, null=True, help_text='Minimum card ownership period to allow balance transfer.') 

    class Meta: 
     unique_together = ('no_transfer_from', 'no_transfer_to') 

Pero cuando creo la relación desde admin, solo se crea una. ¿Puedes ayudarme a resolver el problema?

+0

¿Puede tal vez elaborar un poco más en detalle a qué se refiere con _only es created_? O especifica lo que esperas que pase? –

+0

La función CreditCardIssuer.add_balancetransfer muestra lo que quiero lograr cuando creo una relación desde admin. De esta forma, la relación se creará para ambos objetos. Gracias por tomarse el tiempo para resolverlo. – noel

+0

No se crearán dos relaciones "automáticamente". No obstante, no estoy 100% seguro sobre el comportamiento que estás esperando. ¿Puedes elaborar? – coleifer

Respuesta

1

Usted dice que tienes la mitad de esto en la administración de Django (usted no dice cómo, pero voy a suponer que funciona a menos que publique el código): el paso que falta es la creación de la mitad de la relación que falta

sospecho que si se pone un punto de interrupción en su add_balancetransfer() método (import pdb; pdb.set_trace()), encontrará que nunca se está llamando - la parte de la relación que se creados se realiza a través de una función de administrador de Django comportamiento .

En resumen, puede que necesite llamar al add_balancetransfer() usted mismo cuando se guarda el modelo o, mejor aún, una versión diferente que solo agrega la relación faltante.

Una forma de hacerlo es overriding the model's save() method, pero esto puede ser un poco frágil. Por su situación, es posible que funcione mejor para llenar en la relación que falta en el model's post_save signal:

from django.db.models.signals import post_save 
from django.dispatch import receiver 

from yourapp.models import CreditCardIssuer 

@receiver(post_save, sender=CreditCardIssuer) 
def add_missing_relationship(sender, **kwargs): 
    # Add the other side of what should be a symmetrical relationship 
    ... 
+0

Gracias por las sugerencias. Ya agregué un poco de registro dentro de esos métodos y confirmó que nunca se llaman. Si no hay una forma automática de crear el objeto de relación inversa, tal vez vaya con el método de salvar(). – noel

+0

@supervacuo parece un error tipográfico. Su importación es para post_save y su receptor usa pre_save. – hobs

+0

@hobs buena captura, gracias. Corregido (a 'post_save') ahora. – supervacuo

Cuestiones relacionadas