Skip to content

Instantly share code, notes, and snippets.

@tim-schilling
Last active September 20, 2024 07:55
Show Gist options
  • Save tim-schilling/62198998a99a19c7f4b73f14d29c6997 to your computer and use it in GitHub Desktop.
Save tim-schilling/62198998a99a19c7f4b73f14d29c6997 to your computer and use it in GitHub Desktop.
Helper classes and a monkeypatch to always register a model's field in the admin as raw_id_fields. This is useful when you have models with 1000+ rows to avoid massive select elements.
from functools import wraps
from django.contrib import admin
class AdminMeta:
"""
Use this Meta class on a model since we can't add
custom fields to Model.Meta
"""
always_raw_id_field = False
def patch_model_admin_always_raw_id_field():
"""
Monkey patch admin.ModelAdmin to dynamically register
additional raw_id_fields.
This is best used in an AppConfig.ready() method
"""
def patch_model_admin(init):
@wraps(init)
def __init__(self, model, admin_site, **kwargs):
init(self, model, admin_site, **kwargs)
# iterate over relationship fields, check if any related models are AdminMeta.always_raw_id_field
new_raw_ids_fields = [
field.name
for field in model._meta.get_fields()
if field.is_relation
and field.related_model
and field.concrete
and (admin_meta := getattr(field.related_model, AdminMeta.__name__, None))
and issubclass(admin_meta, AdminMeta)
and admin_meta.always_raw_id_field
]
if new_raw_ids_fields:
self.raw_id_fields = list(self.raw_id_fields) + new_raw_ids_fields
return __init__
if getattr(admin.ModelAdmin, '_patched_model_admin_always_raw_id_field', None):
return
admin.ModelAdmin.__init__ = patch_model_admin(admin.ModelAdmin.__init__)
admin.ModelAdmin._patched_model_admin_always_raw_id_field = True
from django.db import models
from admin_meta import AdminMeta
class AlwaysRawIdModel(models.Model):
"""
Inherit from this model so that any reference to this
field in the admin will be a raw id field
"""
class Meta:
abstract = True
class AdminMeta(AdminMeta):
always_raw_id_field = True
from django.apps import AppConfig
from admin_meta import patch_model_admin_always_raw_id_field
class MyApp(AppConfig):
name = "my_app"
def ready(self):
patch_model_admin_always_raw_id_field()
from django.contrib.admin
from always_raw_id import AlwaysRawIdModel
class MyModel(AlwaysRawIdModel):
pass
class OtherModel(models.Model):
class AdminMeta(AdminMeta):
always_raw_id_field = True
admin.register(MyModel)
admin.register(OtherModel)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment