【问题标题】:Many-to-Many Database design with Django使用 Django 进行多对多数据库设计
【发布时间】:2016-12-01 20:00:20
【问题描述】:

通常一种药物可以有很多“昵称”,这会让人感到困惑。所以,我正在尝试构建一个小型 Django 应用程序来帮助我解决这个问题。

它应该做的是将药物的实际名称(non_proprietary_name)引用到它的“昵称”(proprietary_name),反之亦然。

例如,“阿司匹林”和“ASS”是“乙酰水杨酸”的专有名称。

为了更复杂一点,我决定添加一个小的 Wiki 页面和类别(此外,一种药物可以分为许多不同的类别)。

遗憾的是,我对数据库设计不是很熟悉,所以我需要一些帮助。

到目前为止我得到了什么:

from django.db import models

# Create your models here.

class Proprietary_name(models.Model):
    proprietary_name = models.CharField(max_length = 100, unique = True) #nick name

    def __str__(self):
        return self.proprietary_name

class Category(models.Model):
    category = models.CharField(max_length = 100, unique = True)

    def __str__(self):
        return self.category

class Mediwiki(models.Model):
    proprietary_name = models.ManyToManyField(Proprietary_name)
    non_proprietary_name = models.CharField(max_length = 100, unique = True) # actual name
    category = models.ManyToManyField(Category)
    wiki_page = models.TextField()

    def __str__(self):
        return self.non_proprietary_name

~

所以,如果我有专有名称,我可以关联到非专有名称:

>>> Mediwiki.objects.get(proprietary_name__proprietary_name='Aspirin')
<Mediwiki: acetylsalicylic acid>

但是,当我输入专有名称时,我无法获取所有非专有名称。这是我的数据库的问题还是我错过了其他东西?

编辑:

基于 cmets 的新 models.py:

from django.db import models

# Create your models here.

class Category(models.Model):
    category = models.CharField(max_length = 100, unique = True)

    def __str__(self):
        return self.category

class Mediwiki(models.Model):
    non_proprietary_name = models.CharField(max_length = 100, unique = True)
    category = models.ManyToManyField(Category)
    wiki_page = models.TextField()

    def __str__(self):
        return self.non_proprietary_name

class ProprietaryName(models.Model):
    proprietary_name = models.CharField(max_length = 100, unique = True)
    non_proprietary_name = models.ForeignKey(Mediwiki)

    def __str__(self):
        return self.proprietary_name

所以,它有效!但我不太确定为什么..这是最好的方法吗?另外,类别呢?它们也应该更改为外键吗?

>>> Mediwiki.objects.get(proprietaryname__proprietary_name="Aspirin")
<Mediwiki: acetylsalicylic acid>
>>>

>>> ProprietaryName.objects.get(proprietary_name="Aspirin").non_proprietary_name
<Mediwiki: acetylsalicylic acid> # Works also, what's preferable? 

>>>ProprietaryName.objects.filter(non_proprietary_name__non_proprietary_name="acetylsalicylic acid")
        [<ProprietaryName: Aspirin>, <ProprietaryName: ASS>]
        >>>

【问题讨论】:

    标签: python django database database-design


    【解决方案1】:

    可以有许多专有名称,但不能将相同的专有名称分配给一种以上的非专有(通用)药物,因此您需要将关系从多对多更改为一对多( nb. 在类名中使用 CamelCase,而不是下划线):

    class Mediwiki(models.Model):
        non_proprietary_name = models.CharField(max_length = 100, unique = True) # actual name
        category = models.ManyToManyField(Category)
        wiki_page = models.TextField()
    
    class ProprietaryName(models.Model):
        proprietary_name = models.CharField(max_length = 100, unique = True) #nick name
        non_proprietary_name = models.ForeignKey(Mediawiki)
    

    然后您可以使用Mediawikiproprietaryname_set 属性和ProprietaryNamemediawiki 属性为其他查找获取所有非专利名称的专利药物。更多信息请关注documentation

    【讨论】:

    • 再次感谢您的回复!编辑了原始问题,这是您的想法吗?另外,类别呢?是否也应该更改为外键?
    • 是的,这就是想法,至于category - 它应该保持多对多,因为一种药物可以分为许多类别,一个类别将包含许多药物。
    【解决方案2】:

    首先,您的型号名称Mediwiki 并不简单,因为每个条目都只是记录有关Drug 的所有信息。因此,只需将其更改为 Drug 会更有意义。

    在您当前的设计中,您使用的是 m2m 字段,这表明一个 proprietary_name 可以用于多种药物。如果您希望在输入proprietary_name 时返回所有Drug non_proprietary_names,只需执行以下操作:

    Drug.objects.filter(proprietary_name__proprietary_name='Aspirin') \
                .values_list('non_proprietary_name', flat=True).distinct()
    

    查看关于values_list的django文档。

    但是,如果一个proprietary_name 只能描述一种药物,则应在模型Proprietary_name 上将Drug 作为外键以指示一对多关系:

    class Proprietary_name(models.Model):
        proprietary_name = models.CharField(max_length=100, unique=True)
        drug = models.ForeignKey(Drug)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-17
      • 2012-09-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-16
      • 1970-01-01
      相关资源
      最近更新 更多