5

I have a long list of 100 labels I need my model to have as fields and to also call in succession to access them in other parts of code. I am going to need to modify them in the future so I would like to be able to do it in one place. Is there a simple way to do this. For example:

labels = ['height', 'weight', 'age']

In models.py

class MyModel(models.Model):
    for label in labels:
        label = models.CharField(max_length=255)

Would the above be equal to :

class MyModel(models.Model):
    height = models.CharField(max_length=255)
    weight = models.CharField(max_length=255)
    age = models.CharField(max_length=255)
Red-Tune-84
  • 381
  • 6
  • 17
  • what does "to also call in succession to access them in other parts of code" mean? Does every model have 100 labels? How often are the labels changing? – dm03514 Jul 13 '14 at 18:20
  • 1
    https://code.djangoproject.com/wiki/DevModelCreation – dm03514 Jul 13 '14 at 18:21
  • So the one model will have 100 different fields then I want to be able to call all those fields. For example: [MyModel.field for field in labels]. – Red-Tune-84 Jul 13 '14 at 19:16
  • No, that code is not equivalent. Strings (fortunately) don't automatically convert to symbols – Eric Jul 13 '14 at 19:32
  • 1
    [Related](http://stackoverflow.com/questions/2265402/adding-class-attributes-using-a-for-loop-in-python) – Eric Jul 13 '14 at 21:21

2 Answers2

12

Django models have an add_to_class method which adds a field (or any attribute, really) to a class. The syntax is MyModel.add_to_class(name, value). The resulting code would be:

class MyModel(models.Model):
    pass

for label in labels:
    MyModel.add_to_class(label, models.CharField(max_length=255))

Internally, this will call the contribute_to_class method on the value passed, if that method exists. Static attributes are added to the class as-is, but fields have this method and all subsequent processing will ensue.

knbk
  • 52,111
  • 9
  • 124
  • 122
  • When would be the best time to call the for loop, not in the model class? In the models.py file? Won't that cause some problems with migrations? – Red-Tune-84 Jul 13 '14 at 23:26
  • @SimpleSyrup Just after the model definition. It won't cause problems with syncdb/migrations, as the model and its fields are fully defined after the class is imported. – knbk Jul 13 '14 at 23:28
  • I see. Since python looks at the entire file. Thanks for the tips. This solved my dilema. – Red-Tune-84 Jul 13 '14 at 23:42
  • Is this considered the most "Pythonic" way to write the code if a Model class contains 20+ attributes? – David Alford Oct 03 '19 at 00:08
4

Using locals() should work here:

class MyModel(models.Model):
    for label in labels:
        locals()[label] = models.CharField(max_length=255)

    del locals()['label']
Eric
  • 95,302
  • 53
  • 242
  • 374
  • So this is python. making label a local variable for the class. Right? – Red-Tune-84 Jul 13 '14 at 19:48
  • Oops, it'll actually be exposed as a property at `MyClass.label`. You'll want to add a `del locals()['label']` after that loop to prevent that – Eric Jul 13 '14 at 20:30
  • I don't understand after the entire loop or in the loop? Wouldn't I want it exposed as that is the behavior that django has by default? Or would it actually try to pull it from the class as opposed to the db? – Red-Tune-84 Jul 13 '14 at 20:34
  • Without that delete, `MyModel.label == 'age'`, which is not useful to anyone – Eric Jul 13 '14 at 21:23