15

クエリをランダム化する必要があるカスタム マネージャーを作成しました。

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であるため、それぞれ my manager と method はありません。 チェーン クエリでカスタム マネージャーを使用する方法はありますか?

4

5 に答える 5

29

これは、カスタム マネージャーでカスタム メソッドをチェーンする方法です。つまり、 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を確認してください

于 2012-11-17T19:47:42.210 に答える
13

新しい 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() は本当に素晴らしいです:)

于 2015-08-07T09:03:55.790 に答える
13

このスニペットがあなたの状況に解決策を提供しているようです: Custom managers with chainable filters

于 2011-09-18T11:32:44.527 に答える
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

于 2013-06-17T20:08:09.457 に答える