Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/346.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/23.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 管理中添加和更改页面的不同字段_Python_Django_Django Admin - Fatal编程技术网

Python 管理中添加和更改页面的不同字段

Python 管理中添加和更改页面的不同字段,python,django,django-admin,Python,Django,Django Admin,我的admin.py中有一个django应用程序,具有以下类: class SoftwareVersionAdmin(ModelAdmin): fields = ("product", "version_number", "description", "media", "relative_url", "current_version") list_display = ["product", "version_number", "size", "curren

我的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',]

我想为添加页面设置这些文件,但为更改页面设置不同的字段。如何实现这一点?

首先查看ModelAdmin类的源代码“
get\u form
get\u formset
方法,这些方法位于
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)
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)

这个特定的代码对我不起作用。 我只是稍微改变一下:

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)

在Django 1.6中使用表单集,我得到了以下结果:

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_fieldset
属性并执行以下操作:

def get_formsets(self, request, obj=None):
    if obj is None:
        self.fieldsets = self.add_fieldsets

    return super().get_formsets(request, obj)

使用上述解决方案,我无法在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')
管理员

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)
现在我可以截取forms clean中的非持久性测试字段,并按照我的意愿使用它,只需在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

这是一个老问题,但我想补充的是,可以为此修改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)

我认为覆盖
字段
排除
表单
不是一个好主意,因为它们是配置属性,所以不会对每个请求进行初始化。
我认为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_字段集
。不幸的是,它不适合我的用例

对于Django 1.7。我不知道它们在其他版本中是如何实现的。我认为上面的dpawlows解决方案是最清晰的

然而,我在这种结构中遇到了另一个问题

如果
change\u view()
对模型进行更改,例如指定在
add\u view()
中填写的
readonly\u字段,则调用
change\u view()
后,这些更改将在
add\u view()
中保留。例如:

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)
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\u view()
之后,调用
add\u view()
将显示
change\u view()
设置的
readonly\u字段
(“名称”),从而保护这些字段不被填充

这可以通过在
add\u view()
中添加“回滚”分配来解决:


Django 1.10就是这样做的。当对象为None时,只需覆盖
get\u form
并返回
add\u 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)

一种简单的方法是使用
fieldset
进行更改页面,使用
add\u fieldset
进行添加页面

我得到了不可预测的结果(它在不同的时间出现和消失)。我认为更改自身属性不是线程安全的——请参见此处的评论:这比当前公认的答案在意图上更好、更清晰。