Imagine este cenário: você deve escrever um formulário que trata do endereço do cliente, com um campo para número de telefone, incluindo código de área.
from django import forms
class PhoneForm(forms.Form):
# very basic
number = forms.CharField()
area_code = forms.CharField()
Parece fácil? E se você tiver que escrever HTML com duas entradas, uma para número de telefone e outra para código de área, mas no banco de dados houver apenas um campo, para um número de telefone com código de área?
A primeira resposta seria lidar com isso no método limpo, assim:
class PhoneForm(forms.ModelForm):
number = forms.CharField()
area_code = forms.CharField()
def clean(self):
number = self.cleaned_data['number']
code = self.cleaned_data['area_code']
self.cleaned_data['full_number'] = code + number
Mas isso é: a) desagradável b) inextensível. Você não pode simplesmente reutilizar qualquer um desses códigos e manter a ação sem limpar nada diretamente no método de limpeza.
Mas, há uma maneira melhor – entre no Django MultiValueField
Para usá-lo efetivamente, precisamos criar uma subclasse de MultiValueField e MultiWidget . Em seguida, você define a subclasse do widget como o widget da subclasse de campo, para que possa manipular e exibir os dados.
A última coisa a lembrar é que você precisa implementar métodos de compactação e descompactação para campo e widget, respectivamente. Isso ocorre porque o campo deve retornar um único valor e recebe um único , não importa quantas entradas você realmente exibe ou quantos dados são enviados.
Por exemplo
class PhoneNumberWidget(forms.MultiWidget):
def __init__(self, *args, **kwargs):
super(PhoneNumberWidget, self).__init__(*args, **kwargs)
self.widgets = [
forms.TextInput(),
forms.TextInput()
]
def decompress(self, value):
if value:
return value.split(' ')
return [None, None]
class PhoneNumberField(forms.MultiValueField):
widget = PhoneNumberWidget
def __init__(self, *args, **kwargs):
super(PhoneNumberField, self).__init__(*args, **kwargs)
fields = (
forms.CharField(),
forms.CharField()
)
def compress(self, data_list):
return ' '.join(data_list)
class PhoneForm(forms.ModelForm):
phone_number = PhoneNumberField()
def __init__(self, *args, **kwargs):
super(PhoneForm, self).__init__(self, *args, **kwargs)
self.initial['phone_number'] = ['+1','11111111']
Isso é um pouco mais de código, mas permite que você envolva bem a lógica de negócios com o código. Se você precisar de um campo para lidar com um número de telefone com código de área dessa forma em qualquer outro lugar, pode apenas importar o campo em vez de usar o método copiar e colar .