簡體   English   中英

將多個值存儲到mysql數據庫的單個字段中,以保留Django中的順序

[英]Storing multiple values into a single field in mysql database that preserve order in Django

我一直在嘗試構建通常在網站上看到的Tutorial系統。 就像我們單擊next -> next -> previous等閱讀的內容一樣。

所有帖子都存儲在名為Post的表(模型)中。 基本上就像一個發布對象池。

Post.objects.all()將返回所有帖子。

現在還有一個名為Tutorial Table(模型),它將存儲以下內容,

class Tutorial(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    tutorial_heading = models.CharField(max_length=100)
    tutorial_summary = models.CharField(max_length=300)

    series = models.CharField(max_length=40) # <---- Here [10,11,12] 
    ...

在這里,此series字段中的條目是作為列表的字符串表示形式存儲的post_id。

例如:series將具有[10,11,12] ,其中10、11和12是post_id,分別對應於Post表中的相應條目。

因此,我針對Tutorial模型的表條目如下所示。

id       heading                   summary                      series

"5"     "Series 3 Tutorial"    "lorem on ullt consequat."    "[12, 13, 14]"

因此,我只是閱讀了series字段,並獲得了此列表中所有具有ids的帖子,然后在Django中使用pagination顯示它們。

現在 ,我從幾個stackoverflow帖子中了解到,在一個字段中包含多個條目是一個壞主意。 使這種關系跨越多個表作為映射是一個更好的選擇。

我想要擁有的功能是可以在我想要的任何地方向該系列插入新帖子。 也許在前面或中間。 通過將此系列作為列表並按我的意願插入,可以輕松實現。 更改"[14,12,13]"將對正在顯示的帖子進行重新排序。

我的問題是,這種在我的用例中在字段中存儲多個值的方法可以嗎? 還是會影響性能,或者通常是一個壞主意。 如果沒有,那么我可以通過使用另一個表擴展關系來保留或更改順序,或者在Django或MYSQL中有一種更好的方法來完成此操作。

在這里,此系列字段中的條目是作為列表的字符串表示形式存儲的post_id。 (...)因此,我只是閱讀了series字段,並獲得了此列表中所有具有ID的帖子,然后在Django中使用分頁顯示它們。

不要這樣做!

您正在使用關系數據庫。 在關系數據庫中的實體之間建立關系的一種正確方法是使用外鍵。 在您的情況下,根據帖子是只屬於一個教程(“一對多”關系)還是同時屬於多個教程(“多對多”關系),您要么希望要么發布一個教程上的外鍵,或者在帖子和教程上使用帶有外鍵的中間“ post_tutorials”表。

您的解決方案不允許數據庫正常工作。 它不能強制執行完整性約束(如果要刪除教程引用的帖子怎么辦?),不能優化讀取訪問權限(使用正確的模式,數據庫可以在單個查詢中檢索教程及其所有帖子),不能遵循反向關系(給出一個帖子,訪問它所屬的教程)等。並且它需要一個外部程序(python代碼)來與您的數據進行交互,而使用適當的建模則只需要標准SQL。

最后-但這是特定於Django的-使用適當的架構與admin功能以及django rest框架(如果您打算構建rest API)一起使用時效果更好。

wrt /排序問題,這是一個長期存在(已解決)的問題,您只需要添加一個“ order”字段(小int就足夠了)。 有幾個第3部分django應用程序為您的模型和管理員添加了對此功能的支持,因此幾乎可以即插即用。

IOW,絕對沒有充分的理由以這種方式對您的模式進行規范化,只有充分的理由才能使用適當的關系建模。 FWIW,我曾經不得不基於一個晦澀(希望已死的很久)的PHP cms進行一個項目,這個cms具有使用“序列化列表”反模式的絕妙想法,我可以告訴你,這既是災難,也是性能和一個完整的噩夢要維持。 因此,對自己和整個世界都有利:不要嘗試發揮創造力,而是遵循眾所周知的既定最佳做法,您的生活會更加幸福。 我的2分錢

我可以想到兩種方法:

方法一:鏈表

一種方法是使用像這樣的鏈表:

class Tutorial(models.Model):
    ...
    previous = models.OneToOneField('self', null=True, blank=True, related_name="next")

通過這種方法,您可以像這樣訪問該系列的上一篇文章:

for tutorial in Tutorial.objects.filter(previous__isnull=True):
   print(tutorial)
   while(tutorial.next_post):
      print(tutorial.next)
      tutorial = tutorial.next

這是一種復雜的方法,例如,每當您要在鏈表中間添加新教程時,都需要在兩個位置進行更改。 喜歡:

post = Tutorial.object.first()
next_post = post.next
new = Tutorial.objects.create(...)
post.next=new
post.save()
new.next = next_post
new.save()

但是這種方法有很大的好處,您不必為創建系列而創建新表。 另外,教程中的順序可能不會經常修改,這意味着您不必太麻煩。

方法二:創建新模型

您可以簡單地創建一個新模型並將FK轉換為Tutorial,如下所示:

class Series(models.Model):
    name = models.CharField(max_length=255)


class Tutorial(models.Model):
   ..
   series = models.ForeignKey(Series, null=True, blank=True, related_name='tutorials')
   order = models.IntegerField(default=0)


   class Meta:
      unique_together=('series', 'order')  # it will make sure that duplicate order for same series does not happen

然后,您可以通過以下方式訪問系列教程:

series = Series.object.first()
series.tutorials.all().order_by('tutorials__order')

這種方法的優點是它可以更靈活地訪問系列教程,但是為此會創建一個額外的表,以及一個額外的字段來維護順序。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM