dot*_*dot 2 python django django-models
我在Django中有以下模型:
class Cast(TimeStampedModel):
user = models.ForeignKey(User, unique=True)
count = models.PositiveIntegerField(default=1)
kind = models.CharField(max_length = 7)
def __str__(self):
return(f"{self.kind} || {self.count} || {self.modified.strftime('%x')}")
Run Code Online (Sandbox Code Playgroud)
但我希望“种类”字段仅采用以下值之一:上,下,奇怪,魅力,顶部或底部。如何在数据库中强制执行此操作,或者仅在导入数据时才能在视图中强制执行此操作?
我认为选择应该做什么?
class Cast(TimeStampedModel):
user = models.ForeignKey(User, unique=True)
count = models.PositiveIntegerField(default=1)
kind = models.CharField(
max_length=7,
choices=(
("up", "Up"),
("down", "Down"),
("strange", "Strange"),
("charm", "Charm"),
("top", "Top"),
("bottom", "Bottom")
)
)
Run Code Online (Sandbox Code Playgroud)
尽管在很多情况下我已经看到它用作SmallInteger来节省数据库空间:在DB中,您存储一个数字,在Admin区域中,您会看到一个下拉菜单,其中包含“人类友好”选项。
kind = models.PositiveSmallIntegerField(
choices=(
(1, "Up"),
(2, "Down"),
(3, "Strange"),
(4, "Charm"),
(5, "Top"),
(6, "Bottom")
)
)
Run Code Online (Sandbox Code Playgroud)
看到:
这不是在数据库级别强制执行的(请参阅此故障单和此SO问题),这意味着您仍然可以执行以下操作:
>>> c = Cast.objects.first()
>>> c.kind = 70
>>> c.save()
Run Code Online (Sandbox Code Playgroud)
但它是在管理员中强制执行的。如果您需要在较低级别实施它,建议您使用Noah Lc的答案。据我了解,这不是100%强制执行的:您仍然可以执行不通过.save()模型方法进行的批量更新,这意味着这样做Cast.objects.all().update(kind=70)仍然会70在kind字段中设置无效值(),但是他的解决方案是,的确比选择“低”了一步。您将无法进行通过.save()实例方法进行的模型更新。意思是,您将不允许这样做:
>>> c=Cast.objects.first()
>>> c.kind=70
>>> c.save()
Run Code Online (Sandbox Code Playgroud)
如果确实需要实施REAL数据库,则需要实际检查数据库的可能性并在cast.kind列上添加约束。
例如,对于Postgres(可能还有其他大多数SQL风格),您可以创建一个执行此操作的新迁移:
from django.db import migrations
def add_kind_constraint(apps, schema_editor):
table = apps.get_model('stackoverflow', 'Cast')._meta.db_table
schema_editor.execute("ALTER TABLE %s ADD CONSTRAINT check_cast_kind"
" CHECK (kind IN (1, 2, 3, 4, 5, 6) )" % table)
def remove_kind_constraint(apps, schema_editor):
table = apps.get_model('stackoverflow', 'Cast')._meta.db_table
schema_editor.execute("ALTER TABLE %s DROP CONSTRAINT check_cast_kind" % table)
class Migration(migrations.Migration):
dependencies = [
('stackoverflow', '0003_auto_20171231_0526'),
]
operations = [
migrations.RunPython(add_kind_constraint, reverse_code=remove_kind_constraint)
]
Run Code Online (Sandbox Code Playgroud)
然后,是的...您将获得100%的安全保护(检查不取决于Django:现在已由您的数据库引擎掌握):
>>> c = Cast.objects.all().update(kind=70)
django.db.utils.IntegrityError: new row for relation "stackoverflow_cast" violates check constraint "check_cast_kind"
DETAIL: Failing row contains (2, 1, 70, 1).
Run Code Online (Sandbox Code Playgroud)