【问题标题】:DRF - filter across 2 modelsDRF - 过滤 2 个模型
【发布时间】:2016-02-23 17:25:01
【问题描述】:

我正在使用一个遗留数据库,我在表 A 上设置了一个序列化程序,就像这样 -

class TblapplicationsSerializer(serializers.ModelSerializer):

    class Meta:
        model = Tblapplications
        fields = ('applicationid', 'applicationname', 'description', 'drtierid', 'saglink', 'supportinstructions',
                  'defaultincidentpriorityid', 'applicationorigintypeid', 'installationtypeid', 'comments',
                  'lastmodifieddate', 'lastmodifiedby', 'assetstatusid', 'recordownerid', 'adl_app')
        depth = 2

我正在使用标准过滤器 -

class TblapplicationsFilter(django_filters.FilterSet):
    name = django_filters.CharFilter(name="applicationname", lookup_type="exact")
    env = django_filters.CharFilter(name="adl_app__environmentid__domain")

    class Meta:
        model = Tblapplications
        fields = ['applicationname', 'name', 'env']

这里是横向的。我想要做的是过滤我的 URL,比如/api/applications/?name=xxx&env=DEV。然后它将返回与 DEV 环境链接的应用程序和任何数据库。这个名字很容易理解,但我唯一想到的环境是让应用程序的 api 点接触链接两者的中间表,但它返回多个值,因为每次使用单独的数据库引用应用程序时它都会抓取。

我已经根据给定的 cmets 和序列化器更新了序列化器和过滤器,但 &env=DEV 没有返回所有适当的数据(domain 嵌套在反向关系中)。然后我希望我的过滤器基于此过滤结果。这意味着它需要以某种方式知道将反向关系的结果限制为仅从嵌套值提供的结果。

如果你看到我的模型 -

class Tblapplicationdatabaselinks(models.Model):
    id = models.AutoField(db_column='ID', primary_key=True)
    applicationid = models.ForeignKey('Tblapplications', db_column='applicationId', to_field='applicationid',
                                      related_name='adl_app')
    dbid = models.ForeignKey('Tbldatabases', db_column='dbId', to_field='id', related_name='adl_db')
    environmentid = models.ForeignKey('Tbldomaincodes', db_column='environmentId', to_field='id',
                                      related_name='adl_envlink')
    comments = models.TextField(blank=True)
    lastmodifieddate = models.DateTimeField(db_column='lastModifiedDate', blank=True, null=True)
    lastmodifiedby = models.CharField(db_column='lastModifiedBy', max_length=255, blank=True)
#    upsize_ts = models.TextField(blank=True) # This field type is a guess.

    class Meta:
        managed = False
        db_table = 'tblApplicationDatabaseLinks'

class Tblapplications(models.Model):
    applicationid = models.AutoField(db_column='applicationId', primary_key=True)
    applicationname = models.CharField(db_column='applicationName', max_length=255)
    description = models.TextField(blank=True)
    drtierid = models.ForeignKey(Tbldomaincodes, db_column='drTierID', blank=True, null=True, to_field='id',
                                 related_name='app_drtier')
    saglink = models.TextField(db_column='sagLink', blank=True)
    supportinstructions = models.TextField(db_column='supportInstructions', blank=True)
    defaultincidentpriorityid = models.IntegerField(db_column='defaultIncidentPriorityId', blank=True, null=True)
    applicationorigintypeid = models.IntegerField(db_column='applicationOriginTypeId')
    installationtypeid = models.ForeignKey(Tbldomaincodes, db_column='installationTypeId', to_field='id',
                                           related_name='app_insttype')
    comments = models.TextField(blank=True)
    assetstatusid = models.ForeignKey(Tbldomaincodes, db_column='assetStatusId', to_field='id',
                                      related_name='app_status')
    recordownerid = models.ForeignKey(Tblusergroups, db_column='recordOwnerId', blank=True, null=True,
                                      to_field='groupid', related_name='app_owner')
    lastmodifieddate = models.DateTimeField(db_column='lastModifiedDate', blank=True, null=True)
    lastmodifiedby = models.CharField(db_column='lastModifiedBy', max_length=255, blank=True)
