如何在Django Admin禁用多对多字段数据并解决E109错误?
Hey there, let's work through your Django Admin issues step by step—first addressing that admin.E109 error, then handling your goal of disabling edits for the employees ManyToMany field.
First: Resolve the admin.E109 Error
The error you're seeing:
ERRORS: : (admin.E109) The value of 'list_display[6]' must not be a ManyToManyField.
This happens because Django Admin's list_display doesn't support directly referencing ManyToMany fields—these fields link to multiple objects, which can't be rendered as simple text in the list view. To fix this, create a custom method to display the related employees in a readable format:
Update your admin.py like this:
class holidayAdmin(FilterUserAdmin): form = select2_modelform(holiday, attrs={'width': '250px'}) fields= ('type','start_date','end_date','employees','image_ref','note',) # Replace 'employees' in list_display with our custom method list_display = ('type','created_by','last_modified_by','start_date', 'end_date','note','display_employees') # Custom method to display employees as a comma-separated list def display_employees(self, obj): return ", ".join([emp.fullname for emp in obj.employees.all()]) # Set a friendly column name in the admin list display_employees.short_description = 'Employees'
Next: Disable Edits for the employees ManyToMany Field
Choose one of these approaches based on your needs:
Option 1: Make the Field Read-Only
Add employees to readonly_fields—this keeps the field visible in the edit page but prevents any changes:
class holidayAdmin(FilterUserAdmin): form = select2_modelform(holiday, attrs={'width': '250px'}) fields= ('type','start_date','end_date','employees','image_ref','note',) readonly_fields = ('employees',) # Add this line list_display = ('type','created_by','last_modified_by','start_date', 'end_date','note','display_employees') def display_employees(self, obj): return ", ".join([emp.fullname for emp in obj.employees.all()]) display_employees.short_description = 'Employees'
Option 2: Remove the Field from the Edit Page Entirely
If you don't want users to see the employees field at all in the edit form, just remove it from the fields list:
fields= ('type','start_date','end_date','image_ref','note',) # No more 'employees' here
Option 3: Dynamic Control (e.g., Based on User Permissions)
If you need to disable the field only for certain users, override the get_form method to modify the form widget:
class holidayAdmin(FilterUserAdmin): form = select2_modelform(holiday, attrs={'width': '250px'}) fields= ('type','start_date','end_date','employees','image_ref','note',) list_display = ('type','created_by','last_modified_by','start_date', 'end_date','note','display_employees') def display_employees(self, obj): return ", ".join([emp.fullname for emp in obj.employees.all()]) display_employees.short_description = 'Employees' def get_form(self, request, obj=None, **kwargs): form = super().get_form(request, obj, **kwargs) # Disable the employees field (users can't select new values) form.base_fields['employees'].widget.attrs['disabled'] = True # Optional: Make it visually read-only too form.base_fields['employees'].widget.attrs['readonly'] = True return form
内容的提问来源于stack exchange,提问作者Tawfiq Qasim Khaled

