2013-05-21 29 views
6

Mam model, który wygląda tak:ograniczenie queryset dla ManyToMany multipleSelect w Django administratora

class Event(models.Model): 
    event_dates = ManyToManyField("EventDate") 
    #... 

class EventDate(models.Model): 
    event_date = DateField() 
    #... 

Jednak w django admina MultipleSelect pola formularza, który dostaje pokazać event_dates w EventAdmin, chciałbym ograniczyć zestaw zapytań do date_data, które nie należą do przeszłości.

queryset byłoby coś takiego:

event_date_queryset = EventDate.objects.filter(event_date__gte = datetime.date.today()) 

Ale gdzie mogę ustawić queryset tak, że tylko non-przeszłe daty pojawiają się w tej dziedzinie?

(I obecnie nie mają formę niestandardowej dla EventAdmin ale chętnie dodać.)

+0

Możliwy duplikat [Filtr pole ManyToMany w Django admin] (http: // stackoverflow.com/questions/1226760/filter-manytomany-box-in-django-admin) – Wtower

Odpowiedz

14

można spróbować:

event_dates = models.ManyToManyField("EventDate", limit_choices_to={'event_date__gte': date.today()}) 

zaczerpnięte z https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.limit_choices_to

ale potem wyświetlane są tylko daty w przyszłości, nawet jeśli niektóre daty w przeszłości nadal są powiązane z Event.

Jeśli chcesz także wszystkie daty wcześniej skojarzone do Event można manipulować ModelForm następująco

from datetime import date 

from django.contrib import admin 
from django import forms 
from django.db.models import Q 

from models import Event, EventDate 

class EventAdminForm(forms.ModelForm): 
    class Meta: 
     model = Event 

    def __init__(self, *args, **kwargs): 
     super(EventAdminForm, self).__init__(*args, **kwargs) 
     if 'event_dates' in self.initial: 
      self.fields['event_dates'].queryset = EventDate.objects.filter(Q(pk__in=self.initial['event_dates']) | Q(event_date__gte=date.today())) 
     else: 
      self.fields['event_dates'].queryset = EventDate.objects.filter(event_date__gte=date.today()) 

class EventAdmin(admin.ModelAdmin): 
    form = EventAdminForm 
    filter_horizontal = ['event_dates'] 
+0

tak, miałem na myśli date_dates i zaktualizowałem pytanie, aby dokładnie to odzwierciedlić. Dobrze, że chcesz zachować date_darzenia, które są w przeszłości, ale już wybrane. Bardziej kompletne rozwiązanie jest prawdopodobnie tym, którego szukam, chociaż nauczyłem się czegoś nowego z limit_choices_to. Dzięki! –

+0

Skończyłem na używaniu drugiego (bardziej kompleksowego) podejścia niemal dosłownie, działa świetnie. –

2

Najprostszy sposób to zrobić w admin

modeli

class Event(models.Model): 
    event_dates = ManyToManyField("EventDate") 
    #... 

class EventDate(models.Model): 
    event_date = DateField() 
    #... 

Teraz w Twoim pliku administracyjnym

Ma to tę dodatkową zaletę, że tylko zwraca dat zdarzeń tylko dla bieżącego przypadku, gdy patrzysz użyciu wyszukiwania wstecznego event__id=event_id

class EventAdmin(admin.ModelAdmin): 
    def get_field_queryset(self, db, db_field, request): 
     """ 
     If the ModelAdmin specifies ordering, the queryset should respect that 
     ordering. Otherwise don't specify the queryset, let the field decide 
     (returns None in that case). 
     """ 
     if db_field.name == 'event_dates': 
      event_id = int(request.resolver_match.args[0]) 

      return db_field.remote_field.model._default_manager.filter(
           event__id=event_id, 
           event_date__gte = datetime.date.today() 
      ) 

     super().get_field_queryset(db, db_field, request) 
Powiązane problemy