Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python&;Django常数_Python_Django - Fatal编程技术网

Python&;Django常数

Python&;Django常数,python,django,Python,Django,我有一个依赖于元组的Django模型。我想知道在Django程序中引用该元组中的常量的最佳实践是什么。例如,在这里,我想将“default=0”指定为更具可读性且不需要注释的内容。有什么建议吗 Status = ( (-1, 'Cancelled'), (0, 'Requires attention'), (1, 'Work in progress'), (2, 'Complete'), ) class Task(models.Model): statu

我有一个依赖于元组的Django模型。我想知道在Django程序中引用该元组中的常量的最佳实践是什么。例如,在这里,我想将“
default=0
”指定为更具可读性且不需要注释的内容。有什么建议吗

Status = (
    (-1, 'Cancelled'),
    (0, 'Requires attention'),
    (1, 'Work in progress'),
    (2, 'Complete'),
)

class Task(models.Model):
    status = models.IntegerField(choices=Status, default=0) # Status is 'Requires attention' (0) by default.
编辑:


如果可能的话,我想避免完全使用数字。以某种方式使用字符串“Required attention”会更具可读性。

您可以使用字典来提高清晰度:

Status = {
    -1: 'Cancelled',
    0: 'Requires attention',
    1: 'Work in progress',
    2: 'Complete',
}

class Task(models.Model):
    status = models.IntegerField(choices=Status.items(), default=Status[0])
我的做法:

class Task(models.Model):
    STATUSES = { 'cancelled': 'Cancelled',
                 'requires attention': 'Requires attention',
                 'work in progress': 'Work in progress',
                 'complete': 'Complete' }

    status = models.CharField(choices=STATUSES.items(), default='cancelled')
这允许您编写方便的表达式:

tasks = Task.objects.filter(status='complete')
此外,它允许您不创建不必要的全局变量

如果确实要使用整型字段:

class Task(models.Model):

   class STATUS:
      CANCELED, ATTENTION, WIP, COMPLETE = range(-1, 3)
      choices = {
        CANCELED: 'Cancelled',
        ATTENTION: 'Requires attention',
        WIP: 'Work in progress',
        COMPLETE: 'Complete'
      }


   status = models.CharField(choices=STATUSES.choices.items(), default=STATUSES.CANCELED)
以及:


请记住,正如其他人所指出的,正确的方法是放置这些变量 在你的模型课里面。官方的django也是这样做的

只有一个原因使您希望将其置于类命名空间之外 只有当这些语义被应用程序的其他模型平等地共享时,才能这样做。即 您无法决定它们属于哪个特定模型


尽管在您的特定示例中,情况似乎并非如此。

通常为整数值定义常量,如下所示:

class Task(models.Model):
    CANCELLED = -1
    REQUIRES_ATTENTION = 0
    WORK_IN_PROGRESS = 1
    COMPLETE = 2

    Status = (
        (CANCELLED, 'Cancelled'),
        (REQUIRES_ATTENTION, 'Requires attention'),
        (WORK_IN_PROGRESS, 'Work in progress'),
        (COMPLETE, 'Complete'),
    )

    status = models.IntegerField(choices=Status, default=REQUIRES_ATTENTION)
# in Python 3.4 or later:
import enum  

class Status(enum.IntEnum):
    Cancelled = -1,
    Requires_attention = 0,
    Work_in_progress = 1,
    Complete = 2

def choiceadapter(enumtype):
    return ((item.value, item.name.replace('_', ' ')) for item in enumtype)

class Task(models.Model):
    status = models.IntegerField(choices=choiceadapter(Status), 
                                 default=Status.Requires_attention.value)

通过在模型类中移动常量和
状态
,您可以保持模块的名称空间更干净,并且作为奖励,您可以引用
任务。在导入
任务
模型的任何位置完成

您可以使用
namedtuple
,对常量使用不可变似乎很合适。;-)


