【问题标题】:CharField with fixed length, how?CharField 具有固定长度,如何?
【发布时间】:2011-01-29 01:41:24
【问题描述】:

我希望在我的模型中有一个固定长度的 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 个字符。

I.E. 如果有人插入 '4b' django 会给出错误,因为它需要一个 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 网站上的文档,看来我是对的(我不能同时使用两者)所以我想问是否有另一种方法来解决这个问题。

【问题讨论】:

    标签: django


    【解决方案1】:

    您甚至不必编写自定义的。只需使用 Django 提供的RegexValidator

    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'。对于其他要求,ReadTheDocs ;)。

    【讨论】:

    • 比接受的答案更喜欢这个,因为即使用户没有使用 VolumeForm,它也能确保正确的长度
    • @tBuLi 我试图只允许数字并将正则表达式更改为 ^\d{5}$ 但它不起作用。我可以用任何字符保存模型 MyModel(myfield='idsj is').save()
    • 只允许使用字母数字:regex='^\w+$'
    【解决方案2】:

    类似于上面的路线,但对于它的价值,你也可以继续使用 django 提供的 MinLengthValidator。为我工作。代码看起来像这样:

    from django.core.validators import MinLengthValidator
    ...
    class Volume(models.Model):
    volumenumber = models.CharField('Volume Number', max_length=4, validators=[MinLengthValidator(4)])
    ...
    
    【解决方案3】:

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

    另一方面,Form Field 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)
    

    【讨论】:

    • 另外,您可以编写一个自定义验证器,如果长度不是 4,则抛出 ValidationError - 这样,数据库将永远不会包含不正确的长度,即使它们没有使用您的 VolumeForm:@ 987654323@
    • 它将生成 varchar,而不是 char(在 mysql 风格中)。 Fixed char 比 varchar 快。
    【解决方案4】:

    您可以按照@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])
    

    【讨论】:

    • 无需实现您的自定义最小长度验证器使用:from django.core.validators import MinLengthValidator
    • 感谢 Pran Kumar Sarkar。小的和最好的答案。无需自定义验证器。
    【解决方案5】:

    另一个使用custom model field的实现:

    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
    

    【讨论】:

      猜你喜欢
      • 2020-04-20
      • 2023-03-03
      • 1970-01-01
      • 1970-01-01
      • 2017-04-13
      • 2017-08-10
      • 2016-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多