通过多个循环和逻辑将代码简化为查询集聚合

时间:2019-04-30 14:21:31

标签: python django django-models django-queryset

我的模特:

class customer(models.Model):
    cstid = models.AutoField(primary_key=True, unique=True)
    insurance_number = models.CharField(max_length=100, blank=True, null=True)
    name = models.CharField(max_length=35)
    ageyrs = models.IntegerField(blank=True)

class Admission(models.Model):
    id = models.AutoField(primary_key=True, unique=True)
    clinic = models.ForeignKey(Clinic, on_delete=models.CASCADE)
    customer = models.ForeignKey(customer, on_delete=models.CASCADE)
    diagnosis = models.CharField(max_length=2000, default='', blank=True)
    date_admission = models.DateTimeField(default=timezone.now)
    ward = models.ForeignKey(Ward, on_delete=models.CASCADE)
    bed = models.ForeignKey(Bed, on_delete=models.CASCADE)
    discharged = models.BooleanField(default=False)
    ip_number = models.IntegerField(blank=True)
    ip_prefix = models.CharField(max_length=20, default='', blank=True)

我的目标:为查询过滤器设置一个变量,在查询集中添加一个属性“ is_admitted”,以便我可以将此查询集传递给模板并在显示数据时使用该属性。

代码:

def is_admitted(cust):
    admission = Admission.objects.filter(customer=cust, discharged=False)
    admission_results = len(admission)
    if admission_results > 0:
        return True
    return False


my_q = or_q_if_truthfull(
    cstid=HospitalID,
    name__lower__contains=name.lower() if name else None,
    ageyrs=ageyrs if ageyrs.isdigit() else None,
    agemnths=agemnths if agemnths.isdigit() else None,
    mobile__contains=mobile if mobile else None,
    alternate__contains=alternate if alternate else None,
    email__lower__contains=email.lower() if email else None,
    address__lower__contains=address.lower() if address else None,
    city__lower__contains=city.lower() if city else None
)
ORSearchResult = customer.objects.filter(my_q, linkedclinic=clinicobj)
cust_set = []
cust_admission_status = []
for cust in ORSearchResult:
    cust_set.append(cust)
    cust_admission_status.append(is_admitted(cust))
    print(f"Customer name: {cust.name} Admission status: {is_admitted(cust)}")
cust_templ_set = zip(cust_set, cust_admission_status)

在模板中,我将这样做:

{% for cust, status in cust_templ_set %}
    {{ cust.name }} {{ status }}
{% endfor %}

我想了解如何通过在查询集上生成汇总来转换上述代码,以便可以使用查询的属性,并将模板代码更改为以下代码,并避免视图中的循环,和拉链。这样模板代码变为:

{% for cust in customers %}
    {{ cust.name }} {{ cust.is_admitted }}
{% endfor %}   

我不确定我是否完全有道理,可以进一步解释。

2 个答案:

答案 0 :(得分:2)

我不确定我是否理解正确,也许您会想要这样:

mediaItem = movie
print("type of mediaItem:\(type(of: mediaItem))") //type of mediaItem:Movie

这将返回带有附加字段cust = customer.objects.filter(my_q, linkedclinic=clinicobj) is_admitted_sub_q = Admission.objects.filter(customer=OuterRef('pk'), discharged=False) cust_templ_set = cust.annotate(is_admitted=Exists(is_admitted_sub_q), ) 的客户列表,如果is_admitted中至少有一个(与此客户相关的)链接记录,则该字段为True

OuterRefExists

答案 1 :(得分:1)

一种选择是将conditional-expressionsannotate()一起使用。看起来可能像这样:

from django.db import models

qs = Customer.objects.filter(...)    # your filter conditions go here

# now add a field to the resulting queryset
qs = qs.annotate(
    active_admissions=models.Count(
        models.Case(
            models.When(admission__discharged=False, then=1),
            output_field=models.IntegerField())))

现在,查询集中的每个对象将具有一个名为active_admissions的附加属性,其中将包含活动许可的数量。 可以在这样的模板中使用它:

{% for cust in qs %}
    {{ cust.name }} {{ cust.active_admissions }}
{% endfor %}  

也许您需要修改子查询以适合您的特定需求。有帮助吗?