如何将对象包括在类别或子类别中?

时间:2019-09-17 11:54:18

标签: django django-models

我需要建立这种关系:

└───SCOPE01
    ├───PROJECT01
    │   └───WORKER01
    └───WORKER02

工作人员可以在某些项目上忙,也可以在某些范围内空闲。 我选择了正确的方法,并且否则我该怎么做

#models.py
from django.db import models


class Scope(models.Model):
    title = models.CharField(max_length=30)


class Project(models.Model):
    title = models.CharField(max_length=30)
    scope = models.ForeignKey(
        Scope,
        related_name='projects',
        on_delete=models.CASCADE
    )


class Worker(models.Model):
    title = models.CharField(max_length=30)
    project = models.ForeignKey(
        Project,
        related_name='workers',
        on_delete=models.CASCADE
    )
    scope = models.ForeignKey(
        Scope,
        related_name='workers',
        on_delete=models.CASCADE
    )

如果这是正确的,如何将同时添加的工作人员限制在范围和项目中?

1 个答案:

答案 0 :(得分:1)

  

工作人员可以在某些项目上忙,也可以在某些范围内空闲。我选择了正确的方法吗?

没有足够的规格说明。这是一个排他的“或”吗? “一定范围内免费”是什么意思?究竟什么是“范围”?工人可以从范围A的“自由”更改为范围B的“在项目上忙”吗?工人既不能“忙于某个项目”,又不能“在某些范围内没有空”?

这些只是我想到的头几个问题... IOW:对于知道上下文的人来说,您的“规格”当然很清楚,但我们不知道!-)< / p>

  

如果正确的话

实际上,不是完全正确-至少Worker.project应该可以为空,这样工作人员可以“在一定范围内自由”:

class Worker(models.Model):
    title = models.CharField(max_length=30)
    project = models.ForeignKey(
        Project,
        null=True,
        blank=True,
        related_name='workers',
        on_delete=models.CASCADE
    )
    scope = models.ForeignKey(
        Scope,
        related_name='workers',
        on_delete=models.CASCADE
    )
  

如何将同时添加的工人限制在范围和项目中?

如果这意味着一个工作人员应该与一个范围XOR(异或)或一个项目相关联,那么您必须使两个字段都可为空:

class Worker(models.Model):
    title = models.CharField(max_length=30)
    project = models.ForeignKey(
        Project,
        null=True,
        blank=True,
        related_name='workers',
        on_delete=models.CASCADE
    )
    scope = models.ForeignKey(
        Scope,
        null=True,
        blank=True,
        related_name='workers',
        on_delete=models.CASCADE
    )

然后,您可以将1 /添加几个方法到Worker类中,以将其分配给项目或范围(并同时使其他关系为空):

class Worker(models.Model):
    title = models.CharField(max_length=30)
    project = models.ForeignKey(
        Project,
        null=True,
        blank=True,
        related_name='workers',
        on_delete=models.CASCADE
    )
    scope = models.ForeignKey(
        Scope,
        null=True,
        blank=True,
        related_name='workers',
        on_delete=models.CASCADE
    )

    def assign_to_project(self, project, commit=True):
        self.project = project
        self.scope = None
        if commit:
            self.save()

   def assign_to_scope(self, scope, commit=True):
        self.scope = scope
        self.project = None
        if commit:
            self.save()

,然后通过save()方法添加一些验证(简单但不一定是最佳解决方案):

   def save(self, *args, **kw):
       if self.project and self.scope:
           raise SomeCustomException("cannot assign worker to both a scope and project at the same time")
       super(Worker, self).save(*args, **kw)

using model validation-但您必须确保调用了full_clean方法(调用clean方法)(模型形式会自动进行,但这仅是全部)。但是您当然可以使用full_clean方法自己调用save

class Worker(models.Model):
    title = models.CharField(max_length=30)
    project = models.ForeignKey(
        Project,
        null=True,
        blank=True,
        related_name='workers',
        on_delete=models.CASCADE
    )
    scope = models.ForeignKey(
        Scope,
        null=True,
        blank=True,
        related_name='workers',
        on_delete=models.CASCADE
    )

    def assign_to_project(self, project, commit=True):
        self.project = project
        self.scope = None
        if commit:
            self.save()

   def assign_to_scope(self, scope, commit=True):
        self.scope = scope
        self.project = None
        if commit:
            self.save()


   def clean(self):
       if self.project and self.scope:
           raise ValidationError("cannot assign worker to both a scope and project at the same time")

   def save(self, *args, **kw):
       self.full_clean()
       super(Worker, self).save(*args, **kw)

编辑:(关于assign_to_scope()assign_to_project()方法)

  

这是否意味着它们将被自动调用,或者我可以在需要时显式调用它们吗?我只是不明白他们将被称为什么? -您的代码中没有调用它们

对不起,这对我来说是显而易见的,但是不,这里没有魔术,您必须在适当的地方自己调用这些方法-第一个显而易见的地方是您的模型形式和/或视图和/或drf序列化器(如果您使用drf)等。我没有提供任何示例,因为我不知道您将如何实际使用这些模型。

在处理此问题时,您可能希望将这些字段标记为“受保护”(如果您是python的新手,请在它们的名称前添加一个下划线,这是惯例,该属性应表示“可以直接访问)并提供只读的公共访问器,即(nb:问题与解答示例代码,可能会出现错别字或其他错误):

class Worker(models.Model):
    title = models.CharField(max_length=30)
    _project = models.ForeignKey(
        Project,
        null=True,
        blank=True,
        related_name='workers',
        on_delete=models.CASCADE
    )

    @property
    def project(self):
        return self._project

    _scope = models.ForeignKey(
        Scope,
        null=True,
        blank=True,
        related_name='workers',
        on_delete=models.CASCADE
    )

    @property
    def scope(self):
        return self._scope

    def assign_to_project(self, project, commit=True):
        self._project = project
        self._scope = None
        if commit:
            self.save()

   def assign_to_scope(self, scope, commit=True):
        self._scope = scope
        self._project = None
        if commit:
            self.save()

   def clean(self):
       if self._project and self._scope:
           raise ValidationError("cannot assign worker to both a scope and project at the same time")


   # etc