【问题标题】:How to use custom manager with related objects?如何将自定义管理器与相关对象一起使用?
【发布时间】:2011-11-21 07:45:46
【问题描述】:

我有一个自定义管理器。我想将它用于相关对象。我在文档中找到了use_for_related_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()

【问题讨论】:

    标签: django django-managers django-orm


    【解决方案1】:

    为了主题的完整性,Django 1.7(最终)支持using a custom reverse manager,因此您可以执行类似的操作(只需从 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()
    

    【讨论】:

      【解决方案2】:

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

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

      我想你只在你的PostPages 模型上启用了它,而不是在你的Gallery 模型上(或者通过post_image_gallery 引用的任何模型)。如果您想在此房地产管理器上拥有额外的功能,您需要将带有 use_for_related_fields = True 的自定义默认管理器添加到您的 Gallery 模型!

      【讨论】:

      • 我在两个模型中都定义了管理器。如果我理解正确的话,objects 是指默认管理器。查看问题编辑,我在其中添加了模型。
      • 定义的第一个管理器成为默认管理器,不管它是否被称为objects...
      • 呜呜呜!其作品!很可能有一些非常愚蠢的错误。因为现在没事了。
      • 警告,从 Django 1.10 开始,该功能已被弃用,取而代之的是在模型上设置 Meta.base_manager_name。请参阅docs.djangoproject.com/en/1.10/releases/1.10/… 中的发行说明。
      • 其他警告:文档还说在查询相关对象时不使用管理器。 docs.djangoproject.com/en/1.11/topics/db/managers/…。这可以防止使用该功能隐式过滤掉相关对象。
      【解决方案3】:

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

      你应该使用base_manager_name: 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-related-object-access

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

      【讨论】:

      • base_manager_name 期望所讨论的经理的名称为字符串,而不是实例。见this
      • 对我来说,在我的模型中覆盖默认的objects 属性时甚至需要设置base_manager_name(之前,我认为只有当经理名称与默认的objects 不同时才需要这样做)!
      【解决方案4】:

      另外,在自定义管理器中,确保通过 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()
      

      【讨论】:

        猜你喜欢
        • 2013-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-25
        • 2013-05-31
        • 1970-01-01
        • 2018-01-21
        • 1970-01-01
        相关资源
        最近更新 更多