Django查询相关模型

时间:2017-12-08 10:29:06

标签: mysql django

我有以下模型

class Scheduler(models.Model):  
    id = <this is primary key>
    last_run = <referencing to id in RunLogs below>  

class RunLogs(models.Model):  
    id = <primary key>  
    scheduler = <referencing to id in Scheduler above>
    overall_status = <String>

仅当scheduler达到作业的预定时间时,才会创建RunLogs条目。

现在我在RunLogs上查询以显示如下的运行时间表。

current = RunLog.objects\
                     .filter(Q(overall_status__in = ("RUNNING", "ON-HOLD", "QUEUED") |
                             Q(scheduler__last_run__isnull = True))  

以上查询为我提供了RunLogs匹配状态的所有记录,但未向Scheduler提供last_run is null的记录。

我理解为什么查询的行为如此,但有没有办法从scheduler获取last_run is null的记录 ?

1 个答案:

答案 0 :(得分:1)

我刚刚执行了您所遵循的相同步骤,并找到了运行查询后获取所有记录的原因。以下是确切的步骤和解决方案。

步骤

  1. 创建模型

    from django.db import models
    
    class ResourceLog(models.Model):
        id = models.BigIntegerField(primary_key=True)
        resource_mgmt = models.ForeignKey('ResourceMgmt', on_delete=models.DO_NOTHING,
                                          related_name='cpe_log_resource_mgmt')
        overall_status = models.CharField(max_length=8, blank=True, null=True)
    
    
    class ResourceMgmt(models.Model):
        id = models.BigIntegerField(primary_key=True)
        last_run = models.ForeignKey(ResourceLog, on_delete=models.DO_NOTHING, blank=True, null=True)
    
  2. 添加如下数据:

    resource_log

    +----+----------------+------------------+
    | id | overall_status | resource_mgmt_id |
    +----+----------------+------------------+
    |  1 | RUNNING        |                1 |
    |  2 | QUEUED         |                1 |
    |  3 | QUEUED         |                1 |
    +----+----------------+------------------+
    

    resource_mgmt

    +----+-------------+
    | id | last_run_id |
    +----+-------------+
    |  1 |        NULL |
    |  2 |        NULL |
    |  3 |        NULL |
    |  4 |           3 |
    +----+-------------+
    
    •   

      根据上面的表,resource_mgmt(4)指的是resource_log(3)。但值得注意的是,resource_log(3)并未引用resource_mgmt(4)。

  3. 在python shell中运行以下命令

    In [1]: resource_log1 = ResourceLog.objects.get(id=1)
    
    In [2]: resource_log.resource_mgmt
    Out[2]: <ResourceMgmt: ResourceMgmt object (1)>
    In [3]: resource_log1 = ResourceLog.objects.get(id=2)
    
    In [4]: resource_log.resource_mgmt
    Out[4]: <ResourceMgmt: ResourceMgmt object (1)
    In [5]: resource_log1 = ResourceLog.objects.get(id=3)
    
    In [6]: resource_log.resource_mgmt
    Out[6]: <ResourceMgmt: ResourceMgmt object (1)>
    

    从中我们可以理解所有resource_log对象都引用了resource_mgmt的第一个对象(即id = 1)。

    问)为什么所有对象都引用了resource_mgmt中的第一个对象?

    •   

      resource_mgmt是非空的外键字段。创建resource_log对象时,其默认值为1.如果未指定resource_mgmt,则会在此处添加默认值1。

  4. 运行查询

    In [60]: ResourceLog.objects.filter(resource_mgmt__last_run__isnull = True)
    Out[60]: <QuerySet [<ResourceLog: ResourceLog object (1)>, <ResourceLog: ResourceLog object (2)>, <ResourceLog: ResourceLog object (3)>]>
    
    •   

      此查询返回所有三个ResourceLog对象,因为这三个对象都引用了第一个resource_mgmt对象,其is_null值为True

  5. 解决方案

    你实际上想检查反向关系。

    我们可以使用两个查询来实现这一目标:

    rm_ids = ResourceMgmt.objects.exclude(last_run=None).values_list('last_run', flat=True)
    current = ResourceLog.objects.filter(overall_status__in = ("RUNNING", "QUEUED")).exclude(id__in=rm)
    

    输出结果为:

    <QuerySet [<ResourceLog: ResourceLog object (1)>, <ResourceLog: ResourceLog object (2)>]>
    

    希望有所帮助!