如何在Django Admin修改列表中隐藏指定状态选项
解决Admin面板中限制状态选择的问题
要实现管理员只能选择前3种状态(Unproven、In progress、In line for deletion),同时保留模型层面完整的choices(因为Celery任务需要设置DELETED状态),你可以通过自定义Admin表单来覆盖status字段的可选值,下面提供两种常用的实现方式:
方式一:自定义ModelForm
创建一个Admin专用表单,在表单中重新定义status字段的choices,只保留需要的三个选项:
from django import forms from .models import UserDeleteRequest, UNPROVEN, IN_PROGRESS, IN_LINE_FOR_DELETE class UserDeleteRequestAdminForm(forms.ModelForm): class Meta: model = UserDeleteRequest fields = "__all__" # 重定义status字段,仅保留前三个状态选项 status = forms.ChoiceField( choices=[ (UNPROVEN, "Unproven"), (IN_PROGRESS, "In progress"), (IN_LINE_FOR_DELETE, "In line for deletion"), ], required=True, )
接着在Admin类中指定使用这个表单:
@admin.register(UserDeleteRequest) class UserDeleteRequestAdmin(admin.ModelAdmin): form = UserDeleteRequestAdminForm # 绑定自定义表单 list_display = ("status", "responsible_user") fields = ("delete_user", "status", "responsible_user", "delete_reason") readonly_fields = ("responsible_user", "delete_user", "delete_reason") def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False def save_model(self, request, obj, form, change): # 修正原代码的条件判断错误:原写法"obj.status == 3 or 2"永远为True if obj.status in (IN_PROGRESS, IN_LINE_FOR_DELETE): obj.responsible_user = request.user super().save_model(request, obj, form, change)
方式二:重写Admin的get_form方法
如果不想单独创建ModelForm,也可以在Admin类中动态修改字段的choices:
from .models import UNPROVEN, IN_PROGRESS, IN_LINE_FOR_DELETE @admin.register(UserDeleteRequest) class UserDeleteRequestAdmin(admin.ModelAdmin): list_display = ("status", "responsible_user") fields = ("delete_user", "status", "responsible_user", "delete_reason") readonly_fields = ("responsible_user", "delete_user", "delete_reason") def has_add_permission(self, request): return False def has_delete_permission(self, request, obj=None): return False def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) # 动态替换status字段的可选值 form.base_fields['status'].choices = [ (UNPROVEN, "Unproven"), (IN_PROGRESS, "In progress"), (IN_LINE_FOR_DELETE, "In line for deletion"), ] return form def save_model(self, request, obj, form, change): if obj.status in (IN_PROGRESS, IN_LINE_FOR_DELETE): obj.responsible_user = request.user super().save_model(request, obj, form, change)
额外优化建议
- 针对已处于DELETED状态的记录,你可以让
status字段变成只读,避免管理员误修改:def get_readonly_fields(self, request, obj=None): readonly_fields = super().get_readonly_fields(request, obj) if obj and obj.status == 4: # 或使用DELETED常量 return readonly_fields + ("status",) return readonly_fields - 模型层面的
_STATUS无需修改,这样Celery任务设置DELETED状态后,Admin列表页仍能正常显示"Deleted"文本,只是编辑表单中无法选择该选项。
内容的提问来源于stack exchange,提问作者GrinRuslan
相关产品推荐
相关产品推荐

