我正在使用Django / Python开发一个Web系统,我需要一个来自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/),我可以毫无问题地添加新用户。书面验证器也可以正常工作:
23755124050
被接受。237.551.240-50
被接受。+-*23755124050
或其他可以想象的字符串,其中包含此特定顺序的11位数字。237.551.240-51
:(“验证数字不匹配”)37.551.240-50
:(“错误的位数”)因此,验证器工作正常。
编辑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