【问题标题】:Is there any way to use any user-defined Python method in the Case-When query of Django ORM?有没有办法在 Django ORM 的 Case-When 查询中使用任何用户定义的 Python 方法?
【发布时间】:2020-08-24 15:11:40
【问题描述】:

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

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, decimal_places=8, default=Decimal("0.00"), 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 方法中,我尝试在Case 查询中使用用户定义的 (prepare_location_hotlink) Python 方法来检索作为热链接的所有位置数据。似乎无法以上述方式工作。但无论如何我都需要在Case 查询中使用 user-defined python 方法,因为它检索和准备数据的速度要快得多。我已经研究并阅读了Django 文档,但不幸的是,我找不到任何解决方案。

对于如何在Django ORMCase查询中使用任何用户定义的 Python方法,有什么适当和准确的方法吗?

【问题讨论】:

  • 不,您不能使用 Python 函数,因为数据库不知道这些函数。但是无论如何,在数据库中进行文本处理并不是一个好主意。数据库专门用于存储/接收/聚合数据。没有很好地格式化它。

标签: python django postgresql django-orm


【解决方案1】:

在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,
        decimal_places=8,
        default=Decimal('0.00'),
        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')
        )

【讨论】:

    【解决方案2】:

    您可以使用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'>"), F("latitude"), Value(", "), F("longitude"), Value('</a>'))
            ), default=Value("Not Available"), output_field=CharField()
        )
    }
    return list(cls.objects.annotate(**annotated_case_query).values_list("location", flat=True))
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-04-13
      • 1970-01-01
      • 2019-11-30
      • 2022-12-15
      • 1970-01-01
      • 2021-03-04
      • 2022-12-05
      相关资源
      最近更新 更多