Chi*_*fir 5 python django many-to-many signals
我有3个型号:
class Product(TimeStampedModel):
category = models.ForeignKey('Category', related_name='products', to_field='category_name')
brand = models.ForeignKey('Brand', related_name='products', to_field='brand_name')
class Brand(models.Model):
brand_name = models.CharField(max_length=50)
categories = models.ManyToManyField('Category', related_name='categories')
class Category(models.Model):
category_name = models.CharField(max_length=128)
Run Code Online (Sandbox Code Playgroud)
我想Brand-Category在更改后更新 M2M 关系Product.category。
我尝试连接信号,就像文档m2m_changed中描述的那样:
@receiver(m2m_changed, sender=Brand.categories.through)
def category_changed(sender, **kwargs):
print("Signal connected!")
Run Code Online (Sandbox Code Playgroud)
我还注册signal了apps.py一个project_folder:
def ready(self):
from my_app.signals import category_changed
Run Code Online (Sandbox Code Playgroud)
但问题是——这段代码没有任何效果。我改变了Product.category- 并且没有看到任何打印。我应该如何修复它才能使其正常工作?
这是处理 Many2Many 字段更改的正确方法 Django Docs
from django.db.models.signals import m2m_changed
m2m_changed.connect(category_changed,sender=Brand.categories.through)
Run Code Online (Sandbox Code Playgroud)
编辑:我没有意识到 Chiefir 正在请求 QuerySet更新方法上的信号,为此我们不能使用内置 m2m_changed 信号。正如拉尔夫在之前的回答中指出的那样,在更新时触发信号可能会导致性能问题,例如在收听保存的直通的情况下。然而,有一个解决方案,恕我直言,不会带来性能问题。
本质上,您可以重写查询集更新方法,以在每次更新整个查询集时触发自定义信号。每次查询集更新只会触发一次,您可以通过检查更新参数将其指定为仅在一个特定字段更新时触发。
该信号现在发送正在更新的查询集和作为有效负载的值。请注意,在此代码中,信号是在类别更新之前发送的。要改变这一点,请将超级输出保存为变量,分派信号并返回变量。
from django.dispatch import Signal, receiver
product_category_updated = Signal(providing_args=["queryset", "value"])
class ProductQuerySet(models.QuerySet):
def update(self, *args, **kwargs):
if 'category' in kwargs:
product_category_updated.send(sender=self.__class__, queryset=self, value=kwargs.get('category'))
return super(ProductQuerySet, self).update(*args, **kwargs)
class ProductManager(models.Manager):
def get_queryset(self, show_hidden=False):
return ProductQuerySet(self.model, using=self._db, hints=self._hints)
class Product(TimeStampedModel):
objects = ProductManager()
category = models.ForeignKey('Category', related_name='products', to_field='category_name', on_delete=models.deletion.CASCADE)
brand = models.ForeignKey('Brand', related_name='products', to_field='brand_name', on_delete=models.deletion.CASCADE)
class Brand(models.Model):
brand_name = models.CharField(max_length=50, unique=True)
categories = models.ManyToManyField('Category', related_name='categories')
class Category(models.Model):
category_name = models.CharField(max_length=128, unique=True)
@receiver(product_category_updated, sender=ProductQuerySet)
def category_changed(sender, **kwargs):
print("Signal connected!")
Run Code Online (Sandbox Code Playgroud)
我必须通过在foreignkey字段上添加on_delete属性并使brand_name和category_name唯一来调整代码以适应我的Django 2.0.7版本。