""" 此文件作为 `django.db.models` 的 shortcut 这样做的优点与缺点为: 优点: - 包命名都统一为 `models` - 用户在使用的时候只导入本文件即可 缺点: - 此文件中添加代码的时候,注意不要跟 `django.db.models` 中的命名冲突 """ import uuid from django.db.models import * from django.db.models.functions import Concat from django.utils.translation import ugettext_lazy as _ class Choice(str): def __new__(cls, value, label=''): # `deepcopy` 的时候不会传 `label` self = super().__new__(cls, value) self.label = label return self class ChoiceSetType(type): def __new__(cls, name, bases, attrs): _choices = [] collected = set() new_attrs = {} for k, v in attrs.items(): if isinstance(v, tuple): v = Choice(*v) assert v not in collected, 'Cannot be defined repeatedly' _choices.append(v) collected.add(v) new_attrs[k] = v for base in bases: if hasattr(base, '_choices'): for c in base._choices: if c not in collected: _choices.append(c) collected.add(c) new_attrs['_choices'] = _choices new_attrs['_choices_dict'] = {c: c.label for c in _choices} return type.__new__(cls, name, bases, new_attrs) def __contains__(self, item): return self._choices_dict.__contains__(item) def __getitem__(self, item): return self._choices_dict.__getitem__(item) def get(self, item, default=None): return self._choices_dict.get(item, default) @property def choices(self): return [(c, c.label) for c in self._choices] class ChoiceSet(metaclass=ChoiceSetType): choices = None # 用于 Django Model 中的 choices 配置, 为了代码提示在此声明 class JMSBaseModel(Model): created_by = CharField(max_length=32, null=True, blank=True, verbose_name=_('Created by')) updated_by = CharField(max_length=32, null=True, blank=True, verbose_name=_('Updated by')) date_created = DateTimeField(auto_now_add=True, null=True, blank=True, verbose_name=_('Date created')) date_updated = DateTimeField(auto_now=True, verbose_name=_('Date updated')) class Meta: abstract = True class JMSModel(JMSBaseModel): id = UUIDField(default=uuid.uuid4, primary_key=True) class Meta: abstract = True def concated_display(name1, name2): return Concat(F(name1), Value('('), F(name2), Value(')'))