如何在Django查询中过滤外键对象?

时间:2019-04-12 07:57:57

标签: django django-models one-to-many django-orm

我有两个模型,一个像这样foreign key彼此关联

class CapturedPrescriptionModel(ColModel):
    p_id = models.IntegerField()
    p_age = models.IntegerField()
    p_gender = models.CharField(max_length=10)
    p_care_type = models.CharField(max_length=100)
    bacteria_id = models.ForeignKey(BacteriaListModel, 
              on_delete=models.CASCADE, null=True)

class SuggestedAntibioticsModel(ColModel):
    prescription_id = models.ForeignKey(CapturedPrescriptionModel, 
                  related_name='antibiotics', 
                   on_delete=models.CASCADE)
    cat_ids = models.TextField()
    flag = models.IntegerField(default=0)

现在我想要所有prescriptionssuggested antibiotics,其中flag=1

我尝试过使用CapturedPrescriptionModel.objects.filter(antibiotics__flag=1),但是它过滤的是处方而不是查询集中的抗生素列表。

 [
    {
    "id": 7,
    "p_id": 0,
    "p_age": 19,
    "p_gender": "Male",
    "p_care_type": "ICU",
    "bacteria_id": null,
    "antibiotics": [
        {
            "id": 188,
            "cat_ids": "[]",
            "flag": 0,
            "antibiotic_id_id": 87,
            "prescription_id_id": 7
        },
        {
            "id": 187,
            "cat_ids": "[]",
            "flag": 1,
            "antibiotic_id_id": 112,
            "prescription_id_id": 7
        },
      ......
      ]
}
....
]

我的预期结果将是这样

    [
        {
        "id": 7,
        "p_id": 0,
        "p_age": 19,
        "p_gender": "Male",
        "p_care_type": "ICU",
        "bacteria_id": null,
        "antibiotics": [
            {
                "id": 187,
                "cat_ids": "[]",
                "flag": 1,
                "antibiotic_id_id": 112,
                "prescription_id_id": 7
            }
          ]
}
....
]

2 个答案:

答案 0 :(得分:3)

如果只想过滤相关对象而不是主要对象,则需要过滤的Prefetch

from django.db.models import Prefetch

CapturedPrescriptionModel.objects.prefetch_related(Prefetch(
    'antibiotics',
    queryset=SuggestedAntibioticsModel.objects.filter(flag=1)
)

然后,您必须确保仅使用antibiotics访问单个处方对象上的prescription.antibiotics.all(),否则将不使用预取操作,并且您将再次获得所有抗生素。

答案 1 :(得分:0)

收集所有处方:

prescriptions = CapturedPrescriptionModel.objects.all()

for prescription in prescriptions:
    prescription.antibiotics = prescription.antibiotics.filter(flag=1)

# at this time presciptions should be prepared, just make sure to not save them...

您还可以扩展模型以具有该列表的属性。

class CapturedPrescriptionModel(ColModel):
    p_id = models.IntegerField()
    p_age = models.IntegerField()
    p_gender = models.CharField(max_length=10)
    p_care_type = models.CharField(max_length=100)
    bacteria_id = models.ForeignKey(BacteriaListModel, 
              on_delete=models.CASCADE, null=True)

    @property
    def flagged_antibiotics(self):
        try:
            return self.antibiotics.filter(flag=1)
        except Exception:
            return []

class SuggestedAntibioticsModel(ColModel):
    prescription_id = models.ForeignKey(CapturedPrescriptionModel, 
                  related_name='antibiotics', 
                   on_delete=models.CASCADE)
    cat_ids = models.TextField()
    flag = models.IntegerField(default=0)

类似的事情将是我的第一个尝试