2013-05-21 13 views
6

ich ein Modell, das wie folgt aussieht:Begrenzung der queryset für ManyToMany MultipleSelect in Django Admin

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

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

jedoch in der django Admin MultipleSelect Formularfeld, das für event_dates im EventAdmin zeigen wird, würde Ich mag Beschränken des Abfrage-Sets auf event_dates, die nicht in der Vergangenheit liegen.

Die queryset seien so etwas wie:

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

Aber wo kann ich diese queryset, so dass nur Nicht-Daten in der Vergangenheit auf dem Gebiet auftauchen?

(ich habe nicht noch ein benutzerdefiniertes Formular für die EventAdmin würde aber gerne eine hinzuzufügen.)

+0

Mögliche Duplikat [Filter ManyToMany Feld in Django Admin] (http: // stackoverflow.com/questions/1226760/filter-manytomany-box-in-django-admin) – Wtower

Antwort

14

Sie könnten versuchen:

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

von https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ForeignKey.limit_choices_to genommen

aber dann nur Daten in der Zukunft werden angezeigt, auch wenn einige Daten in der Vergangenheit immer noch mit Event verknüpft sind.

Wenn Sie auch alle Termine möchten Sie vorher Event zugeordnet Sie ModelForm manipulieren könnte als

folgende
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

ja, ich meinte event_dates und aktualisiert die Frage, um genau das zu reflektieren. Guter Punkt, wenn man event_dates beibehalten möchte, die in der Vergangenheit liegen, aber bereits ausgewählt sind. Die vollständigere Lösung ist wahrscheinlich diejenige, nach der ich suche, obwohl ich mit limit_choices_to etwas Neues gelernt habe. Vielen Dank! –

+0

Ich endete mit dem zweiten (umfassenderen) Ansatz fast wörtlich, funktioniert gut. –

2

einfachste Weg, es in der Admin zu tun ist

Ihre Modelle

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

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

Jetzt in Ihrer Admin-Datei

Dies hat den zusätzlichen Vorteil, dass sie nur Ereignisdaten nur für das aktuelle Ereignis zurückgibt, die Sie bei Verwendung des Reverse-Lookup suchen 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)