#    upsize_ts = models.TextField(blank=True) # This field type is a guess.

    class Meta:
        managed = False
        db_table = 'tblApplications'

class Tbldatabases(models.Model):
    dbid = models.AutoField(db_column='dbId', primary_key=True)
    dbname = models.CharField(db_column='dbName', max_length=255)
    serverid = models.ForeignKey('Tblservers', db_column='serverId', to_field='serverid', related_name='db_serv')
    servicename = models.CharField(db_column='serviceName', max_length=255, blank=True)
    dbtypeid = models.IntegerField(db_column='dbTypeId', blank=True, null=True)
    inceptiondate = models.DateTimeField(db_column='inceptionDate', blank=True, null=True)
    comments = models.TextField(blank=True)
    assetstatusid = models.IntegerField(db_column='assetStatusId')
    recordownerid = models.IntegerField(db_column='recordOwnerId', blank=True, null=True)
    lastmodifieddate = models.DateTimeField(db_column='lastModifiedDate', blank=True, null=True)
    lastmodifiedby = models.CharField(db_column='lastModifiedBy', max_length=255, blank=True)
#    upsize_ts = models.TextField(blank=True) # This field type is a guess.

    class Meta:
        managed = False
        db_table = 'tblDatabases'

class Tbldomaincodes(models.Model):
    id = models.IntegerField(db_column='ID', primary_key=True)
    domain = models.CharField(primary_key=True, max_length=255)
    displayname = models.CharField(db_column='displayName', primary_key=True, max_length=255)
    displayorder = models.IntegerField(db_column='displayOrder', blank=True, null=True)
    comments = models.TextField(blank=True)
    lastmodifieddate = models.DateTimeField(db_column='lastModifiedDate', blank=True, null=True)
    lastmodifiedby = models.CharField(db_column='lastModifiedBy', max_length=255, blank=True)
#    upsize_ts = models.TextField(blank=True) # This field type is a guess.

    class Meta:
        managed = False
        db_table = 'tblDomainCodes'

【问题讨论】:

    标签: python django django-rest-framework django-filter


    【解决方案1】:

    扩展您的过滤器集并引用其他模型中的字段:

    class TblapplicationsFilter(django_filters.FilterSet):
        name = django_filters.CharFilter(name="applicationname", lookup_type="exact")
        env = django_filters.CharFilter(name="environmentid__name")
        #                                    ^^^^^^^^^^^^^^^^^^^
    
        class Meta:
            model = Tblapplications
            fields = ['applicationname', 'name', 'env']
    

    此外,您可能希望在命名 ForeignKey 字段时不使用 id 后缀,这是 Django 约定。在 Django 中,当你访问 Tblapplications.environmentid 时,它通常是一个模型实例,而不是实际的 id 整数本身。

    【讨论】:

    • 谢谢。不幸的是,我正在使用旧数据库,因此不更改字段名称。也就是说,我已经尝试过了,但不幸的是,因为映射来自反向关系,它不起作用,而是返回它找不到字段environmentid。我将其更改为adl_app__environmentid__name,这不会出错,但它什么也不返回。
    • 要调试正在发生的事情,请使用this answer 将所有 SQL 查询记录到控制台。您可以使用python manage.py shell 以交互方式调试关系,导入您的模型,然后在查看打印的 SQL 到控制台时进行过滤,例如 foo_model.objects.filter(adl_app__environmentid__name='bar')
    • 至于更改遗留数据库列的名称,这只是 Django 可见的事情。我与一个 horrific 遗留数据库合作,它的名字是我见过的最糟糕的名字。我将它们重命名为 new_name = models.CharField(db_column='crappy_name') 并且我能够建立反向关系。关键部分是db_column 参数。
    • 无论如何,使用控制台日志记录交互式 shell,您将能够计算出 CharFiltername 参数的名称应该是什么。
    • 非常感谢!现在绝对没有考虑在 django 中重命名字段。至于返回意识到再次查看数据库是displayname,它具有环境。问题是现在它正在返回所有内容。我想我需要重新考虑这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 2021-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多