0

I am trying to create a dynamic form after checking some condition in the view and i am not sure how to approach it. How do i populate the fields attribute in the forms Meta class from my views?

Below are my views.py and my forms.py files.

views.py

How do i populate the fields list in forms.py from my views?

    from django.shortcuts import render, get_object_or_404
    from django.http import HttpResponse
    from django import forms

    from .models import Master, Label, Assosiative
    from .forms import LabelForm, MzasterForm, AssosiativeForm

    def master(request,pk):
        associate = get_object_or_404(Assosiative, pk=pk)
        form = MasterForm(request.POST or None)
        if associate.short_text1 == 1:
            form.fields['short_text1'] = forms.CharField(label='Short text 1')
        if associate.short_text2 == 1:
            form.fields['short_text2'] = forms.CharField(label='Short text 2')
        if associate.short_text3 == 1:
            form.fields['short_text3'] = forms.CharField(label='Short text 3')
        if associate.short_text4 == 1:
            form.fields['short_text4'] = forms.CharField(label='Short text 4')
        if associate.num_field1 == 1:
            form.fields['num_field1'] = forms.CharField(label='Number field 1')
        if associate.num_field2 == 1:
            form.fields['num_field2'] = forms.CharField(label='Number field 2')
        if form.is_valid():
            try:
                short_text1 = form.cleaned_data['short_text1']
                short_text2 = form.cleaned_data['short_text2']
                short_text3 = form.cleaned_data['short_text3']
                short_text4 = form.cleaned_data['short_text4']
                num_field1 = form.cleaned_data['num_field1']
                num_field2 = form.cleaned_data['num_field2']
                form.save()
            except Exception, ex:
        return HttpResponse("Error %s" %str(ex))
        return render(request, 'master.html', {'form':form,}) 

forms.py

I am not sure what to do here so that i can populate the fields from my views

    def masterForm(fields_list, *args, **kwargs):
        class MasterForm(forms.ModelForm):
            class Meta:
                model = Master
                fields = fields_list
            def __init__(self):
                super(MasterForm, self).__init__(*args, **kwargs)
         return MasterForm()
    joke = masterForm(('short_text1',))
Hamfri
  • 1,979
  • 24
  • 28
  • [This question](http://stackoverflow.com/questions/297383/dynamically-update-modelforms-meta-class) might help. – Alasdair Mar 22 '16 at 11:16
  • I have tried implementing as that question explains but still it doesn't work – Hamfri Mar 22 '16 at 11:22
  • 2
    What "doesn't work"? Try the simpler version `def get_form(exclude_list):`, I think it's clearer when you create the form class, then instantiate it as two separate steps. – Alasdair Mar 22 '16 at 11:26
  • My main issue is that i can't find a way to pass values of the fields list that i am creating in views.py after checking some condition to the fields list in forms.py . Any idea? – Hamfri Mar 22 '16 at 11:45

2 Answers2

2

As in this question, you can define a method that creates the form class. Looking at your view, you seem to be creating fields one by one based on associate, instead of creating a list of fields. Therefore, I would use associate as an argument to your get_form_class method.

def get_form_class(fields_list):
    class MasterForm(ModelForm):
        class Meta:
            model = Master
            fields = fields_list
        ...
    return MasterForm

Then, in your view, use the get_form to create the form class dynamically, then instantiate it.

def master(request, pk):
    associate = get_object_or_404(Assosiative, pk=pk)
    fields_list = []
    if associate.short_text1 == 1:
        fields_list.append('short_text1')
    if associate.short_text2 == 1:
        fields_list.append('short_text2')
    MasterForm = get_form_class(fields_list)
    form = MasterForm(request.POST or None)
    if form.is_valid():
        ...
Community
  • 1
  • 1
Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • your answer heped me however i had to tweak a little bit as in the code below – Hamfri Mar 22 '16 at 13:15
  • Thanks alot your answer helped me. Now the only issue i have is that when i post data it gets posted as null values to the database and also if i don't include **fields = []** in the **class Meta** django complains **Creating a ModelForm without either the 'fields' attribute or the 'exclude' attribute is prohibited; form MasterForm needs updating.** – Hamfri Mar 22 '16 at 13:24
  • `class Master(models.Model): short_text1 = models.CharField(max_length=100, blank=True, null=True) short_text2 = models.CharField(max_length=100, blank=True, null=True) short_text3 = models.CharField(max_length=100, blank=True, null=True) short_text4 = models.CharField(max_length=100, blank=True, null=True) num_field1 = models.IntegerField(blank=True, null=True) num_field2 = models.IntegerField(blank=True, null=True)` – Hamfri Mar 22 '16 at 13:50
  • Above is my models.py. For the case of fields in the class meta should i leave it as **fields = []**? – Hamfri Mar 22 '16 at 13:52
  • Looking at your model, it doesn't look as if you are modifying the fields at all. So it would be better to create a list of field names in the view, and create the model form using that. – Alasdair Mar 22 '16 at 13:56
0

To create form dynamically after checking some condition

views.py

    def master(request, pk):
        associate = get_object_or_404(Assosiative, pk=pk)
        MasterForm = get_form_class(associate)
        form = MasterForm(request.POST or None)
        if form.is_valid():
            form.save()
            messages.add_message(request, messages.INFO, 'Your Form has been posted successfully')
            return HttpResponseRedirect('/')
        return render(request, 'master.html', locals())

Dynamically add form fields to the fields list class Meta in forms.py

    def get_form_class(associate, *args, **kwargs):
        class MasterForm(forms.ModelForm):
            def __init__(self, *args, **kwargs):
                super(MasterForm,self).__init__(*args, **kwargs)
            class Meta:
                model = Master
                fields = [] #initialize an empty fields list
                # Append items to the fields list after checking some condition
                if associate.short_text1 == 1:
                    fields.append('short_text1')
                if associate.short_text2 == 1:
                    fields.append('short_text2')
                if associate.short_text3 == 1:
                    fields.append('short_text3')
                if associate.short_text4 == 1:
                    fields.append('short_text4')
                if associate.num_field1 == 1:
                    fields.append('num_field1')
                if associate.num_field2 == 1:
                    fields.append('num_field2')            
         return MasterForm
Hamfri
  • 1,979
  • 24
  • 28