繁体   English   中英

这种数据库模型结构的最佳方法是什么?

[英]What's the best approach for this database models structure?

我正在用 Django 开发一个物业管理系统,现在我正在开发一个名为“Property Check”的应用程序,基本上它的目的是提供一个包含任务列表的表单,例如“Diswasher:clean & empty? ",这些任务需要由工作人员在酒店进行检查。

主要思想是允许管理员在管理员端创建任务及其类别。 示例:任务 - 洗碗水:清洁和清空属于类别 - 厨房。

每个属性检查都属于一个属性,它具有任务列表,这些任务具有不同的状态,例如“已检查”或“需要注意”。

到目前为止,这是我创建的:

模型.py

class Task(models.Model):
    name = models.CharField(db_column='SafetyTaskName', max_length=100, blank=False, null=False)
    category = models.ForeignKey(Categories, db_column='category')
    task_check = models.ForeignKey(TaskCheck)

class Categories(models.Model):
    name = models.CharField(db_column='Categories', max_length=40, null=False, blank=False)

class TaskCheck(models.Model):
    status = models.CharField(db_column='Status', choices=STATUS_CHOICES, default='nd')
    image = models.ImageField(upload_to='property_check',null=True)
    notes = models.CharField(db_column='Notes', max_length=500, blank=True, null=True)  # Field name made lowercase.

class Propertycheck(models.Model):
    property = models.ForeignKey(Property, models.DO_NOTHING, db_column='ID_Property')  # Field name made lowercase.
    task = models.CharField(TaskCheck)
    name = models.CharField(db_column='Name', max_length=150)
    date = models.DateField(db_column='Date', default=timezone.now)  # Field name made lowercase.
    next_visit = models.DateField(db_column='Next Visit')
    staff = models.ForeignKey(User, db_column='Staff', max_length=25)
    notes = models.CharField(db_column='Notes', max_length=500, blank=True, null=True)  # Field name made lowercase.

我假装的功能示例:

一名工作人员前往需要检查的物业,他填写了包含所有任务的表格。 如果需要更多任务,管理员会转到管理面板并添加一个新任务。 相同的状态适用于每个任务。

要求:

  • 一个属性有很多属性检查;
  • 属性检查有一个任务列表;
  • 管理员必须能够添加任务和类别;
  • 任务属于一类;
  • 财产检查由一名工作人员进行;
  • 任务列表对每个属性都相同;
  • 每个任务都必须有一个状态(例如:已完成状态);

问题:我对在哪里使用外键有点困惑。 我需要属性检查来显示任务列表,以及每个任务的状态。

由于我的经验,我现在陷入困境,所以我需要一些帮助。 你能看看我做了什么,让我知道更好的解决方案吗?

* **更新***

感谢 Bruno Desthuilliers 的回答,我可以按照他的建议重组我的模型。 我认为这个解决方案更接近我的需要,但我的问题是,根据布鲁诺的答案的要求,我的更改是否 100% 正确?

class Task(models.Model):
    name = models.CharField(max_length=100)
    category = models.ForeignKey(Categories)
    property = models.ManyToManyField(Property)

class Categories(models.Model):
    name = models.CharField(max_length=40)

class TaskCheck(models.Model):
    status = models.CharField(choices=STATUS_CHOICES, default='nd')
    image = models.ImageField(upload_to='task_check', null=True)
    notes = models.TextField(max_length=500)
    task = models.ForeignKey(Task)
    property_check = models.ForeignKey(Propertycheck)

class Propertycheck(models.Model):
    property = models.ForeignKey(Property, models.DO_NOTHING)
    name = models.CharField(max_length=150)
    date = models.DateField(default=timezone.now)
    next_visit = models.DateField()
    staff = models.ForeignKey(User, max_length=25)
    notes = models.TextField(max_length=500, default='')

我的英语不是最好的,我不确定我的问题的最佳标题。

一个属性有很多属性检查;

这仅描述了关系基数的一半 - 您还需要指定属性检查可以属于多少个属性。 在这种情况下,答案似乎相当明显(我看不到同一个财产检查属于多个财产的情况),但是除非您对该领域有真实而深入的工作知识,否则您仍然应该询问您的客户- 有时“明显”的事情实际上是错误的;-)

但是如果我们考虑“一个属性有多个属性检查”和“一个属性检查属于一个属性”,我们就有一对多的关系。 在 db 模式级别,这是由“多”方中“一”方的外键具体化的,即 PropertyCheck 必须在 Property 上有一个 fk。

当您记得在关系模型中,字段是原子值(每个字段中有一个值)时,这是合乎逻辑的。 您无法在 Property 中存储相关 PropertyCheck id 的列表,但您可以在每个 PropertyCheck 中存储一个 Property id。

当您考虑约束时,这也是合乎逻辑的 - 属性实际上可以具有“零到多个”相关属性检查(您可以具有迄今为止从未被“检查过”的属性),但 PropertyCheck 必须具有相关属性(在没有财产的情况下进行财产检查是没有意义的,是吗?)。 如果属性检查以列表形式存储在属性中的 id,您仍然可以创建没有属性的属性检查(如果删除了属性检查并且未更新属性的属性检查列表,您也会遇到一致性问题)。

