0

I have a generic ModelAdmin in my admin.py which replaces some widgets in the admin interface. It serves as a superclass for all my other ModelAdmins. It looks like this:

#in mainapp/admin.py:
from django.contrib import admin
from django.db import models
from suit.widgets import SuitSplitDateTimeWidget

class SuitedUpAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.DateTimeField: {
            'widget': SuitSplitDateTimeWidget
        },
        #(...)
    }
    #(...)

In a different Django app, I use SuitedUpAdmin as a superclass for a ModelAdmin that also tries to replace some of the widgets:

#in events/admin.py:
from django.contrib import admin
from django.db import models
from suit.widgets import AutosizedTextarea
from mainapp.admin import SuitedUpAdmin

class LocationAdmin(SuitedUpAdmin):
    formfield_overrides = {
        models.TextField: {'widget': AutosizedTextarea},
    }
    #(...)

The problem is, when I assign a new value to formfield_overrides in LocationAdmin, I lose the previous value inherited from SuitedUpAdmin. How can I deal with this? The solution I'm currently using is replacing widget instances in a LocationAdmin.render_change_form method, but I'm looking for more elegant and readable options. I'd like to avoid using ModelForms for this. Looking forward to your suggestions!

ksadowski
  • 161
  • 9

2 Answers2

1

You can combine formfield_overrides from the base class SuitedUpAdmin with a dict:

class LocationAdmin(SuitedUpAdmin):
    formfield_overrides = dict(SuitedUpAdmin.formfield_overrides, **{
        models.TextField: {'widget': AutosizedTextarea},
    })
Albert Tugushev
  • 1,504
  • 13
  • 25
  • I didn't realize I could execute `.update(...)` in there, thanks! It's sad that I can't use `super`, but maybe close enough. – ksadowski Jun 04 '14 at 10:50
  • 1
    Oh, but there's a bug in the code you provided: it actually updates its superclass's property, and assigns `None` to its own. I'd solve it by first using `copy()`, and then updating a duplicate dictionary, but maybe you have another idea? Please correct your example! – ksadowski Jun 04 '14 at 10:57
  • 1
    @Hellelujah thank you for drawing attention. I've fixed the example. – Albert Tugushev Jun 04 '14 at 12:06
  • It works now. Thanks for your answer - it pointed me in the right direction. What I actually used is: `formfield_overrides = SuitedUpAdmin.formfield_overrides.copy()`, and then `formfield_overrides.update(...)` - two lines instead of a single statement, but I think it's more readable. – ksadowski Jun 04 '14 at 12:59
1

You could use an @property to access the attribute of super (I have not tried this under Django admin, but pure Python example works fine):

class SuperAttributes(object):
    formfield_overrides = {
        'field.Something': 'overrides'
    }


class ChildAttributes(SuperAttributes):
    @property
    def formfield_overrides(self):
        attrs = super(ChildAttributes, self).formfield_overrides
        attrs['field.SomethingElse'] = 'overrides'
        return attrs


child = ChildAttributes()
print child.formfield_overrides

EDIT: More Pythonic inherited class

class ChildAttributes(SuperAttributes):
    @property
    def formfield_overrides(self):
        attrs = super(ChildAttributes, self).formfield_overrides
        attrs.update({
            'field.SomethingElse': 'overrides'
        })
        return attrs
  • That's very interesting. I'd rather avoid an overhead of calling a method every time I need the value of the property, byt thanks for teaching me about that `@property` decorator. – ksadowski Jun 04 '14 at 11:09
  • @Hellelujah the issue is that you can not assign the return of `.update()` since `.update()` does not return dictionary itself. – Sumit Datta Jun 04 '14 at 11:30
  • Yeah, I realize that - at the moment, in my `LocationAdmin`, I did `formfield_overrides = SuitedUpAdmin.formfield_overrides.copy()` and then `formfield_overrides.update(...)`. It isn't as flexible as I'd like it to be (why doesn't `super` work here?!), but it is a fair compromise for me between elegance and performance. But that's my opinion - what do you think? – ksadowski Jun 04 '14 at 12:07
  • But how did you do `.copy()` and `.update()` in a class attribute assignment statement? I am confused :| @Hellelujah – Sumit Datta Jun 04 '14 at 12:16
  • I did exactly what i've written in the previous comment. Try it yourself: http://repl.it/TbX – ksadowski Jun 04 '14 at 12:51