django多表合并查询并能分页

一、背景

当前需求: 做一个小功能,要查询用户的所有订阅的信息,包括所订阅的应用和资源,而且要能分页查。

数据库设计: 但是用户订阅数据是放在两张表中,应用订阅表和资源订阅表。单表可以分页查询,但多表分页查询之前是在java中,使用sql语句用过。在django中还没试过。

解决方案:

  1. 通过sql查询
  2. 创建一个视图
  3. 使用union方法

对比了三个方案,union方案最简单,而且符合django项目设计,所以就选了union方法来实现这个小需求。之所以不选择方案一,是因为我们的项目中,基本不使用原生sql语句。方案二不可行,是因为我们使用的数据库是mysql,使用视图不方便。

二、代码实现

1. 数据库模型
class Application(BaseModel):
    """应用"""
    # 省略其他字段...
    subscribed_users = models.ManyToManyField('User', through='ApplicationSubscription', related_name='subscribed_apps')
    class Meta:
        verbose_name = "应用"


class ApplicationSubscription(BaseModel):
    """应用订阅"""

    user = models.ForeignKey("User", on_delete=models.CASCADE, db_constraint=False)
    application = models.ForeignKey("Application", on_delete=models.CASCADE, db_constraint=False)
    class Meta:
        verbose_name = "应用订阅"


class CheckObject(BaseModel):
    # 省略其他字段...
    subscribed_users = models.ManyToManyField('User', through='CheckObjectSubscription',
                                              related_name='subscribed_checkobjs')
    class Meta:
        verbose_name = "巡检对象"
        
class CheckObjectSubscription(BaseModel):
    """对象订阅"""
    user = models.ForeignKey("User", on_delete=models.CASCADE, db_constraint=False)
    check_object = models.ForeignKey("CheckObject", on_delete=models.CASCADE, db_constraint=False)

    class Meta:
        unique_together = (("user", "check_object"),)
        verbose_name = "对象订阅"
2.union方法的代码实现

query_set的union方法其实对应的就是数据库中的union操作。使用union操作,要有一个前提条件,就是两个query_set的字段名必须一致

    def search_user_subscribe(self, request):
        """查询用户订阅的应用和对象"""
        username = request.user.username
        user_obj = User.objects.filter(account=username).first()
        if not user_obj:
            return Response({"detail": "用户不存在,请重新登录"}, status=500)
        app_obj = user_obj.subscribed_apps.all().order_by().annotate(
            type=Value('a', output_field=CharField(max_length=1)),
            key=F('bk_application_key'),
            name=F('bk_application_name'),
            class_key=Value('', output_field=CharField(max_length=1))
        )
        app_obj = app_obj.values("id", "type", "key", "name", "class_key")
        check_obj = user_obj.subscribed_checkobjs.all().order_by().annotate(
            type=Value('c', output_field=CharField(max_length=1)),
            key=F('bk_object_key'),
            name=F('bk_object_name'),
            class_key=F("bk_object_classification_key")
        )
        check_obj = check_obj.values("id", "type", "key", "name", "class_key")
        subscribe_obj = app_obj.union(check_obj)
        subscribe_obj = subscribe_obj.order_by("type", "name")

        page = self.paginate_queryset(subscribe_obj)
        if page is not None:
            page_data = self.get_paginated_response(page)
            return Response(page_data.data)
        return Response(page)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值