因此,长话短说:对于一对多关系,fk 位于“多”侧并指向“一”侧。

属性检查有一个任务列表;

你确定这个是对的吗? 在我看来,您将应用程序的用户视图与数据库架构混淆了。

当然,用户在“属性检查”页面上查看的是要执行的任务列表(以及每个任务的复选框等) - 但这并不意味着任务属于属性检查。 如果是这种情况,管理员将不得不为每个属性检查创建一个新的任务列表......正如我对域的理解一样,重点是每个属性都有一个任务列表,并且系统构建每个属性检查的(尚未检查的)任务检查列表。 哪个 FWIW 已经是您开始设计的。

因此(假设我的问题是正确的),您的规则实际上是“每个属性都有一个任务列表”。 现在我们有另一个基数需要解决:一个任务是否属于一个单一的属性,或者同一个任务可以被多个属性共享?

我们已经介绍了第一种情况(参见上文)。 在第二种情况下——实际上更有可能,因为对于大多数属性肯定有很多任务是相同的——你有一个多对多的关系。 这些由关系表具体化,该表在关系的每一侧都有一个 fk,对 fk 对具有唯一性约束(您不希望为同一属性列出两次相同的任务)。 请注意,使用 Django 的 ORM,您不需要为此明确声明模型(除非您当然需要向关系添加一些其他字段,但到目前为止我认为这里不需要) - 只需声明关系的任何一侧都有一个 many2many 字段(并不重要),ORM 将为您创建中间表。

那么你就有了属性检查和任务检查之间的关系。 这是一个简单的一对多关系——一个属性检查有许多任务检查,一个任务检查属于一个单一的属性检查。 这里唯一的限制是那些任务检查的任务必须与属性检查的属性属于相同的属性(是的,这样写时有点混乱 xD)。 更简单地说:属性的任务列表用作创建属性检查的任务检查列表的蓝图。

IOW你有:

  • 一项任务属于一个或多个属性
  • 一个属性有很多任务
  • 一个属性有很多属性检查
  • 一个财产检查属于一个单一的财产
  • 一个任务检查引用一个单一的任务
  • 一个任务有很多任务检查
  • 任务检查的任务必须是任务检查的属性检查的属性的任务之一(废话!)

管理员必须能够添加任务和类别;

这确实是一个要求,但它与我们在这里感兴趣的内容无关,因为这是在代码级别(权限)而不是数据库架构级别处理的。

任务属于一类;

一个类别可以有很多任务——一对多的关系,参见上面。

财产检查由一名工作人员进行;

一个工作人员可以做很多财产检查——一对多的关系,参见上面。

任务列表对每个属性都相同;

啊,这个很有意思。 如果这是真的,则意味着您实际上不需要 Task 和 Property 之间的任何关系。

但这仍然是我要与客户仔细检查的事情 - 根据经验,客户在解释域时往往只考虑一般情况,然后当他们开始测试软件时,会突然出现很多极端情况,您突然意识到您将不得不重写一半或更多的架构和代码。 我实际上在我参与的第一个应用程序中遇到了这种情况 - 实际上不是作为开发人员,我只是该应用程序的用户之一,而我必须对应用程序做的第一件事揭示了这些缺点,导致整整一个月的额外开发(雇用我的公司必须支付费用,因为他们签署了 - 错误的 - 要求)。 毋庸置疑,对这一代价高昂的错误负责的人要么受到指责,要么被直接解雇。

每个任务都必须有一个状态(例如:已完成状态);

这个也是错的。 状态属于任务检查,不属于任务。

好的,所以您发布的模型并不太远。 正如我在评论中已经提到的,你有一些一对多的关系是错误的(fk 在关系的错误方面)但是通过上面的解释你应该能够解决这个问题。 您可能还想与客户仔细检查一些规则并相应地调整您的模型。

现在还有一些其他事情:

首先,除非您使用的是遗留数据库(这里显然不是这种情况),否则最好单独保留模型字段db_column属性 - ORM 将使用模型字段的名称作为 db 列名称,这是最重要的通常是最好的默认设置 - 至少当您想要执行原始 SQL 查询时,您不必检查 models.py 文件中的列名。 请注意,对于外键,模型的属性将产生相关的模型实例,但会创建一个“fieldname_id”列。

第二点:如果不需要文本字段或字符字段,请勿使用“null=True”——否则您将有两个可能的值表示“无数据”,SQL“NULL”或空字符串。 最好只有其中之一,在这种情况下是空字符串,因此删除“null=True”并使用“default=''”代替。 此外,对于自由文本(例如“注释”字段),您可能希望使用文本字段而不是字符字段。 这避免了在最大长度上放置无用的ModelForms (您可以打赌用户会要求您扩展),并且还将被 Django 的ModelForms转换为适当的 html“文本”小部件而不是(单行)html“输入” .

第三点:“blank=False”和“null=False”已经是默认值——除非另有说明,否则需要一个字段——所以明确地将它们传递给必填字段只会增加“代码噪音”。 最易读的代码是根本没有代码;-)

希望这可以为您解决问题,如果不能随意在评论中询问详细信息/解释。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM