在Django ORM的Case-When查询中,可以使用任何用户定义的Python方法吗?

问题描述

我已经定义了一个类及其必要的方法,如下所示。

class Location(models.Model):
    latitude = models.DecimalField(max_digits=20,decimal_places=8,default=Decimal("0.00"),null=True)
    longitude = models.DecimalField(max_digits=20,null=True)

    @staticmethod
    def prepare_location_hotlink(latitude=None,longitude=None):
        returm mark_safe(s="<a class='inline-link' href='https://maps.google.com/maps?z=17&q={lat},{lng}' target='_blank'>{lat},{lng}</a>".format(lat=latitude,lng=longitude))

    @classmethod
    def retrieve_location_data(cls):
        annotated_case_query = {
            "location": Case(
                When(Q(location__isnull=False,longitude__isnull=False),then=cls.prepare_location_hotlink(latitude=F("latitude"),longitude=F("longitude"))
                ),default=Value("Not Available"),output_field=CharField()
            )
        }
        return [loc for loc in cls.objects.annotate(**annotated_case_query).values_list("location",flat=True)]

这里,在retrieve_location_data方法中,我尝试在prepare_location_hotlink查询中使用用户定义的Case)Python方法来检索所有位置数据已热链接。似乎无法以上述方式工作。但是无论如何,我仍然需要在Case查询中使用 user-defined python方法,因为它可以更快地检索和准备数据。我已经研究并阅读了Django文档,但不幸的是,对于这种情况我找不到任何解决方案。

Case的{​​{1}}查询中,如何使用任何用户定义的 Python方法有正确且准确的方法吗?

解决方法

在Django ORM的Case查询中,如何使用任何用户定义的Python方法有正确而准确的方法吗?

,因为数据库对Django一无所知。它只是一个解释查询以存储/检索/聚合数据的程序。但是,无论如何,让数据库进行复杂的处理并不是一个好主意。数据库不是为此设计的。

您只需在列表理解中执行操作即可:

from itertools import starmap

class Location(models.Model):
    latitude = models.DecimalField(
        max_digits=20,decimal_places=8,default=Decimal('0.00'),null=True
    )
    longitude = models.DecimalField(
        max_digits=20,null=True
    )

    @staticmethod
    def prepare_location_hotlink(long=None,lat=None):
        if long is None and lat is None:
            return 'Not Available'
        return mark_safe(f"<a class='inline-link' href='https://maps.google.com/maps?z=17&q={lat},{lng}' target='_blank'>{lat},{lng}</a>")

    @classmethod
    def retrieve_location_data(cls):
        return list(starmap(
            Location.prepare_location_hotlink,
            cls.objects.values_list('longitude','latitude')
        )
,

您可以使用Concat函数在数据库级别连接字符串,但是,在这种情况下,我会选择@Willem Van Onsem答案,该答案更易于阅读和维护。

您还可以使用list()将您的查询集包装成一个列表。

from django.db.models import Q,Case,When,Value,F
from django.db.models.functions import Concat

annotated_case_query = {
    "location": Case(
        When(Q(location__isnull=False,longitude__isnull=False),then=Concat(Value("<a class='inline-link' href='https://maps.google.com/maps?z=17&q="),F("latitude"),Value(","),F("longitude"),Value("' target='_blank'>"),Value('</a>'))
        ),default=Value("Not Available"),output_field=CharField()
    )
}
return list(cls.objects.annotate(**annotated_case_query).values_list("location",flat=True))