rol*_*one 6 django django-models django-queryset
我的Django应用程序中有以下模型:
class Book(models.Model):
name = models.CharField(max_length=100)
keywords = models.ManyToManyField('Keyword')
class Keyword(models.Model)
name = models.CharField(max_length=100)
Run Code Online (Sandbox Code Playgroud)
我已经保存了以下关键字:
science-fiction
fiction
history
science
astronomy
Run Code Online (Sandbox Code Playgroud)
在我的网站上,用户可以通过访问按关键字过滤书籍/keyword-slug/.keyword_slug变量传递给我的视图中的函数,该函数按关键字过滤Books,如下所示:
def get_books_by_keyword(keyword_slug):
books = Book.objects.all()
keywords = keyword_slug.split('-')
for k in keywords:
books = books.filter(keywords__name__icontains=k)
Run Code Online (Sandbox Code Playgroud)
这在大多数情况下都有效,但每当我使用包含在关键字表中出现多次的字符串的关键字(例如science-fiction和fiction)进行过滤时,我会在生成的QuerySet中多次出现相同的书.
我知道我可以添加distinct只返回独特的书籍,但我想知道为什么我会开始重复,并且真的想要了解为什么它的工作方式.由于我只调用filter()成功过滤的QuerySet,因此如何将重复的书添加到结果中?
2个车型在你的例子中表示3个表:book,keyword和book_keyword关系表来管理M2M领域。
当您keywords__name在过滤器调用中使用Django时,它将使用SQL JOIN合并所有3个表。这使您可以通过另一个表中的值来过滤第一个表中的对象。
SQL将如下所示:
SELECT `book`.`id`,
`book`.`name`
FROM `book`
INNER JOIN `book_keyword` ON (`book`.`id` = `book_keyword`.`book_id`)
INNER JOIN `keyword` ON (`book_keyword`.`keyword_id` = `keyword`.`id`)
WHERE (`keyword`.`name` LIKE %fiction%)
Run Code Online (Sandbox Code Playgroud)
加入后,您的数据看起来像
| Book Table | Relation table | Keyword table |
|---------------------|------------------------------------|------------------------------|
| Book ID | Book name | relation_book_id | relation_key_id | Keyword ID | Keyword name |
|---------|-----------|------------------|-----------------|------------|-----------------|
| 1 | Book 1 | 1 | 1 | 1 | Science-fiction |
| 1 | Book 1 | 1 | 2 | 2 | Fiction |
| 2 | Book 2 | 2 | 2 | 2 | Fiction |
Run Code Online (Sandbox Code Playgroud)
然后,当数据从DB加载到Python中时,您只会从book表中接收数据。如您所见,Book 1在此处重复
这就是多对多关系和JOIN的工作方式
| 归档时间: |
|
| 查看次数: |
2230 次 |
| 最近记录: |