在Django/Python中,如何在正确验证后,将字段数据插入到数据库中,并将其格式化为所需的格式?
In Django/Python, how to, after proper validation, insert a field data in the database formatted as desired?
我正在使用 Django/Python 开发一个 Web 系统,我需要来自用户模型的特定字段:CPF (https://en.wikipedia.org/wiki/Cadastro_de_Pessoas_Físicas)。我需要它与验证器并在插入数据库之前正确格式化。
我尝试使用 django-localflavor
和 django-localflavor-br
(https://django-localflavor.readthedocs.io/en/latest/localflavor/br/) 中的 localflavor.br.forms.BRCPFField
,但 makemigrations
也无法识别新字段migrate
可以更新数据库中相应的 table (我认为这是一个错误,但现在不是这个问题)。因此,在考虑了其他选择之后,我决定尝试一下并编写自己的验证器。
编辑 1: 代码已更正,如我对 Daniel 的回答的评论中所述。
在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/) 中,我可以毫无问题地添加新用户。书面验证器也可以正常工作:
23755124050
被接受。
237.551.240-50
被接受。
+-*23755124050
或其他一些可以想象的字符串,其中包含此特定顺序中的 11 位数字。
237.551.240-51
不被接受:("Verification digits don't match")
37.551.240-50
不被接受:("Wrong number of digits")
所以,验证器工作正常。
编辑 2: 文本在第一次编辑后更正。
问题是,当我将它保存到数据库中时,无论输入大小写 (1) 到 (3),我都希望将其格式保存为:f'{numeros[0:3]}.{numeros[3:6]}.{numeros[6:9]}-{numeros[9:]}'
。但是数据库总是保存验证前给定的输入文本(将输入文本视为已验证)。所以 +-*23755124050
按原样保存,而不是 237.551.240-50
我想要的方式。
这对我来说很棘手,我在这个过程中遗漏了一些重要的东西。有没有人能赐教一下?
与其使用验证器,不如使用带有 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
我正在使用 Django/Python 开发一个 Web 系统,我需要来自用户模型的特定字段:CPF (https://en.wikipedia.org/wiki/Cadastro_de_Pessoas_Físicas)。我需要它与验证器并在插入数据库之前正确格式化。
我尝试使用 django-localflavor
和 django-localflavor-br
(https://django-localflavor.readthedocs.io/en/latest/localflavor/br/) 中的 localflavor.br.forms.BRCPFField
,但 makemigrations
也无法识别新字段migrate
可以更新数据库中相应的 table (我认为这是一个错误,但现在不是这个问题)。因此,在考虑了其他选择之后,我决定尝试一下并编写自己的验证器。
编辑 1: 代码已更正,如我对 Daniel 的回答的评论中所述。
在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/) 中,我可以毫无问题地添加新用户。书面验证器也可以正常工作:
23755124050
被接受。237.551.240-50
被接受。+-*23755124050
或其他一些可以想象的字符串,其中包含此特定顺序中的 11 位数字。237.551.240-51
不被接受:("Verification digits don't match")37.551.240-50
不被接受:("Wrong number of digits")
所以,验证器工作正常。
编辑 2: 文本在第一次编辑后更正。
问题是,当我将它保存到数据库中时,无论输入大小写 (1) 到 (3),我都希望将其格式保存为:f'{numeros[0:3]}.{numeros[3:6]}.{numeros[6:9]}-{numeros[9:]}'
。但是数据库总是保存验证前给定的输入文本(将输入文本视为已验证)。所以 +-*23755124050
按原样保存,而不是 237.551.240-50
我想要的方式。
这对我来说很棘手,我在这个过程中遗漏了一些重要的东西。有没有人能赐教一下?
与其使用验证器,不如使用带有 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