2011-09-20 18 views
24

Mam niestandardowego menedżera. Chcę go użyć do powiązanych obiektów. Znalazłem use_for_related_fields w dokumentach. Ale to nie działa tak, użyłem go:Jak używać niestandardowego menedżera z powiązanymi obiektami?

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

używałem go do jednego modelu

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

i starał się zrobić to samo z m2m związanego obiektu:

>>> post.image_gallery.randomize() 

Wystąpił błąd:

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

można użyć niestandardowego menedżera w taki sposób, w jaki to zrobiłem? Jeśli tak, jak to działa?

Edit

Moje modele:

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

Odpowiedz

18

Ustawianie use_for_related_fields do True na kierownika będzie to dostępne dla wszystkich stosunków wskazujących do model, na którym zdefiniowano tego menedżera jako domyślny menedżer . Jest to udokumentowane here

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

przypuszczam masz to włączone tylko modelu PostPages, nie od modelu Gallery (lub bez względu na model, który nazywa się odwoływać poprzez post_image_gallery). Jeśli chcesz mieć dodatkowe funkcje w tym menedżerze realtion, musisz dodać niestandardowego domyślnego menedżera z use_for_related_fields = True do swojego modelu Gallery!

+0

zdefiniowałem menedżera w obu modelach. Jeśli dobrze rozumiem, "obiekty" to domyślny menedżer. Zobacz edycje pytań, dodałem tam modele. – I159

+0

Zdefiniowany menedżer _first_ staje się domyślnym menedżerem, bez względu na to, czy jest on nazywany 'obiektem' czy nie ... –

+0

Uoo hooo! To działa! Najprawdopodobniej był jakiś bardzo głupi błąd. Ponieważ teraz jest w porządku. – I159

17

Dla kompletności temacie, Django 1.7 (wreszcie) obsługuje using a custom reverse manager, więc można zrobić coś takiego (tylko kopiowanie z docs 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

również w menedżerze niestandardowego, upewnij się, aby uzyskać dostęp do queryset przez self.get_query_set() metoda proxy podczas wdrażania niestandardowych filtrów należne od powiązanego menedżera: Wykorzystanie

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

Próbka:

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

w Django 2.0 use_for_related_fields jest depricated https://docs.djangoproject.com/en/2.0/releases/1.10/#manager-use-for-related-fields-and-inheritance-changes

Należy użyć base_manager_namehttps://docs.djangoproject.com/en/2.0/ref/models/options/#django.db.models.Options.base_manager_name

Tutaj są aktualizowane dokumenty 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' 
+0

'base_manager_name' oczekuje nazwy menedżera jako ciągu, a nie instancji. Zobacz [to] (https://github.com/django/django/blob/8dc675d90f14a84ef95f16c7cc8100d9a04459b3/tests/custom_managers/models.py#L158). – Nobilis

+0

@Nobilis dzięki, naprawione –