0

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!

rom
  • 3,592
  • 7
  • 41
  • 71

2 Answers2

1

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

Community
  • 1
  • 1
allcaps
  • 10,945
  • 1
  • 33
  • 54
  • I did all thoses steps, but with ActForm, not with GvtCompoForm (I want to save an act). I am sure it works since I am using "form" for other fields. I have found one solution, using an instance instead of the form, but I can't validate or save my field with this solution! – rom Jul 28 '13 at 13:35
  • I changed Gvt to Act in the example. Also added the formset to include related GvtCompo objects in the form. – allcaps Jul 28 '13 at 16:20
  • Why using GvtCompo and formset? Will my field be validated and saved? – rom Jul 29 '13 at 00:44
  • If I understand your question correctly, you want to display a form in your template containing all fields from Act and all fields from the related GvtCompo's. Right? In the act form you can select GvtCompo's but not edit them. So you need to supply forms for each related GvtCompo. This set of forms is the formset. In your case a set of modelfoms. The whole goal of modelfroms is to validate and save data to the db. So the have validation and save. You need to call them from your view. formset.is_valid() and formset.save(). Just like form.is_valid() and form.save(). – allcaps Jul 29 '13 at 09:26
0

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.

iMom0
  • 12,493
  • 3
  • 49
  • 61
  • Doesn't work, nothing is displayed ;(. What does form.instance mean? – rom Jul 28 '13 at 11:13
  • It means the bound model instance. – iMom0 Jul 28 '13 at 13:57
  • So it's what I did in my edit (I used my instance act). Then I can display the values but there is no form field anymore, so no validation and no saving! – rom Jul 29 '13 at 00:48