2009-03-26 15 views
12

Próbowałem różnych metod, aby to osiągnąć.Django - Zastępowanie get_form w celu dostosowania formularzy administracyjnych na żądanie

Zdecydowałem się nie przesłonić pola formfield_for_dbfield, ponieważ nie otrzymałem kopii obiektu żądania i miałem nadzieję uniknąć hackowania thread_locals.

zdecydowałem się na nadrzędne get_form w mojej klasie ModelAdmin i próbowałem następujące:

class PageOptions(admin.ModelAdmin): 
    def get_form(self, request, obj=None, **kwargs): 
     if request.user.is_superuser: 
      self.fieldsets = ((None, {'fields': ('title','name',),}),) 
     else: 
      self.fieldsets = ((None, {'fields': ('title',),}),) 
     return super(PageOptions,self).get_form(request, obj=None, **kwargs) 

Kiedy drukować fieldsets lub declared_fieldsets od wewnątrz get_form uzyskać None (lub cokolwiek ustawić jako wartości początkowej w PageOptions).

Dlaczego to nie działa i czy istnieje lepszy sposób na zrobienie tego?

+1

Czy próbowałeś zadeklarować zestaw pól gdzieś w klasie PageOptions, aby sprawdzić, czy to działa? –

+0

Tak, ten program działa niezależnie od tego, co jest w get_form –

Odpowiedz

8

nie mam pojęcia dlaczego drukując właściwość nie daje chcesz po prostu przypisany (myślę, może być tak, że w zależności od tego, gdzie wydrukować, dokładnie), ale spróbuj nadrzędnymi get_fieldsets zamiast tego. Realizacja baza wygląda następująco:

def get_fieldsets(self, request, obj=None): 
    if self.declared_fieldsets: 
     return self.declared_fieldsets 
    form = self.get_formset(request).form 
    return [(None, {'fields': form.base_fields.keys()})] 

Tj powinieneś być w stanie po prostu zwrócić swoje krotki.

EDYTUJ przez andybak. 4 lata później i ponownie znalazłem swoje własne pytanie, próbując zrobić coś podobnego w innym projekcie. Tym razem poszedłem z tym podejściem, chociaż nieznacznie zmodyfikowany w celu uniknięcia konieczności powtarzania definicji fieldsets:

def get_fieldsets(self, request, obj=None): 
    # Add 'item_type' on add forms and remove it on changeforms. 
    fieldsets = super(ItemAdmin, self).get_fieldsets(request, obj) 
    if not obj: # this is an add form 
     if 'item_type' not in fieldsets[0][1]['fields']: 
      fieldsets[0][1]['fields'] += ('item_type',) 
    else: # this is a change form 
     fieldsets[0][1]['fields'] = tuple(x for x in fieldsets[0][1]['fields'] if x!='item_type') 
    return fieldsets 
21

Mam przykładowy kod z ostatniego projektu, który według mnie może ci pomóc. W tym przykładzie superużytkownicy mogą edytować każde pole, podczas gdy wszyscy inni mają wykluczone pole "opisu".

Pamiętaj, że uważam, że oczekuje się, że zwrócisz klasę Form z get_form, co może być przyczyną tego, że nie działała poprawnie.

Oto przykład:

class EventForm(forms.ModelForm): 
    class Meta: 
     model = models.Event 
     exclude = ['description',] 

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

class EventAdmin(admin.ModelAdmin): 

    def get_form(self, request, obj=None, **kwargs): 
     if request.user.is_superuser: 
      return EventAdminForm 
     else: 
      return EventForm 

admin.site.register(models.Event, EventAdmin) 
+0

To wygląda na bardzo pomocne. Jestem teraz w połowie ostatecznego terminu, ale wypróbuję to w przyszłym tygodniu. PS Czy mój wynik połączenia nie jest zwrócony w formularzu? Po prostu modyfikuję parametry i zwracam to, co get_form zwróciłoby samo. –

+0

A co z używaniem zestawów pól z tym rozwiązaniem? Jeśli użyjemy get_forms, tracimy konfigurację dla zestawów pól, a także widgetu javascript DateTimeField. Dzięki. – vmassuchetto

+1

https://docs.djangoproject.com/en/1.4/ref/contrib/admin/#django.contrib.admin.ModelAdmin.get_form wydaje się być znacznie lepszym rozwiązaniem. @ Ryan-duffield – Saurabh

6

To jest moje rozwiązanie:

class MyModelAdmin(admin.ModelAdmin): 

    def get_form(self, request, obj=None, **kwargs): 
     if request.user.is_superuser: 
      self.exclude =() 
     else: 
      self.exclude = ('field_to_exclude',) 
     return super(MyModelAdmin, self).get_form(request, obj=None, **kwargs) 

