我已经创建了一个自定义查找。我正在使用它进行查询,但是,当我这样做时,错误 Related Field got invalid lookup: lcb
被抛出。
我假设这是因为没有正确注册此自定义查找。正如您将在下面看到的,我已经尝试了几件事,但我不知道问题出在哪里。
这是我的代码:
tenants/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)
main/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建议在 AppConfig
中注册查找,或在 models.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
到目前为止我尝试过的所有事情
- 在
MainConfig.ready()
中注册查找功能 - 在
find_tenants()
中注册查找查看 - 在
main/models.py
中注册查询 - 将查找注册为
Field
而不是ManyToManyField
- 使用
ManyToManyField.register_lookup()
注册查找而不是装饰器 - 正在更改
%s <@ %s
至%s = %s
.我认为问题可能是它认为我的 SQL 无效
最佳答案
编辑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)
...
有几件事是您可以尝试让它工作的一件事:
通过多对多关系在其中一个字段上实现自定义查找,因此您会有如下查询
applications = applications.filter( pets__id__lcb=house.allowed_pets.values_list('id', flat=True))
我能够使用
IN
运算符按照这些思路进行工作。或者,您可以子类化您正在使用的编辑: 我试过了,但没有成功工作,因为它比这更复杂,并且对于连接操作,它是来自右侧表的隐式字段,即使用的ForeignObject
并覆盖get_lookup
,这样它就不会为您的新运算符...毫无疑问,您必须做一些小事才能使其正常工作。Field
,因此将Field
子类化为左侧手头不够用。选项 1 似乎绝对是正确的方法。
原始答案
我相信异常是在告诉您 django 不会尝试对关系字段使用自定义查找。鉴于你提到它,我猜 pets
是一个 ManyToManyField
,即一个关系字段,所以我猜你的查找已经注册,django 只是拒绝使用它。
您正在点击的 django 中的代码位(在 django.db.models.sql.query.Query.build_filter()
中)是:
....
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 ,其他人得出了相同的结论。
关于python - 自定义查找未在 Django 中注册,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40570943/