Question

I am trying to display a ManyToManyField in my template:

class GvtCompo(models.Model):
    startDate=models.DateField(max_length=10, blank=False, null=False)
    endDate=models.DateField(max_length=10, blank=False, null=False)
    gvtCompo= models.CharField(max_length=1000, blank=False, null=False)

class Act(models.Model):
    gvtCompo= models.ManyToManyField(GvtCompo)

In my view, I can display the object, no problem:

for gvtCompo in act.gvtCompo.all():
    print gvtCompo.gvtCompo

In my template, I have a list of "GvtCompo Object" with this code (not nice):

{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field }}
    </div>
{% endfor %}

I have tried to make it nicer, but the following code just not work (nothing appears):

{% for field in form %}
    {% if field.name == "gvtCompo" %}
        {% for gvtCompo in field.gvtCompo.all %}
            {{ gvtCompo.gvtCompo }}
        {% endfor %}
    {% endif %}
{% endfor %}

What's wrong?

*Edit: *

If I don't use the form but an instance of the model (act) passed to render_to_response it displays the ManyToManyField values

{% for gvtCompo in field.gvtCompo.all %}

changed to

{% for gvtCompo in act.gvtCompo.all %}

However there is not form field anymore, so it can't be modified, validated and saved!

Was it helpful?

Solution

You are skipping a step. You first need to create a form.

In forms.py you can create a ModelForm. A ModelForm is a form based on your model:

from django.forms import ModelForm from myapp.models import Act

class ActForm(ModelForm):
   class Meta:
       model = Act

Then your view:

from myapp.models import Act
from myapp.forms import ActForm


def add_view(request):
    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = ActForm() # Creating a empty form.
    return render_to_response("template.html", {
        "form": form,
    })

def edit_view(request):
    obj = Act.objects.get(pk=1)

    if request.method == 'POST':
        form = ArticleForm(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = ActForm(instance=obj) # Creating form pre-filled with obj.
    return render_to_response("template.html", {
        "form": form,
    })

If you want to implement this situation more than once. DRY: https://docs.djangoproject.com/en/1.5/topics/class-based-views/intro/#handling-forms-with-class-based-views

In your template.html:

{{ form }}

Disclaimer: This code is not tested. https://docs.djangoproject.com/en/1.5/ref/forms/ https://docs.djangoproject.com/en/1.5/topics/forms/modelforms/

Update:

You can pass multiple forms to one <form>...</form> in your template. So create two forms. One Act form (see above) and one GvtCompo formset. The formset contains all GvtCompo's that have a relation to Act.

from django.forms.models import modelformset_factory

act = Act.objects.get(pk=1) #The same act as you used to create the form above.

GvtFormSet = modelformset_factory(GvtCompo)
formset = GvtFormSet(queryset=act.gvtCompo.all())

Template can be:

<form ...>
{% for field in form %}
    {% if field.name == "gvtCompo" %}
        {{ formset }}
    {% else %}
        {{ field }}
    {% endif %}
{% endfor %}
</form>

Note: If your form and formset have colliding field names use prefix="some_prefix": Django - Working with multiple forms

OTHER TIPS

When looping over the form, it should be:

{% for field in form %}
    {% if field.name == "gvtCompo" %}
        {% for gvtCompo in form.instance.gvtCompo.all %}
            {{ gvtCompo.gvtCompo }}
        {% endfor %}
    {% endif %}
{% endfor %}

field itself has no related field.gvtCompo.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top