español - Django accede a los campos ManyToMany desde la señal post_save
django signals español (2)
Tengo un modelo de Django y quiero modificar los permisos del objeto en o justo después de guardar. He intentado algunas soluciones y la señal post_save
pareció la mejor candidata para lo que quiero hacer:
class Project(models.Model):
title = models.CharField(max_length=755, default=''default'')
assigned_to = models.ManyToManyField(
User, default=None, blank=True, null=True
)
created_by = models.ForeignKey(
User,
related_name="%(app_label)s_%(class)s_related"
)
@receiver(post_save, sender=Project)
def assign_project_perms(sender, instance, **kwargs):
print("instance title: "+str(instance.title))
print("instance assigned_to: "+str(instance.assigned_to.all()))
En este caso, cuando se crea un proyecto, la señal se dispara y veo el title
, pero una lista vacía para el campo assigned_to
.
¿Cómo puedo acceder a los datos assigned_to
después de guardar?
Cualquier ayuda muy apreciada.
No vas a hacerlo. Los M2M se guardan después de guardar las instancias y, por lo tanto, no habrá ningún registro en todas las actualizaciones m2m. Otros problemas (incluso si resuelve eso) son que todavía está en una transacción y consultar el DB no le permitirá obtener m2m con los estados correctos de todos modos.
La solución es enganchar en la señal m2m_changed
lugar de post_save
.
https://docs.djangoproject.com/en/dev/ref/signals/#m2m-changed
Su remitente sería Project.assigned_to.through
Si su m2m puede estar vacía (en blank=True
), tiene un pequeño problema con m2m_changed
, porque m2m_changed
no se activa si m2m no se configuró. Puedes resolver este problema usando post_save
y m2m_changed
al mismo tiempo. Pero hay una gran desventaja con este método: su código se ejecutará dos veces si el campo m2m no está vacío.
Entonces, puedes usar la transacción on_commit ( solo Django> = 1.9 )
from django.db import transaction
def on_transaction_commit(func):
def inner(*args, **kwargs):
transaction.on_commit(lambda: func(*args, **kwargs))
return inner
@receiver(post_save, sender=SomeModel)
@on_transaction_commit
def my_untimate_func(sender, **kwargs):
# Do things here