在Django中,如何保持多对多关系的同步



在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",
)

请注意,这里有相当多的冗余,简历和工作经验都指向同一个所有者等。也就是说,这两个模型(简历和工作经历(都有一个名为技能的字段。这引用了另一个名为Skills的模型。

我想要的是拥有简历技能,以指向与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对象引用了一项技能,然后我从一个对象中删除了该技能,我如何确保简历中的引用仍然完好无损?即,两个工作经验对象指的是"技能";Javascript";。我从一个WorkExperience对象中移除技能。技能"Javascript";应该仍然被简历引用,因为一个WorkExperience对象仍然有对它的引用。

编辑:我想这样做的原因是为了减少前端的查询量。如果过滤技能的唯一方法是通过";子模型";(工作经验,教育经验(,我需要在前端做两个查询,而不是一个。尽管现在我想一想,做两个查询并没有那么糟糕。

根据您的设计,Skills似乎实际上属于所有者,即AUTH_USER。通过在Resume&其他型号肯定会造成冗余。你为什么不创建一个用户技能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

我从错误的角度处理这个问题。当我只是对Skill对象进行反向查询时,我不必担心是否检查Skills。目前,我正在我的视图中过滤技能查询集,如下所示:

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

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

最新更新