自定义查找未在Django中注册

时间:2016-11-13 05:38:50

标签: python django

我已经创建了自定义查找。我将它用于查询,但是,当我这样做时,会抛出错误Related Field got invalid lookup: lcb

我假设这是因为此自定义查找未正确注册。正如您将在下面看到的那样,我已经尝试了几件事情,但我对这个问题感到很遗憾。

这是我的代码:

租户/ views.py

from main.lookups import *

def find_tenants(request, house_id):
    house = HouseListing.objects.get(pk=house_id)
    applications = HousingApplication.objects.filter(date_from__gte=house.available_from)
    applications = applications.filter(pets__lcb=house.allowed_pets.values_list('id', flat=True))

    context = {'house': house, 'applications': applications}
    return render(request, 'landlords/find-tenants.html', context)

主要/ lookups.py

from django.db.models import Lookup, ManyToManyField


# Custom lookups

@ManyToManyField.register_lookup
class ListContainedBy(Lookup):
    lookup_name = 'lcb'

    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

我发现这很奇怪,因为the docs建议在AppConfigmodels.py中注册查找。我尝试了这两件事,但都没有奏效。

回溯

Environment:


Request Method: GET
Request URL: http://127.0.0.1:8000/landlords/find-tenants/5/

Django Version: 1.10.2
Python Version: 2.7.12
Installed Applications:
['main.apps.MainConfig',
 'tenants.apps.TenantsConfig',
 'landlords.apps.LandlordsConfig',
 'django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.humanize',
 'django.contrib.postgres',
 'imagekit']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/core/handlers/exception.py" in inner
  39.             response = get_response(request)

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/core/handlers/base.py" in _legacy_get_response
  249.             response = self._get_response(request)

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  187.                 response = self.process_exception_by_middleware(e, request)

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/core/handlers/base.py" in _get_response
  185.                 response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
  23.                 return view_func(request, *args, **kwargs)

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/contrib/auth/decorators.py" in _wrapped_view
  23.                 return view_func(request, *args, **kwargs)

File "/Users/mightyspaj/Development/Projects/housingfinder/housingfinder/landlords/views.py" in find_tenants
  132.     applications = applications.filter(pets__lcb=house.allowed_pets.values_list('id', flat=True))

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/db/models/query.py" in filter
  796.         return self._filter_or_exclude(False, *args, **kwargs)

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/db/models/query.py" in _filter_or_exclude
  814.             clone.query.add_q(Q(*args, **kwargs))

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/db/models/sql/query.py" in add_q
  1227.         clause, _ = self._add_q(q_object, self.used_aliases)

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/db/models/sql/query.py" in _add_q
  1253.                     allow_joins=allow_joins, split_subq=split_subq,

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/db/models/sql/query.py" in build_filter
  1178.             lookup_class = field.get_lookup(lookups[0])

File "/Users/mightyspaj/Development/Projects/housingfinder/lib/python2.7/site-packages/django/db/models/fields/related.py" in get_lookup
  694.             raise TypeError('Related Field got invalid lookup: %s' % lookup_name)

Exception Type: TypeError at /landlords/find-tenants/5/
Exception Value: Related Field got invalid lookup: lcb

到目前为止我尝试过的所有事情

  1. MainConfig.ready()功能
  2. 中注册查找
  3. find_tenants()视图
  4. 中注册查找
  5. main/models.py
  6. 中注册查询
  7. 将查询注册为Field而不是ManyToManyField
  8. 使用ManyToManyField.register_lookup()而不是装饰器
  9. 注册查找
  10. %s <@ %s更改为%s = %s。我认为问题可能是它认为我的SQL无效

1 个答案:

答案 0 :(得分:2)

编辑2

看起来有些混乱可能会在django的后续版本中进行整理...下面的编辑1是1.10,但代码在提示中有所不同,所以现在可能已经修复了。您可以尝试升级到1.11并查看是否可以修复它。但是,如果不起作用,我在下面列出的选项仍值得一试。

编辑1

我意识到我在最初的答案中误读了异常。实际上,被触发的异常是django.db.models.fields.related.ForeignObject.get_lookup中的异常,并且那里的代码更清楚django不支持关系字段上的自定义查找:

class ForeignObject(RelatedField):

    ...

    def get_lookup(self, lookup_name):
        if lookup_name == 'in':
            return RelatedIn
        elif lookup_name == 'exact':
            return RelatedExact
        elif lookup_name == 'gt':
            return RelatedGreaterThan
        elif lookup_name == 'gte':
            return RelatedGreaterThanOrEqual
        elif lookup_name == 'lt':
            return RelatedLessThan
        elif lookup_name == 'lte':
            return RelatedLessThanOrEqual
        elif lookup_name == 'isnull':
            return RelatedIsNull
        else:
            raise TypeError('Related Field got invalid lookup: %s' % lookup_name)

    ...

是一些事情是你可以尝试让它工作的一件事:

  1. 通过多对多关系在其中一个字段上实现自定义查找,因此您可以查询

    applications = applications.filter(
        pets__id__lcb=house.allowed_pets.values_list('id', flat=True))
    

    我能够使用IN运算符来实现这些方面的工作。

  2. 或者,您可以继承您正在使用的ForeignObject并覆盖get_lookup,以便它不会为您的新运算符抛出异常。毫无疑问,为了让它工作起来,你必须做一些小提琴。 编辑:我试过这个,但它并没有因为它比这更复杂,并且对于连接操作,它是右侧表中使用的Field的隐式字段,因此将Field子类化为左手表还不够。选项1绝对是正确的方法。

  3. 原始答案

    我认为异常告诉你django不会尝试对关系字段使用自定义查找。鉴于你提到它,我猜测petsManyToManyField,即关系字段,所以我猜你的查找已经注册,django只是拒绝使用它。< / p>

    你正在点击(django.db.models.sql.query.Query.build_filter())的django中的代码是:

    ....
    if field.is_relation:
        # No support for transforms for relational fields
        num_lookups = len(lookups)
        if num_lookups > 1:
            raise FieldError('Related Field got invalid lookup: {}'.format(lookups[0]))
    ....
    

    我不能说我完全理解其基本原理,但这肯定会解释为什么你试图用来注册查询的机制得到相同的结果。

    这似乎是一个记录不完整的问题。网上我唯一能找到的东西(搜索时间为10分钟)是this,其他人得出了同样的结论。