【问题标题】:In Django, how to keep many-to-many relations in sync?在 Django 中,如何保持多对多关系同步?
【发布时间】:2020-09-14 08:42:50
【问题描述】:

在 Django 中,设置并保持最新的多对多字段的最佳方式是什么,该字段是(由于缺乏更好的术语)来自其他模型的多对多字段的组合?

举个具体的例子,我有一个代表简历的模型。

class Resume(models.Model):
    owner = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="resume",
    )
    description = models.TextField(default="Resume description")
    skills = models.ManyToManyField(Skill, related_name="resume")

Resume 对象被另一个名为 WorkExperience 的模型引用:

class WorkExperience(models.Model):
    ...
    skills = models.ManyToManyField(Skill, related_name="work")
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=False,
        default=1,
        related_name="work_experience",
    )
    resume = models.ForeignKey(
        Resume,
        on_delete=models.CASCADE,
        null=False,
        default=1,
        related_name="work_experience",
    )

请注意,这里有相当多的冗余,Resume 和 WorkExperience 都指向同一个所有者等。也就是说,这两个模型(Resume 和 WorkExperience)都有一个名为 Skills 的字段。这引用了另一个名为 Skills 的模型。

我想要的是让 Resume 技能指向与 WorkExperience 中的技能相同的技能。关于如何做到这一点的任何建议?我还有一个名为 EducationExperience 的模型,它也引用了 Skills 并且与 Resume 有外键关系。有什么方法可以让 Resume 中的技能与 WorkExperience 和 EducationExperience 中的技能保持同步?

一个简单的选择是实现一个名为 set_resume_skills 的方法,该方法在调用时会将他们拥有的技能添加到 Resume 拥有的技能列表中

Class WorkExperience(models.Model):
    # Same model as above
    def set_resume_skills(self):
        self.resume.skills.add(self.skills)

我对这种方法的问题是它只会增加技能,并不能真正让它们保持同步。因此,如果我从 WorkExperience 中删除一项技能,它不会从 Resume 中删除。另一个边界条件是,如果多个 WorkExperience 对象正在引用一项技能,然后我从一个对象中删除了该技能,我将如何确保 Resume 中的引用仍然完好无损?即,两个工作经验对象指的是技能“Javascript”。我从一个 WorkExperience 对象中删除了技能。技能“Javascript”仍应被 Resume 引用,因为一个 WorkExperience 对象仍然具有对它的引用。

编辑:我想这样做的原因是为了减少在前端完成的查询量。如果过滤技能的唯一方法是通过“子模型”(WorkExperience、EducationExperience),我需要在前端执行两个查询而不是一个。虽然现在想想,做两个查询也不错。

【问题讨论】:

    标签: python django django-models foreign-keys many-to-many


    【解决方案1】:

    根据您的设计,技能似乎实际上属于所有者,即 AUTH_USER。通过在简历和其他模型中具有其 M2M 关系肯定会导致冗余。为什么不在用户模型中创建一个 M2M 技能?

    关于减少查询的要点,还有其他方法可以做到这一点。通过使用select_relatedprefetch_related

    class User(models.Model):
    skills = models.ManyToManyField(Skill, related_name="resume")
    # ... Other fields here
    
    class Resume(models.Model):
    owner = models.OneToOneField(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        related_name="resume",
    )
    description = models.TextField(default="Resume description")
    # ... Other fields here
    

    【讨论】:

    • 非常感谢。我一直在犹豫是否直接指向 AUTH_USER,但这样做会显着降低复杂性。
    【解决方案2】:

    我从错误的角度解决问题。当我只对技能对象进行反向查询时,我不必担心检查技能。目前我在我的视图中过滤技能查询集,如下所示:

    class SkillViewSet(viewsets.ModelViewSet):
        serializer_class = SkillSerializer
    
        def get_queryset(self):
            queryset = Skill.objects.all()
            email = self.request.query_params.get("email", None)
            if email:
                User = get_user_model()
                user = User.objects.get(email=email)
                query_work_experience = Q(work__owner=user)
                query_education_experience = Q(education__owner=user)
                queryset = queryset.filter(
                    query_work_experience | query_education_experience
                )
    
            return queryset
    

    这消除了使技能与简历模型保持同步的需要。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-11-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-04
      • 2016-06-20
      • 2015-07-02
      • 2015-02-14
      相关资源
      最近更新 更多