Nadzieja może pomóc

+1

Zamiast usuwać pole, możesz chcieć ustawić go jako tylko do odczytu (Django 1.2 i nowsze) - po prostu użyj self.readonly_fields zamiast self.exclude. – jturnbull

+0

To nie jest wątek bezpieczne. Lub jest bezpieczny dla wątków tylko dlatego, że masz inny warunek. Spróbuj zmodyfikować kwargs ["wyklucz"] zamiast self.exclude. – pista329

3

nie należy zmieniać wartości atrybutów własnych, ponieważ nie jest bezpieczny dla wątków. Aby zastąpić te wartości, musisz użyć haków.

6

Do tworzenia niestandardowych formularzy administracyjnych zdefiniowaliśmy nową klasę, która może być używana jako mixin.Takie podejście jest bardzo elastyczny,

  • ModelAdmin: określenie pól jako zawierający wszystkie pola

  • ModelForm: wąskie pola pokazano

  • FlexibleModelAdmin: przełączanie get_fieldsets-sposobu ModelAdmin; zwraca zmniejszona fieldset że tylko zawiera pola zdefiniowane w postaci administratora


class FlexibleModelAdmin(object): 
    ''' 
    adds the possibility to use a fieldset as template for the generated form 
    this class should be used as mix-in 
    ''' 

    def _filterFieldset(self, proposed, form): 
     ''' 
     remove fields from a fieldset that do not 
     occur in form itself. 
     ''' 

     allnewfields = [] 
     fields = form.base_fields.keys() 
     fieldset = [] 
     for fsname, fdict in proposed: 
      newfields = [] 
      for field in fdict.get('fields'): 
       if field in fields: 
        newfields.append(field) 
       allnewfields.extend(newfields) 
      if newfields: 
       newentry = {'fields': newfields} 
       fieldset.append([fsname, newentry]) 

     # nice solution but sets are not ordered ;) 
     # don't forget fields that are in a form but were forgotten 
     # in fieldset template 
     lostfields = list(set(fields).difference(allnewfields)) 
     if len(lostfields): 
      fieldset.append(['lost in space', {'fields': lostfields}]) 

     return fieldset 

    def get_fieldsets(self, request, obj=None): 
     ''' 
     Hook for specifying fieldsets for the add form. 
     ''' 

     if hasattr(self, 'fieldsets_proposed'): 
      form = self.get_form(request, obj) 
      return self._filterFieldset(self.fieldsets_proposed, form) 
     else: 
      return super(FlexibleModelAdmin, self).get_fieldsets(request, obj) 

w modelu administracyjnego zdefiniować fieldsets_proposed który służy jako szablon i zawiera wszystkie pola.

class ReservationAdmin(FlexibleModelAdmin, admin.ModelAdmin): 

    list_display = ['id', 'displayFullName'] 
    list_display_links = ['id', 'displayFullName'] 
    date_hierarchy = 'reservation_start' 
    ordering = ['-reservation_start', 'vehicle'] 
    exclude = ['last_modified_by'] 

    # considered by FlexibleModelAdmin as template 
    fieldsets_proposed = (
     (_('General'), { 
      'fields': ('vehicle', 'reservation_start', 'reservation_end', 'purpose') # 'added_by' 
     }), 
     (_('Report'), { 
      'fields': ('mileage') 
     }), 
     (_('Status'), { 
      'fields': ('active', 'editable') 
     }), 
     (_('Notes'), { 
      'fields': ('note') 
     }), 
    ) 
    ....   

    def get_form(self, request, obj=None, **kwargs): 
     ''' 
     set the form depending on the role of the user for the particular group 
     ''' 

     if request.user.is_superuser: 
      self.form = ReservationAdminForm 
     else: 
      self.form = ReservationUserForm 

     return super(ReservationAdmin, self).get_form(request, obj, **kwargs) 

admin.site.register(Reservation, ReservationAdmin) 

W formularzach modelu można teraz zdefiniować pola do wykluczenia/uwzględnienia. get_fieldset() klasy mixin zapewnia, że ​​zwracane są tylko pola zdefiniowane w formularzu.

class ReservationAdminForm(ModelForm): 
    class Meta: 
     model = Reservation 
     exclude = ('added_by', 'last_modified_by') 

class ReservationUserForm(BaseReservationForm): 
    class Meta: 
     model = Reservation 
     fields = ('vehicle', 'reservation_start', 'reservation_end', 'purpose', 'note') 
0

Można zrobić fieldsets i form właściwości i je emitować sygnały, aby uzyskać żądane/postacie fieldsets.

Powiązane problemy