Django 将自己传递给 models.SET on_delete
Django pass self to models.SET on_delete
我想修改从数据库中删除的外键值。所以我查看了文档并使用了 on_delete=models.SET(foo) 方法。 https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.SET
这是我的模型定义
class OrderLine(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET(getDuplicateProduct), null=True)
quantity = models.PositiveSmallIntegerField(default=1)
finalPricePerUnit = models.PositiveIntegerField()
order = models.ForeignKey(Order, on_delete=models.PROTECT)
dateCreated = models.DateTimeField(auto_now=False, auto_now_add=True)
这是我在删除时调用的方法
def getDuplicateProduct(orderline):
productToDelete = orderline.product
# some logic to generate duplicate copy and returning it
但是这里的问题是我不能将参数传递给这个方法,这就是为什么我不知道哪个产品被删除了。我还尝试使用此答案中指定的信号 django model on_delete pass self to models.SET()
我也尝试过使用信号,但也没有用。我似乎无法为此找到合适的解决方案。
如果有人知道如何实现这一点,请告诉我。
编辑
这是我在信号中使用的代码
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
#further processing
现在的问题是 django 也试图删除我的订单(默认 on_delete 设置为级联)。如果我将 on_Delete 设置为 SET_NULL,它会将外键设置为空。
编辑-2
这是我使用的代码
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
product.name = product.name + ' ' + product.get_type_display()
newProduct = deepcopy(product)
newProduct.name = product.name + ' ' + product.get_type_display()
newProduct.pk=None
newProduct.id=None
newProduct.save()
product.duplicateProductId = newProduct.id
product.old_orderlines = orderlines
product.save()
@receiver(post_delete, sender=Product)
def handlePostDelete(sender, **kwargs):
product = kwargs['instance']
newProduct = Product.objects.get(id=product.duplicateProductId)
for orderline in product.old_orderlines:
orderline.product = newProduct
orderline.save()
编辑-3
为了完整起见,发布完整的实现。
@receiver(pre_delete, sender=Product)
def handlePreDelete(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
shouldCreate=False
for orderline in orderlines:
if orderline.order.status>1:
shouldCreate=True
product.shouldCreate = shouldCreate
if shouldCreate:
product.old_orderlines = orderlines
product.save()
else:
product.save()
return None
@receiver(post_delete, sender=Product)
def handlePostDelete(sender, **kwargs):
product = kwargs['instance']
shouldCreate = product.shouldCreate
if shouldCreate:
newProduct = deepcopy(product)
newProduct.name = product.name + ' ' + product.get_type_display()
newProduct.pk=None
newProduct.id=None
newProduct.save()
# Do whatever you want with product.old_orderlines
for orderline in product.old_orderlines:
orderline.product = newProduct
orderline.save()
信号是执行此操作的正确方法。
您可以从信号接收器获取OrderLine
:
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
# orderlines contains all the OrderLines foreign keyed to the product.
orderlines
是一个可以迭代的查询集或 update in bulk.
编辑
原来上面建议的方法行不通,因为在 pre_delete
信号触发时 Django 已经确定它需要用 on_delete
处理哪些相关模型,并将覆盖这些变化。
这种方法可行,尽管有点笨拙:
首先,在 pre_delete
接收器中:
从复制导入复制
@receiver(pre_delete, sender=Product)
def handlePreDelete(sender, **kwargs):
product = kwargs['instance']
# Store the OrderLines as a property of the object
# Have to copy it otherwise it will be empty later
product.old_orderlines = copy(product.orderline_set.all())
然后,在 post_delete
接收器中:
@receiver(post_delete, sender=Product)
def handlePostDelete(sender, **kwargs):
product = kwargs['instance']
# Do whatever you want with product.old_orderlines
for line in product.old_orderlines:
# ...
在这两个事件之间,Django 将在 OrderLines 上执行 SET_NULL
(或您配置的任何内容)。
支持@solarissmoke 的回答,我认为这是正确的解决方案,但为了给您更多选择,我会 post 这个。如果你有 product
实例,你可以有它的 orderlines
。例如,如果您像这样将 related_name
添加到 OrderLine.product
:
class OrderLine(models.Model):
product = models.ForeignKey(Product, related_name='orderlines')
然后你可以在你的信号中这样做:
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderlines.all()
只是另一种方法,获得 orderlines
.
我想修改从数据库中删除的外键值。所以我查看了文档并使用了 on_delete=models.SET(foo) 方法。 https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.SET
这是我的模型定义
class OrderLine(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET(getDuplicateProduct), null=True)
quantity = models.PositiveSmallIntegerField(default=1)
finalPricePerUnit = models.PositiveIntegerField()
order = models.ForeignKey(Order, on_delete=models.PROTECT)
dateCreated = models.DateTimeField(auto_now=False, auto_now_add=True)
这是我在删除时调用的方法
def getDuplicateProduct(orderline):
productToDelete = orderline.product
# some logic to generate duplicate copy and returning it
但是这里的问题是我不能将参数传递给这个方法,这就是为什么我不知道哪个产品被删除了。我还尝试使用此答案中指定的信号 django model on_delete pass self to models.SET()
我也尝试过使用信号,但也没有用。我似乎无法为此找到合适的解决方案。 如果有人知道如何实现这一点,请告诉我。
编辑
这是我在信号中使用的代码
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
#further processing
现在的问题是 django 也试图删除我的订单(默认 on_delete 设置为级联)。如果我将 on_Delete 设置为 SET_NULL,它会将外键设置为空。
编辑-2 这是我使用的代码
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
product.name = product.name + ' ' + product.get_type_display()
newProduct = deepcopy(product)
newProduct.name = product.name + ' ' + product.get_type_display()
newProduct.pk=None
newProduct.id=None
newProduct.save()
product.duplicateProductId = newProduct.id
product.old_orderlines = orderlines
product.save()
@receiver(post_delete, sender=Product)
def handlePostDelete(sender, **kwargs):
product = kwargs['instance']
newProduct = Product.objects.get(id=product.duplicateProductId)
for orderline in product.old_orderlines:
orderline.product = newProduct
orderline.save()
编辑-3 为了完整起见,发布完整的实现。
@receiver(pre_delete, sender=Product)
def handlePreDelete(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
shouldCreate=False
for orderline in orderlines:
if orderline.order.status>1:
shouldCreate=True
product.shouldCreate = shouldCreate
if shouldCreate:
product.old_orderlines = orderlines
product.save()
else:
product.save()
return None
@receiver(post_delete, sender=Product)
def handlePostDelete(sender, **kwargs):
product = kwargs['instance']
shouldCreate = product.shouldCreate
if shouldCreate:
newProduct = deepcopy(product)
newProduct.name = product.name + ' ' + product.get_type_display()
newProduct.pk=None
newProduct.id=None
newProduct.save()
# Do whatever you want with product.old_orderlines
for orderline in product.old_orderlines:
orderline.product = newProduct
orderline.save()
信号是执行此操作的正确方法。
您可以从信号接收器获取OrderLine
:
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderline_set.all()
# orderlines contains all the OrderLines foreign keyed to the product.
orderlines
是一个可以迭代的查询集或 update in bulk.
编辑
原来上面建议的方法行不通,因为在 pre_delete
信号触发时 Django 已经确定它需要用 on_delete
处理哪些相关模型,并将覆盖这些变化。
这种方法可行,尽管有点笨拙:
首先,在 pre_delete
接收器中:
从复制导入复制
@receiver(pre_delete, sender=Product)
def handlePreDelete(sender, **kwargs):
product = kwargs['instance']
# Store the OrderLines as a property of the object
# Have to copy it otherwise it will be empty later
product.old_orderlines = copy(product.orderline_set.all())
然后,在 post_delete
接收器中:
@receiver(post_delete, sender=Product)
def handlePostDelete(sender, **kwargs):
product = kwargs['instance']
# Do whatever you want with product.old_orderlines
for line in product.old_orderlines:
# ...
在这两个事件之间,Django 将在 OrderLines 上执行 SET_NULL
(或您配置的任何内容)。
支持@solarissmoke 的回答,我认为这是正确的解决方案,但为了给您更多选择,我会 post 这个。如果你有 product
实例,你可以有它的 orderlines
。例如,如果您像这样将 related_name
添加到 OrderLine.product
:
class OrderLine(models.Model):
product = models.ForeignKey(Product, related_name='orderlines')
然后你可以在你的信号中这样做:
@receiver(pre_delete, sender=Product)
def getDuplicateProduct(sender, **kwargs):
product = kwargs['instance']
orderlines = product.orderlines.all()
只是另一种方法,获得 orderlines
.