我在这里阅读教程:https://docs.djangoproject.com/en/1.5/ref/models/fields/#choices 我正在尝试创建一个框,用户可以选择他出生的月份。我尝试过的是
MONTH_CHOICES = (
(JANUARY, "January"),
(FEBRUARY, "February"),
(MARCH, "March"),
....
(DECEMBER, "December"),
)
month = CharField(max_length=9,
choices=MONTHS_CHOICES,
default=JANUARY)
这是对的吗?我看到在我正在阅读的教程中,他们出于某种原因首先创建变量,就像这样
FRESHMAN = 'FR'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'
他们为什么要创建这些变量?此外,MONTHS_CHOICES在一个名为People的模型中,因此我提供的代码会在数据库中创建一个名为“People”的“Months Choices”列,并且它会说明用户在点击几个月后出生的月份并提交表格?
答案 0 :(得分:85)
我认为没有人真正回答过第一个问题:
他们为什么要创建这些变量?
这些变量并非绝对必要。这是真的。你可以完美地做这样的事情:
apply plugin: 'com.android.application'
android {
compileSdkVersion 22
buildToolsVersion "22.0.1"
defaultConfig {
applicationId "com..."
minSdkVersion 15
targetSdkVersion 22
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.android.support:appcompat-v7:22.+'
}
为什么使用变量更好?错误预防和逻辑分离。
MONTH_CHOICES = (
("JANUARY", "January"),
("FEBRUARY", "February"),
("MARCH", "March"),
# ....
("DECEMBER", "December"),
)
month = models.CharField(max_length=9,
choices=MONTH_CHOICES,
default="JANUARY")
现在,假设您有一个视图,您可以在其中创建新的Model实例。而不是这样做:
JAN = "JANUARY"
FEB = "FEBRUARY"
MAR = "MAR"
# (...)
MONTH_CHOICES = (
(JAN, "January"),
(FEB, "February"),
(MAR, "March"),
# ....
(DEC, "December"),
)
你会这样做:
new_instance = MyModel(month='JANUARY')
在第一个选项中,您正在对该值进行硬编码。如果您可以输入一组值,则应在编码时限制这些选项。 此外,如果您最终需要更改Model层的代码,现在您无需在Views层中进行任何更改。
答案 1 :(得分:27)
Field.choices
由其组成的可迭代(例如,列表或元组) 恰好两个项目的迭代(例如[(A,B),(A,B)......])用作 这个领域的选择。如果给出了这个,那么默认表单小部件将会 是一个带有这些选项的选择框,而不是标准文本字段。
每个元组中的第一个元素是要存储的实际值,和 第二个元素是人类可读的名称。
因此,您的代码是正确的,除了您应该定义变量JANUARY
,FEBRUARY
等,或使用calendar
模块来定义MONTH_CHOICES
:
import calendar
...
class MyModel(models.Model):
...
MONTH_CHOICES = [(str(i), calendar.month_name[i]) for i in range(1,13)]
month = CharField(max_length=9, choices=MONTHS_CHOICES, default='1')
答案 2 :(得分:3)
您不能在代码中使用单词,这就是他们创建变量的原因(您的代码将失败并显示NameError
)。
您提供的代码将创建一个名为month
的数据库表(加上django添加的任何前缀),因为这是CharField
的名称。
但是有更好的方法来创建你想要的特定选择。请参阅a previous Stack Overflow question。
import calendar
tuple((m, m) for m in calendar.month_name[1:])
答案 3 :(得分:2)
最干净的解决方案是使用django-model-utils
库:
from model_utils import Choices
class Article(models.Model):
STATUS = Choices('draft', 'published')
status = models.CharField(choices=STATUS, default=STATUS.draft, max_length=20)
https://django-model-utils.readthedocs.io/en/latest/utilities.html#choices
答案 4 :(得分:1)
我建议使用django-model-utils而不是Django内置解决方案。 此解决方案的主要优点是缺少字符串声明重复。所有选择项都只声明一次。这也是使用3个值声明选择并存储与源代码中用法不同的数据库值的最简单方法。
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
class MyModel(models.Model):
MONTH = Choices(
('JAN', _('January')),
('FEB', _('February')),
('MAR', _('March')),
)
# [..]
month = models.CharField(
max_length=3,
choices=MONTH,
default=MONTH.JAN,
)
使用IntegerField代替:
from django.utils.translation import ugettext_lazy as _
from model_utils import Choices
class MyModel(models.Model):
MONTH = Choices(
(1, 'JAN', _('January')),
(2, 'FEB', _('February')),
(3, 'MAR', _('March')),
)
# [..]
month = models.PositiveSmallIntegerField(
choices=MONTH,
default=MONTH.JAN,
)
答案 5 :(得分:1)
对于Django3.0 +,请使用from django.db.models import CharField, Model, TextChoices
class MyModel(Model):
class MonthChoices(TextChoices):
JAN = '1', "JANUARY"
FEB = '2', "FEBRUARY"
MAR = '3', "MAR"
# (...)
month = CharField(max_length=2,
choices=MonthChoices,
default=MonthChoices.JAN)
<Field
component={MyComponent}
defaultValue="my value from database"
name="name"
/>
答案 6 :(得分:1)
对于那些感兴趣的人,我创建了django-better-choices
库,该库提供了一个不错的界面来处理python 3.7+的Django选择。它支持自定义参数,许多有用的功能,并且对IDE非常友好。
您可以将选择定义为类:
from django_better_choices import Choices
class PAGE_STATUS(Choices):
CREATED = 'Created'
PENDING = Choices.Value('Pending', help_text='This set status to pending')
ON_HOLD = Choices.Value('On Hold', value='custom_on_hold')
VALID = Choices.Subset('CREATED', 'ON_HOLD')
class INTERNAL_STATUS(Choices):
REVIEW = 'On Review'
@classmethod
def get_help_text(cls):
return tuple(
value.help_text
for value in cls.values()
if hasattr(value, 'help_text')
)
然后执行以下操作,并执行更多操作:
print( PAGE_STATUS.CREATED ) # 'created'
print( PAGE_STATUS.ON_HOLD ) # 'custom_on_hold'
print( PAGE_STATUS.PENDING.display ) # 'Pending'
print( PAGE_STATUS.PENDING.help_text ) # 'This set status to pending'
'custom_on_hold' in PAGE_STATUS.VALID # True
PAGE_STATUS.CREATED in PAGE_STATUS.VALID # True
PAGE_STATUS.extract('CREATED', 'ON_HOLD') # ~= PAGE_STATUS.VALID
for value, display in PAGE_STATUS:
print( value, display )
PAGE_STATUS.get_help_text()
PAGE_STATUS.VALID.get_help_text()
当然,Django和Django Migrations完全支持它:
class Page(models.Model):
status = models.CharField(choices=PAGE_STATUS, default=PAGE_STATUS.CREATED)