tabla plantillas girls girl formulario form example estilos dinamica con campos calculados django

plantillas - Django eliminar objeto extraño?



plantillas con django (3)

Si configuramos un perfil como recomienda Django:

class Profile(models.Model): user = models.ForeignKey(User, unique=True)

Luego, cuando elimina el objeto User del administrador de Django, también elimina su perfil. Esto se debe a que el perfil tiene una clave externa para el usuario y quiere proteger la integridad referencial. Sin embargo, quiero esta funcionalidad incluso si el puntero va hacia otro lado. Por ejemplo, en mi clase de Profile tengo:

shipper = models.ForeignKey(Shipper, unique=True, blank=True, null=True) carrier = models.ForeignKey(Carrier, unique=True, blank=True, null=True) affiliat = models.ForeignKey(Affiliate, unique=True, blank=True, null=True, verbose_name=''Affiliate'')

Y lo quiero para que, si eliminas el Profile , eliminará los objetos asociados del remitente / transportista / afiliado (no me preguntes por qué Django hizo "afiliado" alguna palabra clave extraña). Debido a que los remitentes, transportistas y afiliados son tipos de usuarios, no tiene sentido que existan sin el resto de los datos (nadie podría iniciar sesión como uno solo).

La razón por la que no puse las llaves en los otros objetos, es porque entonces Django tendría que unir internamente todas esas tablas cada vez que quisiera verificar qué tipo de usuario era ...


Puede anular el método delete() de la clase de perfil y eliminar los otros objetos en este método antes de eliminar el perfil real.

Algo como:

class Profile(models.Model): # ... def delete(self): if self.shipper: self.shipper.delete() if self.carrier: self.carrier.delete() if self.affiliat: self.affiliat.delete() super(Profile, self).delete()


Si bien el uso de una señal post_delete como lo describe bernardo arriba es un buen enfoque, funcionará bien, trato de evitar usar las señales tan poco como sea humanamente posible, ya que creo que complica innecesariamente su código agregando comportamiento a la funcionalidad estándar en lugares donde uno podría estar esperando.

Yo prefiero el método de anulación anterior, sin embargo, el ejemplo dado por Félix tiene un defecto fatal; La función delete () que está reemplazando se ve así:

def delete(self, using=None): using = using or router.db_for_write(self.__class__, instance=self) assert self._get_pk_val() is not None, "%s object can''t be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) collector = Collector(using=using) collector.collect([self]) collector.delete()

Observe el parámetro ''usar'', en la mayoría de los casos llamamos a delete () con argumentos vacíos, por lo que podemos incluso saber que estaba allí. En el ejemplo anterior, este parámetro está oculto por nosotros anulando y sin mirar la funcionalidad de la superclase, si alguien a quien se le pasa el parámetro ''usar'' al eliminar el perfil, causará un comportamiento inesperado. Para evitar eso, nos aseguraríamos de preservar el argumento junto con su lika por defecto así que:

class Profile(models.Model): # ... def delete(self, using=None): if self.shipper: self.shipper.delete() if self.carrier: self.carrier.delete() if self.affiliat: self.affiliat.delete() super(Profile, self).delete(using)

Sin embargo, un obstáculo para el enfoque primordial es que a delete () no se le llama explícitamente por registro de db en eliminaciones masivas, esto significa que si desea eliminar múltiples perfiles a la vez y mantener el comportamiento primordial (llamada). eliminar () en un django queryset, por ejemplo) tendrá que aprovechar la señal de eliminar (como lo describe bernardo) o tendrá que recorrer cada registro eliminándolos individualmente (caro y feo).


Una mejor manera de hacer esto y que funciona con el método de eliminación de objetos y el método de eliminación de queryset es usar la señal post_delete , como se puede ver en la documentation .

En su caso, su código sería muy similar a esto:

from django.db import models from django.dispatch import receiver @receiver(models.signals.post_delete, sender=Profile) def handle_deleted_profile(sender, instance, **kwargs): if instance.shipper: instance.shipper.delete() if instance.carrier: instance.carrier.delete() if instance.affiliat: instance.affiliat.delete()

Esto funciona solo para Django 1.3 o superior porque la señal post_delete se agregó en esta versión de Django.