Django 将 self 传递给 models.SET on_delete

标签 django django-models django-signals

我想在从数据库中删除外键值时对其进行修改。所以我查看了文档并使用了 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,它将外键设置为 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(或您配置的任何内容)。

关于Django 将 self 传递给 models.SET on_delete,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36571834/

相关文章:

python - 对于 Django 模型,是否有查看记录是否存在的快捷方式?

python - 在 Django 中删除 ForeignKey 时在相关模型上发出信号

Django 就地编辑

python - 如何在 Django 中调用异步函数?

django - Django无法连接到gitlab ci中的postgres数据库

python - Django 身份验证模型错误 : name 'User' is not defined

python - 在 Django 管理中重新排序应用程序和模型

Django 管理模板覆盖不起作用

python - Django REST 框架 : return 404 (not 400) on POST if related field does not exist?

python - 跨不同容器接收 Django 信号