如何防止Django中的post_save递归? [英] How can I prevent post_save recursion in Django?
问题描述
在Django中使用 signal
时遇到一些问题。
I have some problems when using signal
in Django.
post_save
由于函数内的 instance.save()
而发生递归。
post_save
occurs recursion because of instance.save()
inside of function.
但是奇怪的是
- 没有发生递归的情况。
models.py
class Product(TimeStampedModel):
name = models.CharField(max_length=120)
slug = models.SlugField(null=True, blank=True)
description = models.CharField(max_length=400, blank=True)
is_active = models.BooleanField(default=True)
objects = ProductManager()
class Meta:
ordering = ('-created',)
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse(
"products:product_detail",
kwargs={
"slug": self.slug,
}
)
信号。 py
@receiver(post_save, sender=Product)
def post_save_product(sender, instance, created, **kwargs):
if not instance.slug:
instance.slug = slugify(instance.name, allow_unicode=True)
instance.save()
当我使用 Product创建
它不会发生递归。 Product
时.objects.create()
When I create Product
using Product.objects.create()
it doesn't occur recursion.
- 发生递归的情况
models.py
class Variation(TimeStampedModel):
COLOR_CHOICES = (
('black', '흑백'),
('single', '단색'),
('multi', '컬러'),
)
price = models.DecimalField(
decimal_places=2,
max_digits=15,
blank=True,
null=True,
)
product = models.ForeignKey(Product)
color = models.CharField(
max_length=10,
choices=COLOR_CHOICES,
default='흑백'
)
is_active = models.BooleanField(default=True)
class Meta:
ordering = ('product',)
def __str__(self):
return "{product} - {color}".format(
product=self.product,
color=self.color
)
signals.py
@receiver(post_save, sender=Variation)
def post_save_variation(sender, instance, created, **kwargs):
if not instance.price:
if instance.color == '흑백':
instance.price = 40000
elif instance.color == '단색':
instance.price = 50000
elif instance.color == '컬러':
instance.price = 60000
instance.save()
此发生递归错误s:
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/base.py", line 708, in save
force_update=force_update, update_fields=update_fields)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/base.py", line 745, in save_base
update_fields=update_fields, raw=raw, using=using)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/dispatch/dispatcher.py", line 192, in send
response = receiver(signal=self, sender=sender, **named)
File "/Users/Chois/Dropbox/Workspace/django/spacegraphy-project/spacegraphy/products/signals/post_save.py", line 24, in post_save_variation
instance.save()
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/base.py", line 708, in save
force_update=force_update, update_fields=update_fields)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/base.py", line 745, in save_base
update_fields=update_fields, raw=raw, using=using)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/dispatch/dispatcher.py", line 192, in send
response = receiver(signal=self, sender=sender, **named)
File "/Users/Chois/Dropbox/Workspace/django/spacegraphy-project/spacegraphy/products/signals/post_save.py", line 24, in post_save_variation
instance.save()
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/base.py", line 708, in save
force_update=force_update, update_fields=update_fields)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/base.py", line 736, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/base.py", line 796, in _save_table
base_qs = cls._base_manager.using(using)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/manager.py", line 122, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/manager.py", line 214, in get_queryset
return self._queryset_class(model=self.model, using=self._db, hints=self._hints)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/query.py", line 171, in __init__
self.query = query or sql.Query(self.model)
File "/Users/Chois/.pyenv/versions/spacegraphy/lib/python3.5/site-packages/django/db/models/sql/query.py", line 155, in __init__
self.where = where()
RecursionError: maximum recursion depth exceeded while calling a Python object
我认为这两种情况具有相同的结构,但只有一种情况发生递归。
I think those two cases have same structure but only one case occurs recursion.
不知道为什么。
推荐答案
在保存之前先断开信号,然后再次连接。 https://docs.djangoproject.com/en/1.10/topics/信号/#disconnecting-signals
Disconnect the signal before save, then connect again. https://docs.djangoproject.com/en/1.10/topics/signals/#disconnecting-signals
def post_save_product(sender, instance, **kwargs):
post_save.disconnect(post_save_product, sender=sender)
instance.do_stuff()
instance.save()
post_save.connect(post_save_product, sender=sender)
post_save.connect(post_save_product, sender= Product)
这篇关于如何防止Django中的post_save递归?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!