簡體   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