如何将自定义管理器与相关对象一起使用?

发布于 2024-12-05 20:22:56 字数 1641 浏览 3 评论 0 原文

我有一个定制经理。我想将它用于相关对象。我在文档中找到了 use_for_lated_fields 。但它不像我使用它的方式工作:

class RandomQueryset(models.query.QuerySet):

    def randomize(self):       
        count = self.count()
        random_index = random.randint(0, count - 1)
        return self.all()[random_index]


class RandomManager(models.Manager):

    use_for_related_fields = True

    def get_query_set(self):
        return RandomQueryset(self.model, using=self._db)

    def randomize(self):
        return self.get_query_set().randomize()

我将它用于一个模型:

>>> post = PostPages.default_manager.filter(image_gallery__isnull=False).distinct().randomize()

并尝试对 m2m 相关对象执行相同的操作:

>>> post.image_gallery.randomize()

遇到错误:

AttributeError: 'ManyRelatedManager' object has no attribute 'randomize'

是否可以按照我的方式使用自定义管理器?如果是这样,你如何让它发挥作用?

编辑

我的模型:

class ShivaImage(models.Model, ImageResizing):
    image = models.ImageField(upload_to='img')
    slide_show = models.BooleanField() 
    title = models.CharField(max_length=100)
    text = models.TextField(max_length=400)
    ordering = models.IntegerField(blank=True, null=True)

    objects = RandomManager()


class PostPages(models.Model):
    image_gallery = models.ManyToManyField(ShivaImage, blank=True,
                                       related_name='gallery',)
    # all the other fields... 

    objects = RandomManager()

I have a custom manager. I want to use it for related objects. I found use_for_related_fields in docs. But it does not work the way I used it:

class RandomQueryset(models.query.QuerySet):

    def randomize(self):       
        count = self.count()
        random_index = random.randint(0, count - 1)
        return self.all()[random_index]


class RandomManager(models.Manager):

    use_for_related_fields = True

    def get_query_set(self):
        return RandomQueryset(self.model, using=self._db)

    def randomize(self):
        return self.get_query_set().randomize()

I used it for one model:

>>> post = PostPages.default_manager.filter(image_gallery__isnull=False).distinct().randomize()

And tried to do the same with m2m related object:

>>> post.image_gallery.randomize()

Got an error:

AttributeError: 'ManyRelatedManager' object has no attribute 'randomize'

Is it possible to use a custom manager in the way I did it? If so, how do you make it work?

Edit

My models:

class ShivaImage(models.Model, ImageResizing):
    image = models.ImageField(upload_to='img')
    slide_show = models.BooleanField() 
    title = models.CharField(max_length=100)
    text = models.TextField(max_length=400)
    ordering = models.IntegerField(blank=True, null=True)

    objects = RandomManager()


class PostPages(models.Model):
    image_gallery = models.ManyToManyField(ShivaImage, blank=True,
                                       related_name='gallery',)
    # all the other fields... 

    objects = RandomManager()

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

情丝乱 2024-12-12 20:22:56

为了主题的完整性,Django 1.7(最终)支持 使用自定义反向管理器,这样你就可以做类似的事情(只需从 django 文档复制):

from django.db import models

class Entry(models.Model):
    objects = models.Manager()  # Default Manager
    entries = EntryManager()    # Custom Manager

b = Blog.objects.get(id=1)
b.entry_set(manager='entries').all()

For completeness of the topic, Django 1.7 (finally) supports using a custom reverse manager, so you can do something like that (just copying from the django docs):

from django.db import models

class Entry(models.Model):
    objects = models.Manager()  # Default Manager
    entries = EntryManager()    # Custom Manager

b = Blog.objects.get(id=1)
b.entry_set(manager='entries').all()
季末如歌 2024-12-12 20:22:56

仅建议 Django 1.09 或更早版本 - 文档证明

设置管理器上的 use_for_lated_fieldsTrue 将使其在指向您将此管理器定义为默认管理器的模型的所有关系上可用。这是记录在这里

class MyManager(models.Manager):
    use_for_related_fields = True
    # ...

我想你已经有了它仅在您的 PostPages 模型上启用,而不是在您的 Gallery 模型(或通过 post_image_gallery 引用的任何模型名称)上启用。如果您想在此领域管理器上拥有额外的功能,您需要将 use_for_lated_fields = True 添加到您的 Gallery 模型中!

THIS IS ONLY SUGGESTED FOR Django 1.09 or older - Docs proof

Setting use_for_related_fields to True on the manager will make it available on all relations that point to the model on which you defined this manager as the default manager. This is documented here

class MyManager(models.Manager):
    use_for_related_fields = True
    # ...

I suppose you have it only enabled on your PostPages model, not on your Gallery model (or whatever the model is called that is referenced through post_image_gallery). If you want to have additionally functionality on this realtion manager you need to add a custom default manager with use_for_related_fields = True to your Gallery model!

愿得七秒忆 2024-12-12 20:22:56

在 django 2.0 中 use_for_lated_fields 已弃用 https://docs.djangoproject.com/en/2.0/releases/1.10/#manager-use-for-lated-fields-and-inheritance-changes

