Alex Rivera | Logout

Programmatically specifying Django model attributes

Asked 2010-03-23T15:30:39.943
11

I would like to add attributes to a Django models programmatically. At class creation time (the time of the definition of the model class). The model is not going to change after that in run time. For instance, lets say I want to define a Car model class and want to add one price attribute (database column) per currency, given a list of currencies. (This list of currencies should be considered a constant that won't change runtime. I don't want a related model for these prices.)

What would be the best way to do this?

I had an approach that I thought would work, but it didn't exactly. This is how I tried doing it, using the car example above:

from django.db import models

class Car(models.Model):
    name = models.CharField(max_length=50)

currencies = ['EUR', 'USD']
for currency in currencies:
    Car.add_to_class('price_%s' % currency.lower(), models.IntegerField())

This does seem to work pretty well at first sight:

$ ./manage.py syncdb
Creating table shop_car

$ ./manage.py dbshell
shop=# \d shop_car
                                  Table "public.shop_car"
  Column   |         Type          |                       Modifiers                       
-----------+-----------------------+-------------------------------------------------------
 id        | integer               | not null default nextval('shop_car_id_seq'::regclass)
 name      | character varying(50) | not null
 price_eur | integer               | not null
 price_usd | integer               | not null
Indexes:
    "shop_car_pkey" PRIMARY KEY, btree (id)

But when I try to create a new Car, it doesn't really work anymore:

>>> from shop.models import Car
>>> mycar = Car(name='VW Jetta', price_eur=100, price_usd=130)
>>> mycar
<Car: Car object>
>>> mycar.save()
Traceback (most recent call last):
  File "<console>", line 1, in <modu
Edit
Report

1 Answer

2

"I would like to add attributes to a Django models programmatically. At class creation time"

Don't. "Programmatically" adding columns is silly and confusing. It seems fine to you -- the developer -- who deeply gets the nuances of Django.

For us, the maintainers, that code will (a) make no sense and (b) have to be replaced with simple, obvious code that does the same job the simplest most obvious way.

Remember, the maintainers are violent sociopaths who know where you live. Pander to them with simple and obvious code.

There's no reason to replace a cluster of simple attribute definitions with a tricky-looking loop. There's no improvement and no savings.

  1. The run-time performance of the view functions is the same.

  2. The one-time class-definition has saved a few lines of code that are executed once during application start-up.

  3. The development cost (i.e., solving this question) is higher.

  4. The maintenance cost (i.e., turning this code over to someone else to keep it running) is astronomically high. The code will simply be replaced with something simpler and more obvious.

Even if you have 100's of currencies, this is still a perfectly bad idea.

"I don't want a related model for these prices"

Why not? A related model is (1) simple, (2) obvious, (3) standard, (4) extensible. It has almost no measurable cost at run time or development time and certainly no complexity.

"For instance, lets say I have a Car model class and want to add one price attribute (database column) per currency, given a list of currencies."

That is not a new attribute at all.

That is a new value (in a row) of a table that has Car Model and Currency as the keys.

You class looks something like this:

class Price( models.Mod
answered 2010-03-23T15:38:23.400

Your Answer