如何在Django和xadmin中移除已注册模型的Admin类菜单入口
解决方案
嘿,针对你的需求,结合Python3/Django2.0/xadmin的技术栈,我整理了两种实用的实现方式——既能在C的新增/编辑页面创建关联的A、B数据,又能把A、B的专属管理菜单完全隐藏起来:
方法一:注册A、B但隐藏菜单,用xadmin自带的弹窗新增功能
这种方式最省心,直接利用xadmin原生的关联对象交互能力:
注册A、B模型,但隐藏它们的菜单入口
在你的adminx.py文件里,注册A和B模型,同时通过hidden_menu属性把它们的菜单从系统导航里藏掉:import xadmin from .models import A, B, C class AAdmin(object): # 让该模型不在系统菜单中显示 hidden_menu = True # 可按需配置其他属性,比如列表页显示的字段 list_display = ['name'] # 假设A模型有name字段 class BAdmin(object): hidden_menu = True list_display = ['name'] # 假设B模型有name字段 xadmin.site.register(A, AAdmin) xadmin.site.register(B, BAdmin)配置C模型的xadmin,启用外键弹窗新增
默认情况下,xadmin的外键字段旁会自带一个"+"按钮,点击就能弹窗创建关联的A/B数据(我们已经注册了A、B,只是菜单被隐藏了)。如果想优化选择体验,还可以配置外键的显示样式:class CAdmin(object): # 给所有外键字段配置ajax选择+弹窗新增的样式 relfield_style = 'fk-ajax' # 也可以单独给某个外键指定样式,比如: # relfield_style = {'product': 'fk-ajax', 'product_module': 'fk-select'} # 配置C模型的列表显示和编辑字段 list_display = ['product', 'product_module'] fields = ['product', 'product_module'] xadmin.site.register(C, CAdmin)要是担心有人通过URL直接访问A/B的管理页,还可以在AAdmin和BAdmin里加权限限制,彻底禁止访问:
class AAdmin(object): hidden_menu = True def has_permission(self): # 禁止所有用户访问A的管理页 return False
方法二:不注册A、B,自定义表单嵌入A/B字段
如果完全不想把A、B注册到xadmin,那可以通过自定义表单,在C的编辑页面直接嵌入A、B的字段,提交时自动创建关联对象:
编写自定义表单
在应用的forms.py里,定义C的表单,同时包含A、B的字段(要和A、B模型的实际字段对应):from django import forms from .models import A, B, C class CForm(forms.ModelForm): # 假设A模型有name必填字段,添加对应的表单字段 a_name = forms.CharField(label='TestA名称', required=True) # 如果A有其他必填字段,也要同步添加,比如: # a_description = forms.CharField(label='TestA描述', widget=forms.Textarea) # 同理添加B的字段,假设B有name必填字段 b_name = forms.CharField(label='TestB名称', required=True) class Meta: model = C fields = ['a_name', 'b_name'] def save(self, commit=True): # 先创建A的实例 a_instance = A.objects.create( name=self.cleaned_data['a_name'] # 有其他字段的话在这里补充赋值 # description=self.cleaned_data['a_description'] ) # 再创建B的实例 b_instance = B.objects.create( name=self.cleaned_data['b_name'] ) # 创建C的实例并关联A、B c_instance = super().save(commit=False) c_instance.product = a_instance c_instance.product_module = b_instance if commit: c_instance.save() return c_instance在xadmin中配置C使用自定义表单
回到adminx.py,注册C模型并指定使用刚才的自定义表单:import xadmin from .models import C from .forms import CForm class CAdmin(object): form = CForm # 配置C的列表显示字段 list_display = ['product', 'product_module'] xadmin.site.register(C, CAdmin)这种方式下,A、B完全没注册到xadmin,系统菜单里肯定看不到它们,用户编辑C时直接填写A、B的信息,提交后就会自动创建关联的A、B实例。
小提醒
- 方法一中的
hidden_menu只是隐藏菜单,若要彻底禁止访问A/B的管理页,一定要加上has_permission返回False的配置。 - 方法二中,要确保A、B的所有必填字段都在自定义表单里体现,不然保存时会触发数据库校验错误。
内容的提问来源于stack exchange,提问作者Bob
相关产品推荐
相关产品推荐

