微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

如何从 Django 中的另一个模型字段更新模型的字段? 解决方案

如何解决如何从 Django 中的另一个模型字段更新模型的字段? 解决方案

我有两个模型。 DepartmentGoal 有一个字段“scores”,Task 也有一个字段“scores”和一个外部部门目标。

我想要的是;如果我将分数分配给 DepartmentGoal,分配给 Task 的分数应该从 DepartmentGoal 的分数中减去,这意味着任何数量的 Task 分数相加应该等于 DepartmentGoal 的单个实例的分数。

我只需要一个关于如何实现这一点的线索。

这是模型

class DepartmentGoal(models.Model):
   name = models.TextField(max_length=150,null=True)
   score = models.IntegerField(null=True,blank=True)
   created_at = models.DateTimeField(auto_Now_add=True,null=True)
   updated_at = models.DateTimeField(auto_Now=True,null=True)

   def __str__(self):
       return self.name



class Task(models.Model):
   name = models.CharField(max_length=300,null=True)
   departmentgoal = models.ForeignKey(DepartmentGoal,on_delete=models.CASCADE,related_name='departgoal',null=True,blank=True)
   score = models.IntegerField(null=True,null=True)

   def __str__(self):
       return self.name

这里是表格

class DepartmentGoalForm(ModelForm):
    class Meta:
        model = DepartmentGoal
        fields = (         
            ('name'),('score'),)


class TaskForm(ModelForm):
    class Meta:
        model = Task
        fields = [ 
            'departmentgoal','name','score',]

这是我的实现

class Task(models.Model):
   name = models.CharField(max_length=300,null=True)


    def save(self,*args,**kwargs):
        goal = DepartmentGoal.objects.get(id=self.departmentgoal.id)
        goal.scores -= self.scores
        goal.save()
        super(Task,self).save(*args,**kwargs)

我现在的问题是,如果部门目标分数用尽,即变为 0,用户仍然可以向任务添加新的任务分数,这会将部门目标分数的值更新为负分数。这是我想要防止的行为。如果部门目标分数值为零,用户应该无法添加更多任务和任务分数

解决方法

之前的回复

我将采用的方法是仅将任务分数公开为可编辑,并在保存或更新 Task 实例时,更新关联 scoreDepartmentGoal。我不允许编辑 DepartmentGoal 分数的原因是因为将更改传播到相关任务会很困难。

想象一下,如果您的 DepartmentGoal 得分为 10 并且它有两个相关任务:

  1. 任务 1 - 当前,分数设置为 7
  2. 任务 2 - 当前,分数设置为 3

现在,如果您将 DepartmentGoal 分数更新为 13,您如何将更改向下传播到任务?任务 1 的分数增加 2,任务 2 的分数增加 1 吗?每项任务的分数是否增加了相等的数量(在这种情况下,这意味着每项任务 +1.5)?

因此,通过只允许编辑任务分数并将更改传播回 DepartmentGoal,您至少可以确信 DepartmentGoal 分数将准确反映相关 { {1}} 分。毕竟,根据您的评论,您同意 Task 分数是一个计算字段

所以解决方案非常简单。您可以覆盖 DepartmentGoal 模型的 Task 方法,或使用保存后信号。我将使用前一种方法进行演示,但如果您选择使用后保存信号,则情况类似。

save

这只是一个最小可行的例子。显然,可以对保存后挂钩进行一些优化,例如检查任务的 class Task(models.Model): name = models.CharField(max_length=300,null=True) departmentgoal = models.ForeignKey( DepartmentGoal,on_delete=models.CASCADE,related_name='departgoal',null=True,blank=True) score = models.IntegerField(null=True,blank=True) created_at = models.DateTimeField(auto_now_add=True,null=True) updated_at = models.DateTimeField(auto_now=True,null=True) def __str__(self): return self.name def save(self,*args,**kwargs): super().save(*args,**kwargs) # post-save,update the associated score of the `DepartmentGoal` # 1. grab associated `DepartmentGoal` goal = DepartmentGoal.objects.get(id=self.departmentgoal.id) # 2. sum all task scores of the `DeparmentGoal` # Note: I'm using `departgoal` which is the `related_name` you set on # the foreign key. I would rename this to `tasks` since the `related_name` # is the reference back to the model from the foreign key. sum = goal.departgoal.values("departmentgoal") \ .annotate(total=models.Sum("score")) \ .values_list("total",flat=True)[0] # 3. update score of `DepartmentGoal` with the calculated `sum` goal.score = sum goal.save(update_fields=["score"]) 是否已更改,但这需要使用字段跟踪器,例如 django-model-utils 提供的跟踪器。

附加说明:

您还可以使用 score 方法,在这种方法中您不需要运行任何保存后挂钩,但在调用 property 属性时让 python 计算分数的总和。这样做的好处是您无需在保存任务后进行任何计算(因此可以优化性能)。但是,缺点是您将无法在 django 查询集中使用属性,因为查询集使用字段,而不是属性。

property

更新回复

以下是您的要求:

  1. 预先定义 DepartmentGoal 的得分。
  2. 任何具有给定分数的新任务都会减少 DepartmentGoal 的预定义分数。
  3. 在用完预定义的分数后,不应允许为该 DepartmentGoal 执行任何其他任务。
  4. 此外,对任务分数的任何修改都不应导致超过预定义分数的总任务分数。

解决方案

  1. 在您的 DepartmentGoal 模型中,定义一个名为 class DepartmentGoal(models.Model): name = models.TextField(max_length=150,null=True) created_at = models.DateTimeField(auto_now_add=True,null=True) def __str__(self): return self.name @property def score(self): if self.departgoal.count() > 0: return ( self.departgoal.values("departmentgoal") .annotate(total=models.Sum("score")) .values_list("total",flat=True)[0] ) return 0 的字段。这是您预先定义分数的字段,并且是必填字段。
  2. 在您的任务模型中,添加一个 clean 方法来验证分数。 score 方法将自动由您的 clean 调用。
  3. 回到您的 DepartmentGoal 模型,添加一个 ModelForm 方法来验证分数,以防用户计划修改目标分数。如果目标已经有关联的任务,这可以确保分数不会低于任务总和。
clean

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。