python - 自定义查找未在 Django 中注册

标签 python django

我已经创建了一个自定义查找。我正在使用它进行查询,但是,当我这样做时,错误 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)

ma​​in/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

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

  1. MainConfig.ready() 中注册查找功能
  2. find_tenants() 中注册查找查看
  3. main/models.py 中注册查询
  4. 将查找注册为 Field而不是 ManyToManyField
  5. 使用 ManyToManyField.register_lookup() 注册查找而不是装饰器
  6. 正在更改 %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)

    ...

有几件事是您可以尝试让它工作的一件事:

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

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

    我能够使用 IN 运算符按照这些思路进行工作。

  2. 或者,您可以子类化您正在使用的 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/

相关文章:

python - 将列与 NULL 值相乘

python - 我可以从 Django 模板访问字典中的特定键值吗?

django - "Best"有条件地显示Django模板中不同模型字段的值的方法?

python - Django模板中根据用户选择不同的样式表

python - django 1.6.5 + python3 wsgi 问题

django - 使用 Django rest-framework-jwt 撤销 token

python - 在Python中使简单的绘图变得平滑

python - 如何将模型操作传递给 Tkinter MVC 中的查看按钮?

django - 在 manage.py shell 中自动导入所有 db 表

python - pyodbc 到 Sage ERP MAS 200 驱动程序错误