django通过orm外键关联查询,导出原生sql执行,mysql两表中重复字段被覆盖问题

如何实现mysql语句效果 : “SELECT field as x…” with Django ORM 参考地址

场景描述

最近因业务需求,这边需要做一个数据导出,需要用到两张表的数据来满足,A表和B表,属于一对多的数据关系,因此首先想到的就是django orm 的外键关联查询,借助django-restfuldjango-filter的强大组合,轻松实现这个组合查询。数据量的问题,考虑到耗时,采用celery来异步完成数据处理,所以就借助django orm的功能,获取映射的原生sql,将sql传入tasks任务中,让数据库执行和导出放在task下来处理。

一切按照计划进行,期间还是遇到一些问题。

class B(models.Model):
    id = models.AutoField(db_column='f_id', primary_key=True)
    email = models.CharField(db_column='f_email', max_length=32, default='', help_text=u'邮箱')
    address = models.CharField(db_column='f_address', max_length=32, default='', help_text=u'地址')

class A(models.Model):
    id = models.AutoField(db_column='f_id', primary_key=True)
    name = models.CharField(db_column='f_name', max_length=32, default='', help_text=u'姓名')
    b= models.ForeignKey(B, db_column='f_email', to_field='email', db_constraint=False, help_text=u'邮箱')
from django_filters import rest_framework as filters
class AListFilter(filters.FilterSet):
    """请款记录"""
    address = filters.CharFilter(name='b__address')

    class Meta:
        model = A
        fields = ('address',)

问题:

A与B两表在orm中未使用外键关系ForeignKey标记

虽然在数据库中有关联两表的唯一字段,但是并不是一个无意义的唯一id值,而是我们的业务单号,若添加外键,影响到原表的该字段存储方式。这里采用了继承,将业务单号字段单独抽取,其余的公共字段置为一个抽象model下,这样,采用继承,一个子类保持原名称和业务号字段不变,另一个采用ForeignKey。外键关联的字段需要是唯一的,默认指定为关联model的主键id,这里通过to_field指定为需要关联的唯一字段。这样就可以使用orm的关联查询,通过select_related来正向关联查询。

django-filter 如何接受关联表的参数筛选

在我们定义的AListFilter中,address字段的指定查询为b__address,即可自动关联执行查询。

获取orm映射sql

原因为简单的通过A.objects.all().query就可以获取到sql语句,这里其实拿到的是一个Query对象,需要通过str()获取其sql字符串,一切都是很顺利,但是在运行时,查询报错了,原来是这样拼接出来的sql对于传参的占位符%s未使用引号包裹,导致报错参数类型不是整形。通过对Query类查询,发现__str__魔法方法是将sql和变量拼接得到的,sql, params = A.objects.all().query.sql_with_params()其中的sql占位符确实没有引号,MySQL-python的执行函数,支持对占位sql和参数传入,会自动处理这个%s占位符的问题。

映射sql中两表字段名一样的字段,在执行结束后获取的值被后面的覆盖

对于A和B中的字段名一样问题,django的聚合函数annotate可以实现将sql指定别名,A.objects.all().annotate(other_name=F('name')),这样,就可以避免字段名一样被覆盖的问题。

你可能感兴趣的:(django通过orm外键关联查询,导出原生sql执行,mysql两表中重复字段被覆盖问题)