我制作了一个自定义管理器,必须随机化我的查询:
class RandomManager(models.Manager):
def randomize(self):
count = self.aggregate(count=Count('id'))['count']
random_index = random.randint(0, count - 1)
return self.all()[random_index]
当我首先使用我的经理中定义的方法时,它可以正常工作:
>>> PostPages.random_objects.randomize()
>>> <PostPages: post 3>
我需要随机化已经过滤的查询。当我尝试使用管理器和链中的方法时出现错误:
PostPages.random_objects.filter(image_gallary__isnull=False).randomize()
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
/home/i159/workspace/shivaroot/shivablog/<ipython-input-9-98f654c77896> in <module>()
----> 1 PostPages.random_objects.filter(image_gallary__isnull=False).randomize()
AttributeError: 'QuerySet' object has no attribute 'randomize'
过滤结果不是模型类的实例,而是django.db.models.query.QuerySet
,因此它分别没有我的经理和方法。
有没有办法在链式查询中使用自定义管理器?
答案 0 :(得分:27)
这是您在自定义管理器上链接自定义方法的方式,即:Post.objects.by_author(user = request.user).published()
from django.db.models.query import QuerySet
class PostMixin(object):
def by_author(self, user):
return self.filter(user=user)
def published(self):
return self.filter(published__lte=datetime.now())
class PostQuerySet(QuerySet, PostMixin):
pass
class PostManager(models.Manager, PostMixin):
def get_query_set(self):
return PostQuerySet(self.model, using=self._db)
此处链接:django-custom-model-manager-chaining
在Django 1.7中你可以开箱即用。查看QuerySet.as_manager
答案 1 :(得分:12)
看起来此代码段为您的情况提供了解决方案:Custom managers with chainable filters。
答案 2 :(得分:10)
使用新的as_manager()方法的代码示例(请参阅@zzart的更新信息。
class MyQuerySet(models.query.QuerySet):
def randomize(self):
count = self.aggregate(count=Count('id'))['count']
random_index = random.randint(0, count - 1)
return self.all()[random_index]
class MyModel(models.Model):
.....
.....
objects = MyQuerySet.as_manager()
.....
.....
然后你就可以在你的代码中使用这样的东西了:
MyModel.objects.filter(age__gt=16).randomize()
如您所见,新的as_manager()非常简洁:)
答案 3 :(得分:0)
如下所示,动态创建自定义QuerySet,并允许我们将自定义查询“移植”到返回的QuerySet实例上:
class OfferManager(models.Manager):
"""
Additional methods / constants to Offer's objects manager
"""
### Model (db table) wide constants - we put these and
### not in model definition to avoid circular imports.
### One can access these constants through like
<foo>.objects.STATUS_DISABLED or ImageManager.STATUS_DISABLED
STATUS_DISABLED = 0
...
STATUS_CHOICES = (
(STATUS_DISABLED, "Disabled"),
(STATUS_ENABLED, "Enabled"),
(STATUS_NEGOTIATED, "Negotiated"),
(STATUS_ARCHIVED, "Archived"),
)
...
# we keep status and filters naming a little different as
# it is not one-to-one mapping in all situations
QUERYSET_PUBLIC_KWARGS = {'status__gte': STATUS_ENABLED}
QUERYSET_ACTIVE_KWARGS = {'status': STATUS_ENABLED}
def get_query_set(self):
""" our customized method which transpalats manager methods
as per get_query_set.<method_name> = <method> definitions """
CustomizedQuerySet = QuerySet
for name, function in self.get_query_set.__dict__.items():
setattr(CustomizedQuerySet, name, function)
return CustomizedQuerySet(self.model, using=self._db)
def public(self):
""" Returns all entries accessible through front end site"""
return self.all().filter(**OfferManager.QUERYSET_PUBLIC_KWARGS)
get_query_set.public = public # will tranplat the function onto the
# returned QuerySet instance which
# means 'self' changes depending on context.
def active(self):
""" returns offers that are open to negotiation """
return self.public().filter(**OfferManager.QUERYSET_ACTIVE_KWARGS)
get_query_set.active = active
...
此方法和django票的更精美版本:https://code.djangoproject.com/ticket/20625。
答案 4 :(得分:0)
鉴于您已有models.Manager
并且您不希望将某些管理器方法公开给可链接的查询集,您可以使用Manager.from_queryset(QuerySet)()
。
因此,您仍然可以将所有可链接的查询集方法独立地放在QuerySet和管理器方法中。
官方网站提供的示例。
来自Django Docs的片段
class BaseManager(models.Manager):
# Available only on Manager.
def manager_only_method(self):
return
class CustomQuerySet(models.QuerySet):
# Available on both Manager and QuerySet.
def manager_and_queryset_method(self):
return
# Available only on QuerySet.
def _private_method(self):
return
CustomManager = BaseManager.from_queryset(CustomQuerySet)
class MyModel(models.Model):
objects = CustomManager()