2011-02-23 11 views
5

Estoy constantemente haciendo lo siguiente patrón en Django:agregar automáticamente las constantes para cada una de las opciones en un modelo de Django

class MyModel(models.Model): 

    FOO = 1 
    BAR = 2 
    GOO = 3 

    BLAH_TYPES = (
     (FOO, 'Foodally boogaly'), 
     (BAR, 'Bar bar bar bar'), 
     (GOO, 'Goo goo gaa gaa'), 
    ) 

    TYPE_FOR_ID = dict(BLAH_TYPES) 

    ID_FOR_TYPE = dict(zip(TYPE_FOR_ID.values(), TYPE_FOR_ID.keys())) 

    blah = models.IntegerField(choices=BLAH_TYPES) 

¿Hay un buen patrón que siguen otras personas que se consiga el mismo efecto (es decir, I tener acceso a constantes con nombres y diccionarios que van en ambos sentidos) sin tanto código?

Respuesta

5

La biblioteca de Carl Meyer django-model-utils tiene una excelente solución para esto: la clase Choices, que le permite declarar una lista de opciones con acceso a través de atributos legibles por el ser humano.

0

Se trata de la forma más compacta para inicializar sus constantes:

# foobar choices constants 
FOO, BAR, BAZ = range(3) 

# bebop choices constants (if you prefer this to readability) 
(BUU, 
BAA, 
DII, 
DUU) = range(4) 

# then, in a galaxy far away, much to your expectations: 
>> FOO 
0 
>> DII 
2 

En cualquier caso, por lo general preparar una const.py y mantener toda la locura de allí (sólo mirar a uno que es 98 líneas de largo) , pero definitivamente los aleje de la clase de modelo y conviértalos en parte de los datos del módulo para ahorrar tiempo y memoria, a menos que haga algo dinámico.

De lo contrario, lo hará tan bien como sea posible. También hago un BLAH_TYPES, para cumplir con la estructura de opciones de Django que todo desarrollador está acostumbrado a leer. Eso es parte de lo que no puedes evitar y no puedes hacer atajos. Y, si necesito esas transformaciones, como ID_FOR_TYPE, simplemente las defino justo debajo de las opciones. Legible, limpio y compacto.

0

que tenían el mismo picor, y eso es lo que escribí:

from django.db import models 
from django.db.models.base import ModelBase 
import re 

class ModelBaseWithChoices(ModelBase): 
    def __new__(cls, name, bases, attrs): 
     def format_label(label): 
      return re.sub('[^A-Z]+', '_', label.upper()).strip('_') 

     def get_choices(attrs): 
      for attr, value in attrs.items(): 
       if attr.endswith('_CHOICES') and isinstance(value, tuple): 
        base = '_'.join(attr.split('_')[:-1]) 
        for val, label in value: 
         yield '_'.join((base, format_label(label))), val 

     attrs.update(list(get_choices(attrs))) 
     return super(ModelBaseWithChoices, cls).__new__(cls, name, bases, attrs) 

class ModelWithChoices(models.Model): 
    __metaclass__ = ModelBaseWithChoices 

    class Meta: 
     abstract = True 

A partir de ahí, se puede reescribir MyModel como:

class MyModel(ModelWithChoices): 
    BLAH_CHOICES = ((1, 'Foodally boogaly'), 
        (2, 'Bar bar bar bar'), 
        (3, 'Goo goo gaa gaa')) 

    blah = models.IntegerField(choices = BLAH_CHOICES) 

y tienen todas las constantes creadas automáticamente para usted en el modelo. Desde el shell de Django:

>>> MyModel.BLAH_FOODALLY_BOOGALY 
1 
>>> MyModel.BLAH_GOO_GOO_GAA_GAA 
3 
Cuestiones relacionadas