2016-07-06 2 views
1

У меня есть модель с пользовательским полем modelchoice.Избегайте свежих экземпляров полей modelform в django

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'] 

Моего чтение показывает, что обработка моего поля таким образом, является переопределение любой информации из модели (например, является ли она или нет необходимости), потому что это инстанцирование его из моего определения, а не увеличение поля модели.

Кажется, что свести к минимуму моего изменения полей, как это я должен быть взаимодействующим с инициализацией вместо (см ниже)

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'}) 

Я понимаю, как это сделать QuerySet и виджет, предполагая, что выше является правильным. Мой вопрос заключается в том, как использовать этот настраиваемый выбор. Более того, я даже не уверен, что это способ сделать это, поскольку это кажется немного взломанным.

ответ

1

Ugh .. Я помню, что у меня возникла эта проблема и не нашел встроенного или идиоматического решения. Я не придумал лучшего решения, чем это декоратора (и да, это production code):

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 

Так, например, я бы:

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") 
    ... 

и:

@model_generated(models.Team) 
class TeamJoiningForm(forms.Form): 
    MODEL_GENERATED_FIELDS = ('name', 'passphrase') 
    ... 

Вы можете адаптировать и расширить декоратор model_generated для своих нужд. Сожалею.

+0

Большое спасибо за помощь. Ваше решение намного превосходит мой опыт. Я удивлен, что нет ничего встроенного, учитывая, что это настоятельно рекомендуется – Ewanw

+0

@Ewanw Попробуйте добавить ветку 'elif' рядом с веткой' if model_field_type == django_models.CharField' и установить переменные 'form_field_type' и' attributes 'Соответственно –

+0

И да, есть много примеров, когда я удивляюсь чему-то столь же популярному, как Django, похоже, не имеет хорошего решения, похожего на общие проблемы (и да, иногда проблемы, созданные по их собственным рекомендациям!) –

Смежные вопросы