我可能需要一些帮助来设计我的模型及其关系。
每个标签可以在Book 的多个实例中使用(例如“指环王”和“Discworld”都有“Fantasy”标签)。
每个Aspect可以在Tag 的多个实例中使用(例如“Fantasy”和“Scifi”都具有“World Detail”方面)。
以下是描述性图片:
(哇,这些都很大)
因为我想存储与特定图书相关的每个方面的用户评分。
这是主要问题。我想在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',)
除了模型,我为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()
虽然这应该有用,但我需要额外的逻辑来处理删除的标签。
但真正恼人的是我必须手动添加每本书的方面关系,以便我可以存储用户评级。当然,我对不同书籍的相同方面需要不同的评级。
答案 0 :(得分:2)
我会改变:
class Book(models.Model):
title = models.CharField(max_length=100, unique=True)
tags = ManyToManyField(Tag)
由于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