在本例中,将
任务
上的属性作为常量(如中)使用更有意义,但命名的元组是不改变的dict和对象的廉价替代品。特别是如果你想在内存中有很多的话,这是非常方便的。它们就像常规元组,具有描述性的
\uuuu repr\uuuu
和属性访问的额外功能。

我不使用Django,但我在金字塔和扭曲下做了如下类似的事情

def setup_mapping( pairs ):
    mapping = {'id':{},'name':{}}
    for (k,v) in pairs:
        mapping['id'][k]= v
        mapping['name'][v]= k
    return mapping

class ConstantsObject(object):
    _pairs= None
    mapping= None

    @classmethod
    def lookup_id( cls , id ):
       pass

    @classmethod
    def lookup_name( cls , name ):
       pass

class StatusConstants(ConstantsObject):
    CANCELLED = -1
    REQUIRES_ATTENTION = 0
    WORK_IN_PROGRESS = 1
    COMPLETE = 2

    _pairs= (
        (-1, 'Cancelled'),
        (0, 'Requires attention'),
        (1, 'Work in progress'),
        (2, 'Complete'),
    )
    mapping= setup_mapping(_pairs)
因此,其实质是:

  • 有一个基本的“常量”类,每种类型都有另一个类。该类将关键字定义为ALLCAPS中的值
  • 我也把明文
    \u对
    扔进了课堂。为什么?因为我可能需要用它们构建一些DB表,或者我可能希望它们用于错误/状态消息。我使用数字而不是ALLCAPS变量名作为个人偏好
    
  • 我初始化了一个
    映射
    类变量,它基本上是通过在一个dict中预编译一组变量来修补类,因为
  • 该类派生自该基类,该基类提供classmethod功能来搜索值或执行通常需要使用常量执行的其他标准操作
这不是一种一刀切的方法,但我通常都非常喜欢这种方法。您可以轻松地使用dict定义对,让“映射”函数设置一些其他属性,例如为您提供对值的元组,如k、v或v、k,或者您可能需要的任何奇怪格式

我的代码可以如下所示:

status_id = sa.Column(sa.Integer, sa.ForeignKey("_status.id") , nullable=False , default=constants.StatusConstants.CANCELLED )

status_name = constants.StatusConstants.lookup_id(status_id)    
status_name = constants.StatusConstants.mapping['id'][status_id]
def choices(labels):
    labels = labels.strip().split('\n')
    ids = range(1, len(labels)+1)
    return zip(ids, labels)
my_choices = """
choice1
choice2
choice3
"""
MY_CHOICES = choices(my_choices)
print(MY_CHOICES) # ((1, choice1), (2, choice2), (3, choice3))

当您需要以另一种方式使用常量时,只需添加或更改基的classmethods

有时我不得不创建一些巨大的选择列表。我不喜欢像猴子一样打字,所以我宁愿创建这样的函数:

status_id = sa.Column(sa.Integer, sa.ForeignKey("_status.id") , nullable=False , default=constants.StatusConstants.CANCELLED )

status_name = constants.StatusConstants.lookup_id(status_id)    
status_name = constants.StatusConstants.mapping['id'][status_id]
def choices(labels):
    labels = labels.strip().split('\n')
    ids = range(1, len(labels)+1)
    return zip(ids, labels)
my_choices = """
choice1
choice2
choice3
"""
MY_CHOICES = choices(my_choices)
print(MY_CHOICES) # ((1, choice1), (2, choice2), (3, choice3))
然后像这样使用:

status_id = sa.Column(sa.Integer, sa.ForeignKey("_status.id") , nullable=False , default=constants.StatusConstants.CANCELLED )

status_name = constants.StatusConstants.lookup_id(status_id)    
status_name = constants.StatusConstants.mapping['id'][status_id]
def choices(labels):
    labels = labels.strip().split('\n')
    ids = range(1, len(labels)+1)
    return zip(ids, labels)
