【问题标题】:Django: How to cascade an update through multiple models?Django:如何通过多个模型级联更新?
【发布时间】:2022-01-01 11:14:02
【问题描述】:

我正在编写一个基于 Django 的应用程序来跟踪对象 (Objekt) 及其维护任务。对象可以链接到一个位置。

位置 (0/1) --- (n) 对象 (1) --- (n) 任务

Location、Objekt 和 Task 都有一个具有以下值的状态字段:

    RED = "red"
    YELLOW = "yellow"
    GREEN = "green"
    STATUS = [
        (RED, "Overdue tasks"),
        (YELLOW, "Pending tasks"),
        (GREEN, "All good"),
    ]

我希望位置地图标记根据相关对象和最终任务的状态更改其颜色。

我已经尝试关注django best practices 并创建一个胖模型。

from django.db import models
from locationapp.models import Location
from taskapp.models import Task
from rules.contrib.models import RulesModel

class Objekt(RulesModel):
    RED = "red"
    YELLOW = "yellow"
    GREEN = "green"
    STATUS = [
        (RED, "Overdue tasks"),
        (YELLOW, "Pending tasks"),
        (GREEN, "All good"),
    ]
    name = models.CharField(max_length=200)
    description = models.TextField(blank=True)
    location = models.ForeignKey(
        Location, on_delete=models.SET_NULL, null=True, blank=True
    )
    status = models.CharField(max_length=6, choices=STATUS, default=GREEN)

    def set_status(self):
        if Task.objects.filter(objekt=self.id).filter(status=Task.RED).exists():
            self.status = Objekt.RED
        elif Task.objects.filter(objekt=self.id).filter(status=Task.YELLOW).exists():
            self.status = Objekt.YELLOW
        else:
            self.status = Objekt.GREEN

但不知何故,我不确定我的概念...... Task 的更新如何触发相关 Objekt 的更新。如果需要,Objekt 将如何进一步触发位置更新?

【问题讨论】:

    标签: python django model


    【解决方案1】:

    一个潜在的解决方案是使用信号。我已经实现它如下,现在没有芹菜:

    # objektapp/apps.py
    from django.apps import AppConfig
    
    
    class ObjektappConfig(AppConfig):
        default_auto_field = 'django.db.models.BigAutoField'
        name = 'objektapp'
    
        def ready(self):
            import objektapp.signals
    
    # objektapp/signals.py
    from django.db.models.signals import post_save
    from django.dispatch import receiver
    from django.db import transaction
    from taskapp.models import Task
    from objektapp.models import Objekt
    
    @receiver(post_save, sender=Task)
    def set_status(sender, instance, created, **kwargs):
        # TODO: Use celery for async operation: https://docs.djangoproject.com/en/3.2/topics/db/transactions/
        transaction.on_commit(lambda: objekt_update_status(instance))
    
    def objekt_update_status(task_instance):
        objekt = Objekt.objects.get(id=task_instance.objekt.id)
    
        new_objekt_status = Objekt.GREEN
        if Task.objects.filter(objekt=task_instance.objekt.id, status=Task.RED).exists():
            new_objekt_status = Objekt.RED
        elif Task.objects.filter(objekt=task_instance.objekt.id, status=Task.YELLOW).exists():
            new_objekt_status = Objekt.YELLOW
    
        if objekt.status != new_objekt_status:
            objekt.status = new_objekt_status
            objekt.save()
    

    我在 Location 模型上做了类似的设置,它也会对来自 Objekt 的 post_save 信号作出反应。我不确定它是否是将 objekt_update_status() 函数存储在 signals.py 文件中的最佳位置,但尝试将其放入 models.py 最终会出现循环导入错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-05-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-08
      • 1970-01-01
      • 2020-03-05
      相关资源
      最近更新 更多