Django: CharField з фіксованою довжиною, як?


76

Я хотів би мати в своїй моделі 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 символи.

IE, якщо хтось вставить django '4b', видасть помилку, оскільки він очікує рядок з 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 і, схоже, маю рацію (я не можу використовувати обидва разом), тому я запитую, чи є інший спосіб вирішити проблему.

Знову дякую

Відповіді:


46

Екземпляри полів моделі бази даних CharField мають лише max_lengthпараметр, як зазначено в документах . Це, мабуть, тому, що в 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
Крім того, ви можете написати власний валідатор, який видає ValidationError, якщо довжина не 4 - таким чином, база даних ніколи не міститиме неправильної довжини, навіть якщо вони не використовують вашу VolumeForm: docs.djangoproject.com/en/dev / ref / models / instances /…
Бен,

він буде генерувати varchar, а не char (у ароматі mysql). Фіксований символ швидший, ніж varchar.
Славомір Ленарт

89

Вам навіть не потрібно писати власний. Просто використовуйте те, RegexValidatorщо постачає Django.

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' в аргументі регулярного виразу. Інші вимоги читайте у TheTheDocs;).


7
віддайте перевагу цьому прийнятій відповіді, оскільки це забезпечує правильну довжину, навіть якщо користувач не використовує VolumeForm

@tBuLi Я намагаюся дозволити лише цифри і змінив регулярний вираз на ^ \ d {5} $, але це не працює. Я можу зберегти модель будь-якими символами MyModel (myfield = 'idsj is'). Save ()
Даниїл Машкін

1
для дозволити лише буквено-цифрове використання: regex = '^ \ w + $'
M Haziq

78

Начебто в тому ж напрямку, що і вище, але для того, що це варто, ви також можете продовжувати MinLengthValidator, який постачає django. Працював у мене. Код буде виглядати приблизно так:

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

3
Правильна відповідь! docs.djangoproject.com/en/1.11/ref/validators/…
Raptor

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
Пран Кумар Саркар

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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.