Django中具有多个多对多关系的数据库建模

Alp*_*Alp 6 python django many-to-many django-signals django-models

我可能需要一些帮助来设计我的模型及其关系.

简短概述

  • :书名(例如"指环王")
  • 标签:与书籍相关的标签(例如"幻想","巫师","史诗般的战斗")
  • 方面:与标签相关的方面,或者换句话说,用户在特定标签出现时可以评价的事物,例如:
    • 对于标签"幻想"方面可能是"世界细节"和"时间"
    • 对于标签"史诗般的战斗"方面可能是"戈尔水平"和"战斗紧张"

每个标签可用于Book的多个实例(例如"指环王"和"Discworld"都有"Fantasy"标签).

每个Aspect可以在Tag的多个实例中使用(例如"Fantasy"和"Scifi"都具有"World Detail"方面).

这是一个描述性图像:

在此输入图像描述

(哇,这些都很大)

"为什么你需要额外的桌面BookAspect?" 你可能会问?

因为我想存储与特定书籍相关的每个方面的用户评级.

这是主要问题.我想在Django中对此进行建模,这是我到目前为止所得到的:

class Book(models.Model):
    title = models.CharField(max_length=100, unique=True)
    tags = ManyToManyField(Tag)
    # the following line is a workaround...
    aspects = models.ManyToManyField(Aspect, through='BookAspect')

class Tag(models.Model):
    name = models.CharField(max_length=100)
    aspects = models.ManyToManyField(Aspect)

class Aspect(models.Model):
    name = models.CharField(max_length=100)

# this class is a workaround ...
class BookAspect(models.Model):
    book = models.ForeignKey(Book)
    aspect = models.ForeignKey(Aspect)
    # this is from django-ratings
    rating = RatingField(range=5, can_change_vote=True, allow_delete=True, blank=True)

    class Meta:
        unique_together = ('book', 'aspect',)
Run Code Online (Sandbox Code Playgroud)

除了模型,我创建了一个m2m_changed信号监听器action="post_add":

@receiver(m2m_changed, sender=Book.tags.through)
def m2m_changed_book(sender, instance, action, reverse, pk_set, **kwargs):
    if action is not 'post_add' or reverse:
        return

    # iterate through all newly created tags to manually add
    # the aspects from each tag to the BookAspect table
    for tag_id in pk_set:
        aspects = Tag.objects.get(pk=tag_id).aspects.all()
        # this is annoying, i have to manually set the relations...
        for aspect in aspects:
            bookAspect = BookAspect(book=instance, aspect=aspect)
            bookAspect.save()
Run Code Online (Sandbox Code Playgroud)

虽然这应该工作,我需要额外的逻辑来处理删除的标签.

但真正恼人的是我必须手动添加每书的方面关系,以便我可以存储用户评级.当然,我对不同书籍的相同方面需要不同的评级.

问题

1.这是正确的做法,我是否遗漏了某些东西,或者我认为不是那么复杂吗?

2.是否可以"自动化"Book-Aspect关系,以便我不必手动更新关系?

3.我如何在Django中建模?

Ste*_*e K 2

  • 我认为可以更简单地完成。
  • 我认为,在某种程度上。
  • 我会改变:

    class Book(models.Model):
      title = models.CharField(max_length=100, unique=True)
      tags = ManyToManyField(Tag)
    
    Run Code Online (Sandbox Code Playgroud)

由于该aspects领域与该领域无关Book

我不知道你为什么写BookAspect。关于用户评分,您可以这样做:

class BookRating(models.Model):
  book = models.ForeignKey(Book)
  aspect = models.ForeignKey(Aspect)
  rating = models.RatingField()
  # Method to rate a book and check the aspect belong to one of the book's tags
  def rate(book, aspect):
    # check the aspect is related to a tag which is also related to the book
    # if so, save a new rating entry
  # You can also override the save() method to check the aspect is valid for the book
Run Code Online (Sandbox Code Playgroud)