如何自动将ForeignKey与OneToOneField配置为raw_id_fields?
Automatically set raw_id_fields for all ForeignKey/OneToOneField in Django Admin
Absolutely! You can build a reusable mixin that takes care of auto-populating raw_id_fields with all your model's ForeignKey and OneToOneField fields—no more manual list maintenance. Let's fix up that mixin you started with to work properly with Django's admin lifecycle:
The Complete Mixin Implementation
from django.db import models from django.contrib import admin class AutoRawIdFieldsMixin: def __init__(self, model, admin_site): # Call parent constructor first to initialize core admin functionality super().__init__(model, admin_site) self.setup_raw_id_fields() def setup_raw_id_fields(self): # Collect all editable ForeignKey/OneToOneField fields from the model raw_id_candidates = [] # Use include_parents=False to skip fields inherited from parent models (optional) for field in self.model._meta.get_fields(include_parents=False): # Only include fields that are editable (since non-editable ones won't show up in the admin) if isinstance(field, (models.ForeignKey, models.OneToOneField)) and field.editable: raw_id_candidates.append(field.name) # Assign the collected fields to raw_id_fields as a tuple (matching Django's expected format) self.raw_id_fields = tuple(raw_id_candidates)
How to Use the Mixin
Just inherit the mixin first in your admin class (order matters—mixins need to come before admin.ModelAdmin):
@admin.register(DaftarSoal, site=admin_site) class DaftarSoalAdmin(AutoRawIdFieldsMixin, admin.ModelAdmin): # No manual raw_id_fields needed anymore! pass @admin.register(AnotherModel, site=admin_site) class AnotherModelAdmin(AutoRawIdFieldsMixin, admin.ModelAdmin): pass
Customization Options
If you need to exclude specific fields from being converted to raw ID inputs, add an exclude_raw_id_fields attribute to your admin class and update the mixin like this:
class AutoRawIdFieldsMixin: # Default to no exclusions exclude_raw_id_fields = () def __init__(self, model, admin_site): super().__init__(model, admin_site) self.setup_raw_id_fields() def setup_raw_id_fields(self): raw_id_candidates = [] for field in self.model._meta.get_fields(include_parents=False): if ( isinstance(field, (models.ForeignKey, models.OneToOneField)) and field.editable and field.name not in self.exclude_raw_id_fields ): raw_id_candidates.append(field.name) self.raw_id_fields = tuple(raw_id_candidates)
Then use it to exclude fields:
class DaftarSoalAdmin(AutoRawIdFieldsMixin, admin.ModelAdmin): # Keep 'folder' as a regular dropdown instead of raw ID exclude_raw_id_fields = ('folder',)
Key Notes
- We use
self.model._meta.get_fields()to inspect the model's fields directly, which is the official Django way to access model metadata. - Adding
field.editableensures we only include fields that would normally appear in the admin form (non-editable fields are skipped automatically). - Using
include_parents=Falseis optional but useful if you want to exclude fields inherited from abstract parent models.
内容的提问来源于stack exchange,提问作者binpy
相关产品推荐
相关产品推荐

