Django 模型 - 如何将多对多相关对象聚合到数组中?

问题描述 投票:0回答:1

所以我最近开始使用 Django,我遇到了书籍和作者之间多对多关系的情况 - 作为一个简单的例子 - 一本书可以有多个作者。

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField('Author', related_name='books')

    def __str__(self):
        return self.title

class Author(models.Model):
    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name

我的目标是获取 Book 的数据,但问题是当一本书有多个作者时,我为每个作者获得相同的书行,问题是 我可以有一个书行,其所有作者都存储在一个列表 ?而不是每个作者占一行

以 JSON 形式获取数据的示例:

[
    {
        "id": 1,
        "title": "Good Omens",
        "authors__name": "Neil Gaiman"
    },
    {
        "id": 1,
        "title": "Good Omens",
        "authors__name": "Terry Pratchett"
    },
    {
        "id": 2,
        "title": "The Lord of the Rings",
        "authors__name": "J.R.R. Tolkien"
    }
]

所以我想要这样的东西:

    {
        "id": 1,
        "title": "Good Omens",
        "authors__name": ["Neil Gaiman", "Terry Pratchett"]
    },

虽然通过 python 代码实现这一点很容易,但我想要一个使用模型查询或 ORM 方法的解决方案,以获得一些性能和时间,因为数据会很大。

以下代码显示了一个负责获取数据并进行一些排序和过滤的方法,所有这些都使用查询:

def __model_query(self, model_class, fields=None, enum_fields=None, order_by=None, search=None, field_search=None):
        queryset = model_class.objects.all()

        # Apply ordering if specified
        if order_by:
            field_name, sort_order = order_by
            if sort_order == "desc":
                queryset = queryset.order_by(f"-{field_name}")
            elif sort_order == "asc":
                queryset = queryset.order_by(field_name)

        # Apply general search if specified
        if search:
            search_filters = Q()
            for field in fields:
                search_filters |= Q(**{f"{field}__icontains": search})
            
            queryset = queryset.filter(search_filters)

        # Apply field-specific search if specified
        if field_search:
            search_filters = Q()
            for field, value in field_search.items():
                if enum_fields and field in enum_fields:
                    search_filters |= Q(**{f"{field}__exact": value})
                else:
                    search_filters |= Q(**{f"{field}__icontains": value})
            
            queryset = queryset.filter(search_filters)

        return queryset

我目前使用的是sqlite3 db,所以我无法使用与Postgres db相关的任何方法。

我真的很感谢能够帮助我的人,我希望我提供了所需的所有详细信息。

我没有尝试太多解决方案,只是ChatGPT提供的解决方案,但都失败了。

django django-models many-to-many aggregate django-orm
1个回答
0
投票

您正在使用不支持

ArrayAgg
的db.sqlite3,因此您可以使用如下方式达到预期结果:enter image description here

    books = Book.objects.values('id', 'title', 'authors__name')

    book_dict = {}
    for book in books:
        book_id = book['id']
        if book_id not in book_dict:
            book_dict[book_id] = {
                'id': book_id,
                'title': book['title'],
                'authors__name': []
            }
        if book['authors__name']:
            book_dict[book_id]['authors__name'].append(book['authors__name'])

    books_list = list(book_dict.values())
© www.soinside.com 2019 - 2024. All rights reserved.