zoukankan      html  css  js  c++  java
  • django LookUp

    Custom Lookups

    一个简单LookUp例子

    Author.objects.filter(name__ne='Jack') 
    # Translate SQL
    "author"."name" <> 'Jack'
    

    自定义

    from django.db.models import Lookup
    from django.db.models.fields import Field
    
    
    @Field.register_lookup
    class NotEqual(Lookup):
        lookup_name = "ne"
    
        def as_sql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return '%s <> %s' % (lhs, rhs), params
    
    Field.register_lookup(NotEqual)  # 注册 或者使用 @Field.register_lookup装饰器
    

    一个简单的Transform例子

    from django.db.models import Transform
    
    class AbsoluteValue(Transform):
        lookup_name = 'abs'
        function = 'ABS'
    
    from django.db.models import IntegerField  # 只应用在数字字段
    IntegerField.register_lookup(AbsoluteValue)
    

    Experiment.objects.filter(change__abs=27)
    # generate SQL
    SELECT ... WHERE ABS("experiments"."change") = 27
    
    
    Experiment.objects.filter(change__abs__lt=27)
    # generate SQL
    SELECT ... WHERE ABS("experiments"."change") < 27
    
    
    Experiment.objects.order_by('change__abs')
    # generate SQL
    SELECT ... ORDER BY ABS("experiments"."change") ASC
    

    output_filed

    rom django.db.models import FloatField, Transform
    
    class AbsoluteValue(Transform):
        lookup_name = 'abs'
        function = 'ABS'
    
        @property
        def output_field(self):
            return FloatField()
    

    Writing an efficient abs_lt lookup

    在使用上述编写的abs查找时,在某些情况下生成的SQL不会有效地使用索引。特别是,当我们使用change__abs__lt=27时,这就相当于change__gt=-27和change__lt=27。(对于lte,我们可以使用SQL BETWEEN)。

    因此,我们想要用experimental .objects.filter(change__abs__lt=27)来生成以下SQL:

    SELECT .. WHERE "experiments"."change" < 27 AND "experiments"."change" > -27
    

    The implementation is:
    
    from django.db.models import Lookup
    
    class AbsoluteValueLessThan(Lookup):
        lookup_name = 'lt'
    
        def as_sql(self, compiler, connection):
            lhs, lhs_params = compiler.compile(self.lhs.lhs)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params + lhs_params + rhs_params
            return '%s < %s AND %s > -%s' % (lhs, rhs, lhs, rhs), params
    
    AbsoluteValue.register_lookup(AbsoluteValueLessThan)
    

    A bilateral transformer example

    我们前面讨论的AbsoluteValue示例是一个应用于查找左边的转换。在某些情况下,你可能想把变换应用到左边和右边。例如,如果您想根据左边和右边的等式对某个SQL函数不敏感地过滤一个queryset。

    from django.db.models import Transform
    
    class UpperCase(Transform):
        lookup_name = 'upper'
        function = 'UPPER'
        bilateral = True
    

    from django.db.models import CharField, TextField
    CharField.register_lookup(UpperCase)
    TextField.register_lookup(UpperCase)
    

    Author.objects.filter(name__upper="doe")
    # generate SQL
    SELECT ... WHERE UPPER("author"."name") = UPPER('doe')
    

    Writing alternative implementations for existing lookups

    有时,不同的数据库供应商对相同的操作需要不同的SQL。对于本例,我们将为NotEqual操作符重写MySQL的自定义实现。我们将使用!=操作符,而不是<>。(请注意,实际上几乎所有数据库都支持这两种方法,包括Django支持的所有官方数据库)。
    我们可以通过使用as_mysql方法创建NotEqual的子类来更改特定后端上的行为

    class MySQLNotEqual(NotEqual):
        def as_mysql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return '%s != %s' % (lhs, rhs), params
    
    Field.register_lookup(MySQLNotEqual)
    

    然后我们可以将它注册到Field。它取代了原来的NotEqual类,因为它具有相同的lookup_name。
    在编译查询时,Django首先查找as_%s %连接。然后返回到as_sql。内置后端的厂商名称是sqlite、postgresql、oracle和mysql。

    How Django determines the lookups and transforms which are used

    在某些情况下,您可能希望根据传入的名称动态更改返回的转换或查找,而不是修复它。例如,您可以有一个存储坐标或任意维度的字段,并希望允许像.filter(coords__x7=4)这样的语法返回第7个坐标值为4的对象。为了做到这一点,您可以使用类似的方法重写get_lookup

    class CoordinatesField(Field):
        def get_lookup(self, lookup_name):
            if lookup_name.startswith('x'):
                try:
                    dimension = int(lookup_name[1:])
                except ValueError:
                    pass
                else:
                    return get_coordinate_lookup(dimension)
            return super().get_lookup(lookup_name)
    

    查找顺序:

    如果匹配上Lookup,查找Lookup,如果没匹配上,查找Transform,在从Truansform查找LookUp。

  • 相关阅读:
    oracle的常见问题与解决
    final、finally、finalize的区别
    java中读取程序运行时间
    数据库设计与SQL优化的建议
    Eclipse 快捷键操作和常用设置
    OO设计原则
    structs常用的Action
    java的深复制与浅复制
    python进制(十进制,八进制,十六进制)
    linux的shell基础
  • 原文地址:https://www.cnblogs.com/LTEF/p/9736806.html
Copyright © 2011-2022 走看看