我正在尝试允许多个模型使用Review
提供的通用关系与django.contrib.contenttypes
模型建立连接。
在Django 1.7中使用django.contrib.contenttypes.fields.GenericRelation
,您可以在related_query_name
上设置GenericRelation
,以便在关系中执行反向查询。 The django docs give this example:
class Bookmark(models.Model):
url = models.URLField()
tags = GenericRelation(TaggedItem, related_query_name='bookmarks')
>>> # Get all tags belonging to books containing `django` in the url
>>> TaggedItem.objects.filter(bookmarks__url__contains='django')
[<TaggedItem: django>, <TaggedItem: python>]
我想创建一个内置于模型中的装饰器,因此我不必为related_query_name='bookmarks'
模型定义Bookmark
。这可以用装饰器完成吗?我在想的是这样的:
# reviews/decorators.py
from django.contrib.contenttypes.fields import GenericRelation
from .models import Review
def reviewable(klass):
# a related attr to the Review model:
klass.reviews = GenericRelation(Review, related_query_name=klass.__name__) # need to access the name of the class being defined here
# some other functions are added to a reviewable model here
return klass
像这样使用装饰器:
# web_store/models.py
from reviews.decorators import related_decorator
from django.db import models
@reviewable
class Product(models.Model):
name = models.CharField(max_length=50)
@reviewable
class Seller(models.Model):
name = models.CharField(max_length=50)
然后我希望能够像上面的django文档中描述的那样进行查询:
>>> from reviews.models import Review
>>> Review.objects.filter(product__name__contains='widget')
[<Review: Blue Widget>, <Review: Red Widget>]
>>> Review.objects.filter(seller__name__contains='inc')
[<Review: We Sell Stuff, Inc>, <Review: Cool Stuff, Inc>]
这里的关键是反向查询取决于related_query_name
。如何访问装饰器中定义的类的名称? klass.__name__
会工作吗?
当我尝试我所描述的内容时,存在一个问题:
>>> Review.objects.filter(product__name__contains='television')
Traceback (most recent call last):
File "<console>", line 1, in <module>
File "/Users/atheiman/programming/python/virtualenvs/simple-django/lib/python2.7/site-packages/django/db/models/manager.py", line 92, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/Users/atheiman/programming/python/virtualenvs/simple-django/lib/python2.7/site-packages/django/db/models/query.py", line 691, in filter
return self._filter_or_exclude(False, *args, **kwargs)
File "/Users/atheiman/programming/python/virtualenvs/simple-django/lib/python2.7/site-packages/django/db/models/query.py", line 709, in _filter_or_exclude
clone.query.add_q(Q(*args, **kwargs))
File "/Users/atheiman/programming/python/virtualenvs/simple-django/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1331, in add_q
clause, require_inner = self._add_q(where_part, self.used_aliases)
File "/Users/atheiman/programming/python/virtualenvs/simple-django/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1358, in _add_q
current_negated=current_negated, connector=connector)
File "/Users/atheiman/programming/python/virtualenvs/simple-django/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1182, in build_filter
lookups, parts, reffed_aggregate = self.solve_lookup_type(arg)
File "/Users/atheiman/programming/python/virtualenvs/simple-django/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1120, in solve_lookup_type
_, field, _, lookup_parts = self.names_to_path(lookup_splitted, self.get_meta())
File "/Users/atheiman/programming/python/virtualenvs/simple-django/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1427, in names_to_path
self.raise_field_error(opts, name)
File "/Users/atheiman/programming/python/virtualenvs/simple-django/lib/python2.7/site-packages/django/db/models/sql/query.py", line 1433, in raise_field_error
"Choices are: %s" % (name, ", ".join(available)))
FieldError: Cannot resolve keyword 'product' into field. Choices are: anonymous, comment, comment_approved, content_type, content_type_id, created, id, object_id, score, updated, user, user_id
此外,当我用装饰器添加它时,GenericRelation
似乎会中断:
>>> product = Product.objects.all()[0]
>>> product.reviews
<django.contrib.contenttypes.fields.GenericRelation>
当我在模型定义中直接添加reviews
关系时,它会创建一个GenericRelatedObjectManager
字段,而不是GenericRelation
字段:
>>> product = Product.objects.all()[0]
>>> product.reviews
<django.contrib.contenttypes.fields.GenericRelatedObjectManager object at 0x104b06bd0>
答案 0 :(得分:0)
在我看来,你应该能够通过模型继承和子类中的related_names的特殊情况来完成你想要的东西,但我在这里有一个免责声明:这是基于在非关系上使用这些东西的经验GenericRelations
。它似乎应该以下列方式工作,但我可能是错的:
例如,你可以像这样定义一些base(或mixin):
class ReviewBase(models.Model):
reviews = GenericRelation(Review, related_query_name="%(class)s")
这是来自related_name="%(class)s"
的猜测,appears in the docs.
有了这个,您应该能够在任何希望评论能够作为属性的模型中继承此Base模型:
class Product(ReivewBase):
name = models.CharField(max_length=50)
同样,我不确定是否有效。它基于一种假设,即您可以将此类行为扩展到GenericRelations
,但我会尝试一下。