my_choices = """
choice1
choice2
choice3
"""
MY_CHOICES = choices(my_choices)
print(MY_CHOICES) # ((1, choice1), (2, choice2), (3, choice3))
Python 3.4+:
Enum
你写“如果可能的话,我想避免使用数字。” 事实上,命名表示法显然更像蟒蛇。 然而,一个简单的字符串容易被输入错误

Python3.4引入了一个名为 提供
Enum
IntEnum
伪类 这有助于解决这种情况。 有了它,您的示例可以如下工作:

class Task(models.Model):
    CANCELLED = -1
    REQUIRES_ATTENTION = 0
    WORK_IN_PROGRESS = 1
    COMPLETE = 2

    Status = (
        (CANCELLED, 'Cancelled'),
        (REQUIRES_ATTENTION, 'Requires attention'),
        (WORK_IN_PROGRESS, 'Work in progress'),
        (COMPLETE, 'Complete'),
    )

    status = models.IntegerField(choices=Status, default=REQUIRES_ATTENTION)
# in Python 3.4 or later:
import enum  

class Status(enum.IntEnum):
    Cancelled = -1,
    Requires_attention = 0,
    Work_in_progress = 1,
    Complete = 2

def choiceadapter(enumtype):
    return ((item.value, item.name.replace('_', ' ')) for item in enumtype)

class Task(models.Model):
    status = models.IntegerField(choices=choiceadapter(Status), 
                                 default=Status.Requires_attention.value)
一旦Django团队拿起
Enum
choiceadapter
甚至将内置到Django中

编辑2021-06:在使用
Enum
进行了一些工作之后,我必须说我没有热情。
在我的工作风格中(在Django中,你的里程数可能会有所不同),抽象往往会妨碍我,我发现自己更喜欢松散的常量列表(通常嵌入到另一个存在的类中)。

一种可能的方法是将pythonrange函数与tuple结合使用

class Task(models.Model):
    CANCELED, ATTENTION, WIP, COMPLETE = range(-1, 3)
    Status = (
        (CANCELLED, 'Cancelled'),
        (REQUIRES_ATTENTION, 'Requires attention'),
        (WORK_IN_PROGRESS, 'Work in progress'),
        (COMPLETE, 'Complete'),
    )

    status = models.IntegerField(choices=Status, default=REQUIRES_ATTENTION)

Final
ly常量已通过

安装:

pip install mypy typing_extensions
用法示例:

from typing_extensions import Final

DAYS_IN_A_WEEK: Final = 7
DAYS_IN_A_WEEK = 8  # I really want more days in a week!
您需要运行mypy类型检查器:

mypy --python-version=3.6 --strict week.py
week.py:4: error: Cannot assign to final name "DAYS_IN_A_WEEK"

有关更多信息,请参见:

我认为这与简单地使用数值常量非常相似。在这种情况下,有没有办法将人类可读的上下文信息添加到“1”的含义中?有人怎么知道1意味着“正在工作”?我认为这与简单地使用数字常量非常相似。在这种情况下,有没有办法将人类可读的上下文信息添加到“1”的含义中?有人怎么知道1是“正在工作”的意思呢?投票表决结果是正确的,但我更喜欢将常量移动到类中,就像阿拉斯代尔的回答一样。@ChrisWesseling完全同意,只是不想偏离OP的示例代码。尽管它只在模型中使用,但有时将它们放在类之外是有用的。可能在一个常量文件中。我不得不这样做,以避免循环进口。要调用Task.cancelled,我必须导入它。由于它在许多地方被调用,而且模型变化非常快,如果我们在所有需要的文件中导入任务,就有可能进行循环导入。如果您需要进一步的
[11:35-26:00]
,您是否阅读过这个使用
\uuuuu元类的有趣方法?还可以使用以下命令访问字符串表示:
def status\u str(self):return self.status[self.status][1]
@Alveoli django的基本模型为其中的每个字段提供“get\u fieldname\u display()”函数