formularios - Evitar nuevas instancias de campos de forma de modelo en django
formularios django (1)
Tengo una forma de modelo con un modelo de campo personalizado.
class UserModelChoiceField(forms.ModelChoiceField):
def label_from_instance(self, obj):
return obj.get_full_name()
class TaskForm(forms.ModelForm):
originator = UserModelChoiceField(queryset=User.objects.all().order_by(''first_name''),widget=forms.Select(attrs={''class'':''form-control''}))
class Meta:
model = Task
fields = [''originator'']
Mi lectura sugiere que el manejo de mi campo de esta manera está anulando cualquier información del modelo (por ejemplo, si es necesario o no) porque está creando una instancia de mi definición en lugar de aumentar el campo del modelo.
Parece que para minimizar mi alteración de campos como este debería interactuar con el init en su lugar (ver abajo)
def __init__(self,*args, **kwargs):
super(TaskForm, self).__init__(*args, **kwargs)
self.fields[''originator''].queryset=User.objects.all().order_by(''first_name'')
self.fields[''originator''].widget = forms.Select(attrs={''class'':''form-control''})
Entiendo cómo hacer el conjunto de consulta y el widget suponiendo que lo anterior es correcto. Mi pregunta es cómo uso ese campo de elección personalizado. Además, ni siquiera estoy seguro de si esta es la manera de hacerlo, ya que parece un poco hacky.
Ugh ... Recuerdo haber tenido este problema y no encontrar una solución incorporada o idiomática. No encontré una mejor solución que este decorador (y sí, este es el código de producción ):
def model_generated(model):
"""Generate form fields from model fields
Purpose:
This decorator lets you have form field attributes like
`max_length` copied over from a model field while being DRY.
Usage:
Decorate a form class with this decorator and set MODEL_GENERATED_FIELDS
to a list of attribute names you would like to be generated.
Limitations:
- Currently, this decorator only supports CharFields.
"""
def decorator(cls):
for field_name in cls.MODEL_GENERATED_FIELDS:
model_field = model._meta.get_field(field_name)
model_field_type = type(model_field)
if model_field_type == django_models.CharField:
form_field_type = forms.CharField
attributes = { # (form_attribute, model_attribute, processor)
(''label'', ''verbose_name'', None),
(''max_length'', None, None),
(''min_length'', None, None),
(''required'', ''blank'', lambda value: not value),
}
else:
# (Maybe one day this decorator will support more types of fields.)
raise ValueError("Unknown type of model field: {}".format(model_field_type))
kwargs = {}
for form_attribute, model_attribute, processor in attributes:
if model_attribute is None:
model_attribute = form_attribute
if processor is None:
processor = lambda value: value
if hasattr(model_field, model_attribute):
kwargs[form_attribute] = processor(getattr(model_field, model_attribute))
form_field = form_field_type(**kwargs)
setattr(cls, field_name, form_field)
# Register field since we''re monkey-patching
# (Django''s meta-class hackery to detect fields only runs the first time the class is declared.)
cls.base_fields[field_name] = form_field
return cls
return decorator
Entonces, por ejemplo, tendría:
class Team(models.Model):
name = models.CharField(max_length=30, unique=True,
verbose_name="Team Name")
passphrase = models.CharField(max_length=30,
verbose_name="Passphrase")
...
y:
@model_generated(models.Team)
class TeamJoiningForm(forms.Form):
MODEL_GENERATED_FIELDS = (''name'', ''passphrase'')
...
Puede adaptar y ampliar el decorador model_generated
por model_generated
para sus necesidades específicas. Lo siento.