django: Migrating to Admin-newforms made easy

I have been a great admirer of simplicity of django. So I was rather disappointed when I saw the newforms-admin. Using newforms-admin requires more code, more named classes and more work :( . This is a simple comparison of how to use admin functionality before and after the changes.

Before

#file models.py
from django.db import models
class MyModel(models.Model):
      #field definitions
      class Admin:
            #admin options

Now

#file models.py
from django.db import models
class MyModel(models.Model):
      #field definitions
 
#file admin.py
from django.contrib import admin
from myapp.models import *
class MyModelAdmin(admin.ModelAdmin):
      #admin options
 
admin.site.register(MyModel, MyModelAdmin)

Migrating all of my django projects (having a large number of models) was a huge ask. So I started thinking, is there an easy way to migrate all of my django projects to newform-admin? As I started the migration manually, I identified the steps involved,

  1. for every model in models.py create an admin.ModelAdmin base class
  2. define admin options
  3. register the Model and ModelAdmin base classes

Looking at my code, I realized that 1,2 were almost already complete. The model classes already have an inner Admin class with all the options. The only thing required was to call admin.site.register properly. The logic is something like,

for every model in models.py
if model_class has Admin
      admin_class = create  subclass of admin.ModelAdmin
                    at run-time having all admin options
      admin.site.register(mode_class, admin_class)

 

But how to create a named subclass at run-time with unknown attributes?

This is where the type function comes into play. The common use of type is to check the datatype of an object. But if you look closely, you ll find that type can also be used as,

type(name, base, dict)
=>creates a class named name
=>with base classes base
=>and having attributes dict

After messing around with the code for about an hour, I came up with this.

from django.contrib import admin
from django.db import models
from django.contrib import admin
from django.db import models
 
for app in models.get_apps():
      for m in models.get_models(app):
            if hasattr(m, 'Admin'):
            try:
                  admin.site.register(m,
                        type('Admin' + m.__name__,
                              (admin.ModelAdmin,),
                              dict( [(a,getattr(m.Admin,a)) for a in dir(m.Admin)] )))
            except:
                  pass

The snippet iterates over all models of every installed app, checks if the model has an inner class Admin. If found, it creates an admin.ModelAdmin base class using the options from the inner class and names it by appending ‘Admin’ to model name. A try, except block is added to handle if there are any models already registered.

And thats it. I placed this code in admin.py of only one of my apps and I did not have to make any change in any of my apps (other than removing the unsupported options). This made my migration to newforms-admin a painless procedure. Until you feel like migrating manually, use this code to make life a little easier :)

Related posts:

  1. django: Hacking django object_list to take list of templates

Leave a Reply