Автоматически добавлять константы для каждого из вариантов в модели Django - PullRequest
5 голосов
/ 23 февраля 2011

Я постоянно делаю следующий шаблон в 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)

Есть ли хороший шаблон, которому следуют другие люди, который достигает того же эффекта (т.е. у меня есть доступ к константам с именами и словарями, которые идутв обе стороны) без такого большого количества кода?

Ответы [ 3 ]

5 голосов
/ 23 февраля 2011

Библиотека Карла Мейера django-model-utils имеет отличное решение для этого - класс Choices, который позволяет объявлять список вариантов с доступом через удобочитаемые атрибуты.

0 голосов
/ 14 сентября 2011

У меня был такой же зуд, и вот что я написал:

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

Оттуда вы можете переписать MyModel как:

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

    blah = models.IntegerField(choices = BLAH_CHOICES)

И автоматически иметь все константысоздан для вас в модели.Из оболочки Джанго:

>>> MyModel.BLAH_FOODALLY_BOOGALY
1
>>> MyModel.BLAH_GOO_GOO_GAA_GAA
3
0 голосов
/ 23 февраля 2011

Это самый компактный способ инициализации ваших констант:

# 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

В любом случае я обычно набираю const.py и сохраняю там все безумие (просто глядя на тот, который равен 98строк), но определенно выведите их из класса модели и сделайте их частью данных модуля для экономии времени и памяти, если только вы не делаете что-то динамическое.

В противном случае вы делаете это примерно так же хорошо, как и выможет получить.Я также делаю BLAH_TYPES, чтобы соответствовать структуре выбора Django, которую каждый разработчик привык к чтению.Это часть, которую вы не можете избежать и не можете сделать какие-либо ярлыки.И если мне нужны эти преобразования, такие как ID_FOR_TYPE, я просто определяю их прямо под выбором.Читаемый, чистый и компактный.

...