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。

  • 相关阅读:
    1046 Shortest Distance (20 分)(模拟)
    1004. Counting Leaves (30)PAT甲级真题(bfs,dfs,树的遍历,层序遍历)
    1041 Be Unique (20 分)(hash散列)
    1036 Boys vs Girls (25 分)(查找元素)
    1035 Password (20 分)(字符串处理)
    1044 Shopping in Mars (25 分)(二分查找)
    onenote使用小Tip总结^_^(不断更新中...)
    1048 Find Coins (25 分)(hash)
    三个故事
    领导者的举止
  • 原文地址:https://www.cnblogs.com/LTEF/p/9736806.html
Copyright © 2011-2022 走看看