Django:固定长度的CharField,如何?


75

我希望模型中具有固定长度的CharField。换句话说,我希望仅指定的长度有效。

我试图做类似的事情

volumenumber = models.CharField('Volume Number', max_length=4, min_length=4)

但这给了我一个错误(似乎我可以同时使用max_length和min_length)。

还有另一种快速方法吗?

谢谢

编辑:

遵循一些人的建议,我会更具体一些:

我的模型是这样的:

class Volume(models.Model):
    vid = models.AutoField(primary_key=True)
    jid = models.ForeignKey(Journals, db_column='jid', null=True, verbose_name = "Journal")
    volumenumber = models.CharField('Volume Number')
    date_publication = models.CharField('Date of Publication', max_length=6, blank=True)
    class Meta:
        db_table = u'volume'
        verbose_name = "Volume"
        ordering = ['jid', 'volumenumber']
        unique_together = ('jid', 'volumenumber')
    def __unicode__(self):
        return (str(self.jid) + ' - ' + str(self.volumenumber))

我想要的是volumenumber必须完全是4个字符。

如果有人插入“ 4b” django,则IE会给出错误,因为它期望包含4个字符的字符串。

所以我尝试了

volumenumber = models.CharField('Volume Number', max_length=4, min_length=4)

但这给了我这个错误:

Validating models...
Unhandled exception in thread started by <function inner_run at 0x70feb0>
Traceback (most recent call last):
  File "/Library/Python/2.5/site-packages/django/core/management/commands/runserver.py", line 48, in inner_run
    self.validate(display_num_errors=True)
  File "/Library/Python/2.5/site-packages/django/core/management/base.py", line 249, in validate
    num_errors = get_validation_errors(s, app)
  File "/Library/Python/2.5/site-packages/django/core/management/validation.py", line 28, in get_validation_errors
    for (app_name, error) in get_app_errors().items():
  File "/Library/Python/2.5/site-packages/django/db/models/loading.py", line 131, in get_app_errors
    self._populate()
  File "/Library/Python/2.5/site-packages/django/db/models/loading.py", line 58, in _populate
    self.load_app(app_name, True)
  File "/Library/Python/2.5/site-packages/django/db/models/loading.py", line 74, in load_app
    models = import_module('.models', app_name)
  File "/Library/Python/2.5/site-packages/django/utils/importlib.py", line 35, in import_module
    __import__(name)
  File "/Users/Giovanni/src/djangoTestSite/../djangoTestSite/journaldb/models.py", line 120, in <module>
    class Volume(models.Model):
  File "/Users/Giovanni/src/djangoTestSite/../djangoTestSite/journaldb/models.py", line 123, in Volume
    volumenumber = models.CharField('Volume Number', max_length=4, min_length=4)
TypeError: __init__() got an unexpected keyword argument 'min_length'

如果仅使用“ max_length”或“ min_length”,则显然不会出现。

我在django网站上阅读了文档,看来我是对的(我不能同时使用两者),所以我在问是否有另一种方法可以解决问题。

再次感谢

Answers:


46

CharField数据库模型字段实例仅具有一个max_length参数,如docs中所示。这可能是因为SQL中只有一个最大字符长度约束。

另一方面,表单字段CharField对象确实具有min_length参数。因此,您必须为此特定模型编写一个自定义ModelForm,并用该自定义模型覆盖默认的管理模型表单。

像这样:

# admin.py

from django import forms

...

class VolumeForm(forms.ModelForm):
    volumenumber = forms.CharField(max_length=4, min_length=4)

    class Meta:
        model = Volume


class VolumeAdmin(admin.ModelAdmin):
    form = VolumeForm

...

admin.site.register(Volume, VolumeAdmin)

8
或者,您可以编写一个自定义验证程序,如果长度不为4,则抛出ValidationError-这样,即使数据库未使用VolumeForm,数据库也永远不会包含错误的长度:docs.djangoproject.com/en/dev / REF /模型/实例/ ...

它将生成varchar,而不是char(在mysql中)。固定char比varchar快。
斯瓦沃米尔Lenart

89

您甚至不必编写自定义代码。只需使用RegexValidatorDjango提供的即可。

from django.core.validators import RegexValidator

class MyModel(models.Model):
    myfield = models.CharField(validators=[RegexValidator(regex='^.{4}$', message='Length has to be 4', code='nomatch')])

从Django文档中: class RegexValidator(\[regex=None, message=None, code=None\])

regex:要匹配的有效正则表达式。有关Python正则表达式的更多信息,请查看此出色的HowTo:http : //docs.python.org/howto/regex.html

message:如果失败,消息将返回给用户。

code:ValidationError返回的错误代码。对于您的用例而言并不重要,可以将其省略。

请注意,我建议的正则表达式将允许任何字符,包括空格。要仅允许使用字母数字字符,请用“。”代替。在正则表达式参数中带有“ \ w”。对于其他要求,请阅读TheDocs;)。


7
首选此方法,而不是接受的答案,因为即使用户未使用VolumeForm,它也可以确保正确的长度

@tBuLi我试图只允许数字并将正则表达式更改为^ \ d {5} $,但它不起作用。我可以保存任何字符为MyModel(MyField的= 'idsj是')模型保存()。
达尼尔Mashkin

1
仅允许字母数字使用:regex ='^ \ w + $'
M Haziq,

77

类似于上面的方法,但是值得的是,您还可以继续使用django提供的MinLengthValidator。为我工作。代码看起来像这样:

from django.core.validators import MinLengthValidator
...
class Volume(models.Model):
volumenumber = models.CharField('Volume Number', max_length=4, validators=[MinLengthValidator(4)])
...


16

您可以按照@Ben的建议编写自定义验证程序。截至本答案发布之日,有关说明,请访问https://docs.djangoproject.com/en/dev/ref/validators/

该代码将是这样的(从链接中复制):

from django.core.exceptions import ValidationError

def validate_length(value,length=6):
    if len(str(value))!=length:
        raise ValidationError(u'%s is not the correct length' % value)

from django.db import models

class MyModel(models.Model):
    constraint_length_charField = models.CharField(validators=[validate_length])

1
无需实现您的自定义最小长度验证器用法:from django.core.validators import MinLengthValidator
Pran Kumar Sarkar

0

使用自定义模型字段的另一种实现:

from django.core.validators import BaseValidator
from django.db import models
from django.utils.deconstruct import deconstructible


@deconstructible
class FixedLengthValidator(BaseValidator):
    message = 'Ensure this value has %(limit_value)d character (it has %(show_value)d).'
    code = 'length'

    def compare(self, a, b):
        return a != b

    def clean(self, x):
        return len(x)


class FixedLengthCharField(models.CharField):
    def __init__(self, *args, length, **kwargs):
        self.length = length
        kwargs['max_length'] = length
        super().__init__(*args, **kwargs)
        self.validators.insert(0, FixedLengthValidator(length))

    def deconstruct(self):
        name, path, args, kwargs = super().deconstruct()
        del kwargs['max_length']
        kwargs['length'] = self.length
        return name, path, args, kwargs
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.