固定长度的 CharField,怎么做到的?

我希望在我的模型中有一个固定长度的 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 给出一个错误,因为它期望一个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 网站上的文档,似乎我是正确的(我不能同时使用两者) ,所以我问是否有其他方法来解决这个问题。

64025 次浏览

CharField database model field instances only have a max_length parameter, as indicated in the docs. This is probably because there is only a max character length contraint equivalent in SQL.

Form Field CharField objects, on the other hand, do have a min_length parameter. So you'd have to write a custom ModelForm for this specific model and override the default admin model form with the custom one.

Something like that:

# 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)

You can write a custom Validator as suggested by @Ben. As of the date of this answer the instructions for doing this can be found at https://docs.djangoproject.com/en/dev/ref/validators/

The code would be something like this (copying from the link):

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])

You don't even have to write a custom one. Just use the RegexValidator which Django supplies.

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')])

From the Django Docs: class RegexValidator(\[regex=None, message=None, code=None\])

regex: A valid regular expression to match. For more on regex in Python check this excellent HowTo: http://docs.python.org/howto/regex.html

message: The message returned to the user in case of failure.

code: error code returned by ValidationError. Not important for your usage case, you can leave it out.

Watch out, the regex suggested by me will allow any characters including whitespace. To allow only alphanumeric characters, substitute the '.' with '\w' in the regex argument. For other requirements, ReadTheDocs ;).

Kind of along the same lines as above, but for what it's worth you could also go ahead with MinLengthValidator which django supplies. Worked for me. The code would look something like this:

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

Yet another implementation using 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