您应该使用 基本经理名称https://docs.djangoproject.com/ en/2.0/ref/models/options/#django.db.models.Options.base_manager_name

更新的文档:https://docs.djangoproject。 com/en/2.0/topics/db/managers/#using-managers-for-lated-object-access

class MyModel(models.Model):
    field1 = ...
    field2 = ...
    special_manager = MyManager()

    class Meta:
        base_manager_name = 'special_manager'

In django 2.0 use_for_related_fields is deprecated https://docs.djangoproject.com/en/2.0/releases/1.10/#manager-use-for-related-fields-and-inheritance-changes

You should use base_manager_name: https://docs.djangoproject.com/en/2.0/ref/models/options/#django.db.models.Options.base_manager_name

Updated docs: https://docs.djangoproject.com/en/2.0/topics/db/managers/#using-managers-for-related-object-access

class MyModel(models.Model):
    field1 = ...
    field2 = ...
    special_manager = MyManager()

    class Meta:
        base_manager_name = 'special_manager'
漫雪独思 2024-12-12 20:22:56

另外,在自定义管理器中,确保通过 self.get_query_set() 访问查询集
实现从相关管理器调用的自定义过滤器时的代理方法:

class EventManager(models.Manager):

    use_for_related_fields = True

    def visible_events(self):
        today = datetime.date.today()
        # don't do this !!! 
        # unsuitable for related managers as could retrieve extraneous objects
        # qs = super(EventManager, self).get_query_set()
        # Use queryset proxy method as follows, instead:
        qs = self.get_query_set()
        qs = qs.filter(visible_from__lte=today, visible_to__gte=today)
        return qs


class Event(models.Model):

    visible_from = models.DateField(_(u'visible from'), null=False, blank=False)
    visible_to = models.DateField(_(u'visible to'), null=False, blank=False)
    concepts = models.ManyToManyField(Concept, through='ConceptEventRegistration')

    objects = EventManager()

示例用法:

my_concept = Concept.objects.get(id=1)
# retrieve all events related to the object
my_concept.event_set.all()
# retrieve all visible events related to the object
my_concept.event_set.visible_events()

Also, in the custom manager, make sure to access the queryset via the self.get_query_set()
proxy method when implementing custom filters to be called from related manager:

class EventManager(models.Manager):

    use_for_related_fields = True

    def visible_events(self):
        today = datetime.date.today()
        # don't do this !!! 
        # unsuitable for related managers as could retrieve extraneous objects
        # qs = super(EventManager, self).get_query_set()
        # Use queryset proxy method as follows, instead:
        qs = self.get_query_set()
        qs = qs.filter(visible_from__lte=today, visible_to__gte=today)
        return qs


class Event(models.Model):

    visible_from = models.DateField(_(u'visible from'), null=False, blank=False)
    visible_to = models.DateField(_(u'visible to'), null=False, blank=False)
    concepts = models.ManyToManyField(Concept, through='ConceptEventRegistration')

    objects = EventManager()

Sample usage:

my_concept = Concept.objects.get(id=1)
# retrieve all events related to the object
my_concept.event_set.all()
# retrieve all visible events related to the object
my_concept.event_set.visible_events()
初心未许 2024-12-12 20:22:56

对于 Django 4 和 5,它有点不同:

class SubscriptionQuerySet(models.QuerySet):
    def recent_trial_subscriptions(self, duration_type):
        return self.filter(
            duration_type=duration_type,  # Whatever filters you fancy here
            date_end__isnull=True,
            created_at__gt=datetime.now() - relativedelta(years=1)). \
            order_by('-created_at')


class SubscriptionManager(models.Manager):
    def get_queryset(self):
        return SubscriptionQuerySet(self.model, using=self._db)

    def get_recent_trial_subscriptions(self, duration_type):
        return self.get_queryset().recent_trial_subscriptions(duration_type)


class Subscription(AbstractModel):
    class Meta:
        ordering = ('-created_at',)

    objects = SubscriptionManager()

    user = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=True, related_name='subscriptions')

    ...

然后你可以像这样使用它:

request.user.subscriptions.get_recent_trial_subscriptions(duration_type)

请参阅 django 文档

For Django 4 and 5 it's a bit different:

class SubscriptionQuerySet(models.QuerySet):
    def recent_trial_subscriptions(self, duration_type):
        return self.filter(
            duration_type=duration_type,  # Whatever filters you fancy here
            date_end__isnull=True,
            created_at__gt=datetime.now() - relativedelta(years=1)). \
            order_by('-created_at')


class SubscriptionManager(models.Manager):
    def get_queryset(self):
        return SubscriptionQuerySet(self.model, using=self._db)

    def get_recent_trial_subscriptions(self, duration_type):
        return self.get_queryset().recent_trial_subscriptions(duration_type)


class Subscription(AbstractModel):
    class Meta:
        ordering = ('-created_at',)

    objects = SubscriptionManager()

    user = models.ForeignKey(User, on_delete=models.DO_NOTHING, null=True, related_name='subscriptions')

    ...

and then you can use it like this:

request.user.subscriptions.get_recent_trial_subscriptions(duration_type)

See django documentation

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文