Skip to content
Advertisement

Dynamically creating Django models with `type`

I have 20+ MySQL tables, prm_a, prm_b, … with the same basic structure but different names, and I’d like to associate them with Django model classes without writing each one by hand. So, feeling ambitious, I thought I’d try my hand at using type() as a class-factory:

The following works:

JavaScript

But if I try to generate the model classes as follows:

JavaScript

I get a curious Exception on the type() line (given that __module__ is, in fact, in the prm_class_attrs dictionary):

JavaScript

So I have two questions: what’s wrong with my second approach, and is this even the right way to go about creating my class models?

OK – thanks to @Anentropic, I see that the items in my prm_class_attrs dictionary are being popped away by Python when it makes the classes. And I now have it working, but only if I do this:

JavaScript

not if I set the Meta class as an attribtue with

JavaScript

I don’t really know why this is, but at least I have it working now.

Advertisement

Answer

The imediate reason is because you are not doing prm_class_attrs.copy() in your for loop, so the __modules__ key is getting popped out of the dict on the first iteration

As for why this doesn’t work:

setattr(prm_class, 'Meta', get_model_meta_class(prm_name))

…it’s to do with the fact that Django’s models.Model has a metaclass. But this is a Python metaclass which customises the creation of the model class and is nothing to do with the Meta inner-class of the Django model (which just provides ‘meta’ information about the model).

In fact, despite how it looks when you define the class in your models.py, the resulting class does not have a Meta attribute:

JavaScript

(You can access the Meta class directly, but aliased as MyModel._meta)

The model you define in models.py is really more of a template for a model class than the actual model class. This is why when you access a field attribute on a model instance you get the value of that field, not the field object itself.

Django model inheritance can simplify a bit what you’re doing:

JavaScript
User contributions licensed under: CC BY-SA
2 People found this is helpful
Advertisement