Разные поля для добавления и изменения страниц в admin
У меня есть приложение django со следующим классом в моей admin.py:
class SoftwareVersionAdmin(ModelAdmin):
fields = ("product", "version_number", "description",
"media", "relative_url", "current_version")
list_display = ["product", "version_number", "size",
"current_version", "number_of_clients", "percent_of_clients"]
list_display_links = ("version_number",)
list_filter = ['product',]
Я хочу иметь эти файлы для добавления страницы, но разные поля для страницы изменений. Как я могу это сделать?
Ответы
Ответ 1
Сначала рассмотрим источник методов ModelAdmin class 'get_form
и get_formsets
, расположенных в django.contrib.admin.options.py
. Вы можете переопределить эти методы и использовать kwargs для получения желаемого поведения. Например:
class SoftwareVersionAdmin(ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
# Proper kwargs are form, fields, exclude, formfield_callback
if obj: # obj is not None, so this is a change page
kwargs['exclude'] = ['foo', 'bar',]
else: # obj is None, so this is an add page
kwargs['fields'] = ['foo',]
return super(SoftwareVersionAdmin, self).get_form(request, obj, **kwargs)
Ответ 2
Это старый вопрос, но я хотел добавить, что методы add_view и change_view могут быть изменены для этой цели:
class SoftwareVersionAdmin(ModelAdmin):
...
def add_view(self,request,extra_content=None):
self.exclude = ('product','version_number',)
return super(SoftwareVersionAdmin,self).add_view(request)
def change_view(self,request,object_id,extra_content=None):
self.exclude = ('product','description',)
return super(SoftwareVersionAdmin,self).change_view(request,object_id)
Ответ 3
Вот как это делается в Django 1.10. Просто переопределите get_form
и верните add_form
, когда объект None:
class FoobarAddForm(forms.ModelForm):
class Meta:
model = Foobar
fields = ['some_field',]
@register(Foobar)
class AdminFoobar(admin.ModelAdmin):
add_form = FoobarAddForm
def get_form(self, request, obj=None, **kwargs):
defaults = {}
if obj is None:
defaults['form'] = self.add_form
defaults.update(kwargs)
return super(AdminFoobar, self).get_form(request, obj, **defaults)
Ответ 4
Я не мог получить эту работу в django 1.6.5, используя вышеупомянутые решения. Поэтому я попытался создать формы и получить get_form для этих предопределенных форм в зависимости от того, существует или нет объект:
models.py:
from django.db import models
class Project(models.Model):
name = models.CharField('Project Name', max_length=255)
slug = models.SlugField('Project Slug', max_length=255, unique=True)
forms.py:
из форм импорта django из проектов импорта проекта
class ProjectAddForm(forms.ModelForm):
test = forms.Field()
class Meta:
model = Project
class ProjectEditForm(forms.ModelForm):
class Meta:
model = Project
fields = ("name", 'slug')
admin.py
from django.contrib import admin
from models import Project
from forms import ProjectAddForm, ProjectEditForm
class ProjectAdmin(admin.ModelAdmin):
def get_form(self, request, obj=None, **kwargs):
# Proper kwargs are form, fields, exclude, formfield_callback
if obj:
self.form = ProjectEditForm
else:
self.form = ProjectAddForm
return super(ProjectAdmin, self).get_form(request, obj, **kwargs)
admin.site.register(Project, ProjectAdmin)
Теперь я могу перехватить непостоянное поле теста в чистых формах и делать то, что мне нужно, просто перезаписать в ProjectAddForm:
def clean(self):
cleaned_data = super(ProjectAddForm, self).clean()
test = cleaned_data.get("test")
# Do logic here
#raise forms.ValidationError("Passwords don't match.")
return cleaned_data
Ответ 5
Этот код не работал у меня.
Я просто немного меняю его:
if obj: # obj is not None, so this is a change page
#kwargs['exclude'] = ['owner']
self.fields = ['id', 'family_name', 'status', 'owner']
else: # obj is None, so this is an add page
#kwargs['fields'] = ['id', 'family_name', 'status']
self.fields = ['id', 'family_name', 'status']
return super(YourAdmin, self).get_form(request, obj, **kwargs)
Ответ 6
Я не думаю, что рекомендуется переопределять fields
или exclude
или form
, потому что они являются атрибутами конфигурации, поэтому они не будут инициализироваться для каждого запроса.
Я думаю, что принятый ответ shanyu - хорошее решение.
Или мы можем использовать этот метод из UserAdmin:
def get_fieldsets(self, request, obj=None):
if not obj:
return self.add_fieldsets
return super(UserAdmin, self).get_fieldsets(request, obj)
Не забудьте назначить add_fieldsets
самостоятельно. К сожалению, это не подходит для моего использования.
Для Django 1.7. Я не знаю, как они реализованы в других версиях.
Ответ 7
Полагаю, что решение dpawlows 'является самым ясным.
Однако я обнаружил дополнительную проблему в этом типе структуры.
Если change_view()
вносит изменения в модель, например. указывает readonly_fields
, которые были заполнены в add_view()
, эти изменения сохраняются в add_view()
после вызова change_view()
. Например:
def add_view(self, request, extra_context=None):
return super().add_view(request)
def change_view(self, request, object_id, extra_context=None):
self.readonly_fields = ['name'] # this change persists in add_view()
return super().change_view(self, request, object_id)
В этом случае после того, как change_view()
был вызван в любом экземпляре, вызов add_view()
будет показывать readonly_fields
( "name", в этом случае), установленный change_view()
и, таким образом, защищать эти поля от заполнения.
Это можно решить, добавив в add_view()
назначение 'roll back':
def add_view(self, request, extra_context=None):
self.readonly_fields = [] # 'roll back' for changes made by change_view()
return super().add_view(request)
Ответ 8
Использование форм в Django 1.6 В итоге я получил следующее:
def get_formsets(self, request, obj=None):
if obj is None:
# It a new object
for field, fieldset in {'hide_me_from_the_first_fieldset': 0,
'me_from_the_second': 1,
'and_me_too': 1}.items():
self.fieldsets[fieldset][1]['fields'].remove(field)
return super().get_formsets(request, obj)
EDIT:
Возможно, более интуитивным способом является указание отдельного свойства add_fieldsets
и выполните:
def get_formsets(self, request, obj=None):
if obj is None:
self.fieldsets = self.add_fieldsets
return super().get_formsets(request, obj)