Django

Code

Ticket #6776: 6776_modeladmin_fix.2.diff

File 6776_modeladmin_fix.2.diff, 4.9 kB (added by brosner, 9 months ago)

slightly better patch and tests

  • /dev/null

    old new  
     1 
     2class ModelAdminCache(object): 
     3    """ 
     4    A cache of ModelAdmin classes. This ensures that once a ModelAdmin is 
     5    declared that it will remain the sole class. Basically providing a 
     6    guranteed ModelAdmin idenity. 
     7    """ 
     8    def __init__(self): 
     9        self.modeladmin_store = {} 
     10     
     11    def get(self, key): 
     12        return self.modeladmin_store[key] 
     13     
     14    def register(self, *admin_classes): 
     15        for admin_class in admin_classes: 
     16            key = ".".join(admin_class.__module__.split(".")[-2:] + [admin_class.__name__]) 
     17            if key in self.modeladmin_store: 
     18                continue 
     19            self.modeladmin_store[key] = admin_class 
     20 
     21admin_class_cache = ModelAdminCache() 
  • a/django/contrib/admin/options.py

    old new  
    44from django.newforms.models import _modelform_factory, _inlineformset_factory 
    55from django.contrib.contenttypes.models import ContentType 
    66from django.contrib.admin import widgets 
     7from django.contrib.admin.loading import admin_class_cache 
    78from django.contrib.admin.util import get_deleted_objects 
    89from django.core.exceptions import ImproperlyConfigured, PermissionDenied 
    910from django.db import models, transaction 
     
    124125        attrs = classes and {'class': u' '.join(classes)} or {} 
    125126        return self.field.label_tag(contents=contents, attrs=attrs) 
    126127 
     128class ModelAdminMetaclass(type): 
     129    def __new__(cls, name, bases, attrs): 
     130        new_class = forms.MediaDefiningClass.__new__(cls, name, bases, attrs) 
     131        try: 
     132            parents = [b for b in bases if issubclass(b, ModelAdmin)] 
     133            if not parents: 
     134                return new_class 
     135        except NameError: 
     136            return new_class 
     137        # put this in some sort of registry 
     138        admin_class_cache.register(new_class) 
     139        # due to the way imports happening only use the admin class that is 
     140        # already registered. 
     141        return admin_class_cache.get(".".join(new_class.__module__.split(".")[-2:] + [new_class.__name__])) 
     142 
    127143class BaseModelAdmin(object): 
    128144    """Functionality common to both ModelAdmin and InlineAdmin.""" 
    129145    raw_id_fields = () 
     
    200216 
    201217class ModelAdmin(BaseModelAdmin): 
    202218    "Encapsulates all admin options and functionality for a given model." 
    203     __metaclass__ = forms.MediaDefiningClass 
     219    __metaclass__ = ModelAdminMetaclass 
    204220 
    205221    list_display = ('__str__',) 
    206222    list_display_links = () 
  • a/django/contrib/admin/sites.py

    old new  
    7676        if isinstance(model_or_iterable, ModelBase): 
    7777            model_or_iterable = [model_or_iterable] 
    7878        for model in model_or_iterable: 
    79             if model in self._registry
    80                 raise AlreadyRegistered('The model %s is already registered' % model.__name__
     79            if model in self._registry and self._registry[model].__class__ is not admin_class
     80                raise AlreadyRegistered('The model %s is already registered to %s' % (model.__name__, self._registry[model].__class__.__name__)
    8181            self._registry[model] = admin_class(model, self) 
    8282 
    8383    def unregister(self, model_or_iterable): 
  • a/tests/regressiontests/modeladmin/models.py

    old new  
    1717 
    1818>>> request = None 
    1919 
     20Ensure that only the first ModelAdmin ever declared is the only one for the 
     21app. 
     22 
     23>>> class OneBandAdmin(ModelAdmin): 
     24...     pass 
     25 
     26>>> class TwoBandAdmin(ModelAdmin): 
     27...     pass 
     28 
     29>>> one_band_admin_id = id(OneBandAdmin) 
     30>>> id(OneBandAdmin) != id(TwoBandAdmin) 
     31True 
     32 
     33>>> class OneBandAdmin(ModelAdmin): 
     34...     pass 
     35 
     36>>> one_band_admin_id == id(OneBandAdmin) 
     37True 
     38 
    2039>>> band = Band(name='The Doors', bio='') 
    2140 
    2241Under the covers, the admin system will initialize ModelAdmin with a Model 
     
    96115...     class Meta: 
    97116...         model = Band 
    98117 
    99 >>> class BandAdmin(ModelAdmin): 
     118>>> class AnotherBandAdmin(ModelAdmin): 
    100119...     form = AdminBandForm 
    101120 
    102 >>> ma = BandAdmin(Band, site) 
     121>>> ma = AnotherBandAdmin(Band, site) 
    103122>>> ma.get_form(request).base_fields.keys() 
    104123['name', 'bio', 'sign_date', 'delete'] 
    105124>>> type(ma.get_form(request).base_fields['sign_date'].widget)