web-dev-qa-db-fra.com

Comment utiliser le gestionnaire personnalisé avec des objets associés?

J'ai un gestionnaire personnalisé. Je veux l'utiliser pour des objets connexes. J'ai trouvé se_for_related_fields dans la documentation. Mais cela ne fonctionne pas comme je l'ai utilisé:

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()

Je l'ai utilisé pour un modèle:

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

Et j'ai essayé de faire de même avec un objet lié à m2m:

>>> post.image_gallery.randomize()

Vous avez une erreur:

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

Est-il possible d'utiliser un gestionnaire personnalisé comme je l'ai fait? Si oui, comment le faites-vous fonctionner?

Éditer

Mes modèles:

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()
42
I159

Réglage use_for_related_fields à True sur le gestionnaire le rendra disponible sur toutes les relations qui pointent vers le modèle sur lequel vous avez défini ce gestionnaire comme le gestionnaire par défaut. Ceci est documenté ici

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

Je suppose que vous ne l'avez activé que sur votre modèle PostPages, pas sur votre modèle Gallery (ou quel que soit le modèle appelé qui est référencé par post_image_gallery). Si vous souhaitez avoir des fonctionnalités supplémentaires sur ce gestionnaire de realtion, vous devez ajouter un gestionnaire par défaut personnalisé avec use_for_related_fields = True à votre modèle Gallery!

26
Bernhard Vallant

Pour compléter le sujet, Django 1.7 (enfin) prend en charge en utilisant un gestionnaire inverse personnalisé , donc vous pouvez faire quelque chose comme ça (juste en copiant depuis le 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()
34
Serafeim

Dans Django 2.0 use_for_related_fields est obsolète https://docs.djangoproject.com/en/2.0/releases/1.10/#manager-use-for-related-fields-and-inheritance-changes

Tu devrais utiliser base_manager_name: https://docs.djangoproject.com/en/2.0/ref/models/options/#Django.db.models.Options.base_manager_name

Documents mis à jour: 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'
11

De plus, dans le gestionnaire personnalisé, assurez-vous d'accéder au jeu de requêtes via la méthode proxy self.get_query_set () lors de l'implémentation de filtres personnalisés à appeler à partir du gestionnaire associé:

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()

Exemple d'utilisation:

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()
2
Mario Orlandi