In our case, we need to dynamically include additional "exclude" fields in 
our VersionableAdmin and not override the selections the developer has set 
in their subclass.  There are two options to accomplished this:

1) Override get_form() which is messy because you can't just call super 
here and modify things.  This is a lot of code duplication to just get at 
the exclude

def get_form(self, request, obj=None, **kwargs):
    """
    Returns a Form class for use in the admin add view. This is used by
    add_view and change_view.
    """
    if 'fields' in kwargs:
        fields = kwargs.pop('fields')
    else:
        fields = flatten_fieldsets(self.get_fieldsets(request, obj))
    if self.exclude is None:
        exclude = []
    else:
        exclude = list(self.exclude)
    exclude.extend(self.get_readonly_fields(request, obj))
    if self.exclude is None and hasattr(self.form, '_meta') and 
self.form._meta.exclude:
        # Take the custom ModelForm's Meta.exclude into account only if the
        # ModelAdmin doesn't define its own.
        exclude.extend(self.form._meta.exclude)
    # if exclude is an empty list we pass None to be consistent with the
    # default on modelform_factory
    exclude = exclude or None
    defaults = {
        "form": self.form,
        "fields": fields,
        "exclude": exclude,
        "formfield_callback": partial(self.formfield_for_dbfield, 
request=request),
    }
    defaults.update(kwargs)

    if defaults['fields'] is None and not 
modelform_defines_fields(defaults['form']):
        defaults['fields'] = forms.ALL_FIELDS

    try:
        return modelform_factory(self.model, **defaults)
    except FieldError as e:
        raise FieldError('%s. Check fields/fieldsets/exclude attributes of 
class %s.'
                         % (e, self.__class__.__name__))


2) Build your own descriptor for exclude:

@property
def exclude(self):
    """
    Custom descriptor for exclude since there is no get_exclude method to be 
overridden
    """
    exclude = self.VERSIONED_EXCLUDE

    if super(VersionedAdmin, self).exclude is not None:
        # Force cast to list as super exclude could return a tuple
        exclude = list(super(VersionedAdmin, self).exclude) + exclude

    return exclude


But then this trips the _check_exclude check in ModelAdminChecks for not 
being a list or tuple. So you have to subclass that:

class VersionedAdminChecks(ModelAdminChecks):
    def _check_exclude(self, cls, model):
        """
        Required to suppress error about exclude not being a tuple since we are 
using @property to dynamically change it
        """
        return []


All of this is a lot of effort just to get at dynamic exclude where 
get_exclude() fits the current pattern used in the admin in the current 
code base.

-- 
You received this message because you are subscribed to the Google Groups 
"Django developers  (Contributions to Django itself)" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/django-developers.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-developers/350a8a70-aca9-493b-8ebe-225791cd9a70%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to