В Django / Python, как после правильной проверки вставить данные поля в базу данных, отформатированную по желанию? - PullRequest
0 голосов
/ 14 февраля 2019

Я разрабатываю веб-систему с Django / Python, и мне нужно определенное поле из модели User: CPF (https://en.wikipedia.org/wiki/Cadastro_de_Pessoas_Físicas). Мне нужно это с валидатором и для правильного форматированияперед вставкой в ​​базу данных.

Я пытался использовать localflavor.br.forms.BRCPFField из django-localflavor и django-localflavor-br (https://django -localflavor.readthedocs.io / en / latest / localflavor /br / ), но makemigrations не может распознать новое поле, и migrate не может обновить соответствующую таблицу в базе данных (я думаю, что это ошибка, но пока это не проблема). Итак, после рассмотрениядругие варианты, я решил попробовать и написать свой собственный валидатор.

РЕДАКТИРОВАТЬ 1: Код исправлен, как указано в моем комментарии к ответу Даниэля.

В models.py:

from django.core.exceptions import ValidationError

def validate_cpf(cpf):
    digitos = [int(digit) for digit in cpf if digit.isdigit()]
    if len(digitos) < 11 or len(digitos) > 11:
        raise ValidationError("Wrong number of digits")
    sop = sum(a*b for a, b in zip(digitos[0:9], range(10, 1, -1)))
    ed1 = (sop * 10 % 11) % 10
    sop = sum(a*b for a, b in zip(digitos[0:10], range(11, 1, -1)))
    ed2 = (sop * 10 % 11) % 10
    if ed1 != digitos[9] or ed2 != digitos[10]:
        raise ValidationError("Verification digits don't match")
    else:
        numeros = ''.join(str(d) for d in digitos)
        return f'{numeros[0:3]}.{numeros[3:6]}.{numeros[6:9]}-{numeros[9:]}'

class Usuario(models.Model):
    name = models.CharField(max_length=256)
    cpf = models.CharField(max_length=14, validators=[validate_cpf])

В admin.py:

from .models import Usuario

class UsuarioAdmin(admin.ModelAdmin):
    fieldsets = [ ('ID', { 'fields': ['name', 'cpf', ], }), ]
    list_display = ('name', 'cpf', )

admin.site.register(Usuario, UsuarioAdmin)

В области администрирования (http://localhost:8000/admin/), я могу без проблем добавить нового пользователя.письменный валидатор также отлично работает:

  1. 23755124050 принято.
  2. 237.551.240-50 принято.
  3. +-*23755124050 илидопускается какая-либо другая мыслимая строка с этими 11 цифрами в данном конкретном порядке.
  4. 237.551.240-51 не принимается: («Контрольные цифры не совпадают»)
  5. 37.551.240-50 не принято: («Неверное количество цифр»)

Итак, валидатор работает нормально.

РЕДАКТИРОВАТЬ 2: Текст исправлен после первого редактирования.

Проблема в том, что когда я сохраняю его в базе данных, я хочу - независимо от регистра ввода (1) в (3) - сохранить в формате: f'{numeros[0:3]}.{numeros[3:6]}.{numeros[6:9]}-{numeros[9:]}'.Но база данных всегда сохраняет введенный текст как заданный до проверки (учитывая введенный текст как проверенный).Таким образом, +-*23755124050 сохраняется как есть, а не как 237.551.240-50, как я намереваюсь.

Это сложно для меня, я упускаю что-то важное в этом процессе.Кто-нибудь может просветить меня?

1 Ответ

0 голосов
/ 14 февраля 2019

Вместо использования валидатора вы должны использовать пользовательскую форму с методом clean_cpf;это несет двойную ответственность за проверку входных данных и возврат данных в той форме, в которой вы хотите их сохранить.(Обратите внимание, что внутри чистого метода вы должны поднять forms.ValidationError, а не core.exceptions.ValidationError).

class MyUsarioForm(forms.ModelForm):
    def clean_cpf(self):
        cpf = self.cleaned_data['cpf']
        digitos = [int(digit) for digit in cpf if digit.isdigit()]
        if len(digitos) < 11 or len(digitos) > 11:
            raise forms.ValidationError("Wrong number of digits")
        sop = sum(a*b for a, b in zip(digitos[0:9], range(10, 1, -1)))
        ed1 = (sop * 10 % 11) % 10
        sop = sum(a*b for a, b in zip(digitos[0:10], range(11, 1, -1)))
        ed2 = (sop * 10 % 11) % 10
        if ed1 != digitos[9] or ed2 != digitos[10]:
            raise forms.ValidationError("Verification digits don't match")
        else:
            return f'{digitos[0:2]}.{digitos[3:5]}.{digitos[6:8]}-{digitos[9:10]}'


class UsuarioAdmin(admin.ModelAdmin):
    form = UsarioForm
...