我的admin.py中有以下类的django应用程序:
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',]
我希望这些文件用于添加页面,但不同的字段用于更改页面。我怎么能这样做?
答案 0 :(得分:27)
首先查看位于get_form
的ModelAdmin类“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)
答案 1 :(得分:24)
这是一个老问题,但我想补充一点,为此可以修改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)
答案 2 :(得分: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中覆盖clean:
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
答案 3 :(得分:4)
这是在Django 1.10中完成的。只需覆盖get_form
并在对象为无时返回add_form
:
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 :(得分:2)
此特定代码对我不起作用。 我只是稍微改变一下:
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)
答案 5 :(得分:2)
我认为覆盖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。我不知道它们是如何在其他版本中实现的。
答案 6 :(得分:1)
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
将显示由change_view()
设置的add_view()
(在本例中为“name”)从而保护这些领域免于填补。
这可以通过在def add_view(self, request, extra_context=None):
self.readonly_fields = [] # 'roll back' for changes made by change_view()
return super().add_view(request)
中添加“回滚”作业来解决:
.slide-down-banner-menu-panel
答案 7 :(得分:0)
在Django 1.6中使用formset我得到了以下内容:
def get_formsets(self, request, obj=None):
if obj is None:
# It's 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)
编辑:
也许更直观的方法是指定单独的add_fieldsets
属性并执行:
def get_formsets(self, request, obj=None):
if obj is None:
self.fieldsets = self.add_fieldsets
return super().get_formsets(request, obj)
答案 8 :(得分:0)
一种简单的方法是将fieldsets
用于更改页面,将add_fieldsets
用于添加页面。
答案 9 :(得分:0)
使用更现代的 Django 版本(在撰写本文时为 3.2),您可以覆盖 BaseModelAdmin
中的一些方法以实现在“更改”和“添加”模型管理页面上具有不同的字段:
class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
"""Functionality common to both ModelAdmin and InlineAdmin."""
# ...
def get_exclude(self, request, obj=None):
"""
Hook for specifying exclude.
"""
return self.exclude
def get_fields(self, request, obj=None):
"""
Hook for specifying fields.
"""
if self.fields:
return self.fields
# _get_form_for_get_fields() is implemented in subclasses.
form = self._get_form_for_get_fields(request, obj)
return [*form.base_fields, *self.get_readonly_fields(request, obj)]
def get_fieldsets(self, request, obj=None):
"""
Hook for specifying fieldsets.
"""
if self.fieldsets:
return self.fieldsets
return [(None, {'fields': self.get_fields(request, obj)})]
def get_readonly_fields(self, request, obj=None):
"""
Hook for specifying custom readonly fields.
"""
return self.readonly_fields
例如,在更改页面上添加一些只读字段(obj
存在),但不在添加页面上:
class MyModelAdmin(admin.ModelAdmin):
# Readonly_fields only on change page
def get_readonly_fields(self, request, obj=None):
if obj: # obj is not None, so this is a change page
return 'field_1', 'field_2'
return () # obj is None, so this is the add page