Django - переопределение get_form для настройки форм администратора на основе запроса
Я пробовал различные методы для достижения этого.
Я решил не переопределять formfield_for_dbfield, поскольку он не получает копию объекта запроса, и я надеялся избежать взлома thread_locals.
Я решил переопределить get_form в моем классе ModelAdmin и попробовал следующее:
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)
Когда я печатаю поля или decl_fieldsets из get_form, я получаю None (или независимо от того, что я установил как начальное значение в PageOptions).
Почему это не работает, и есть ли лучший способ сделать это?
Ответы
Ответ 1
Я понятия не имею, почему печать свойства не дает вам желать, чтобы вы только что назначили (возможно, это зависит от того, где вы печатаете), но вместо этого попробуйте переопределить get_fieldsets
. Базовая реализация выглядит следующим образом:
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()})]
т.е. вы должны просто вернуть свои кортежи.
ИЗМЕНИТЬ by andybak. 4 года спустя, и я снова нашел свой собственный вопрос, пытаясь сделать что-то подобное в другом проекте. На этот раз я пошел с этим подходом, хотя и слегка изменился, чтобы избежать повторения определения полей:
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
Ответ 2
У меня есть образец кода из недавнего моего проекта, который, я считаю, может вам помочь. В этом примере суперпользователи могут редактировать каждое поле, в то время как у всех остальных исключено поле описания.
Обратите внимание, что я думаю, что ожидается, что вы вернете класс Form
из get_form
, что может быть причиной того, что вы не работали совершенно правильно.
Вот пример:
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)
Ответ 3
Это мое решение:
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)
Надежда может помочь
Ответ 4
Для создания настраиваемых форм администратора мы определили новый класс, который можно использовать в качестве mixin. Этот подход довольно гибкий:
-
ModelAdmin: укажите поле, содержащее поля all
-
ModelForm: сузить отображаемые поля
-
FlexibleModelAdmin: переопределение метода get_fieldsets ModelAdmin; возвращает уменьшенный набор полей, который содержит только поля, определенные в форме администратора
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)
В модели admin вы определяете fieldsets_proposed, который служит шаблоном и содержит все поля.
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)
В ваших модельных формах вы можете теперь определить поля, которые должны быть исключены/включены. get_fieldset() класса mixin гарантирует, что возвращаются только поля, определенные в форме.
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')
Ответ 5
Не изменяйте значение атрибутов self, потому что оно не является потокобезопасным. Для переопределения этих значений вам нужно использовать любые перехватчики.
Ответ 6
Вы можете сделать свойства fieldsets
и form
и заставить их испускать сигналы для получения желаемых форм/полей.