Using forloop counter to index into a query set

2,625 views
Skip to first unread message

SnappyDjangoUser

unread,
Sep 29, 2008, 8:31:18 PM9/29/08
to Django users
Hi Folks,

How can I use a forloop counter to index into a query set as in the
example below?

(I know this code does not work, but I want to do something of the
sort):

{% for form in quote_product_formset.forms %}
<tr>
<td>{{ product.(forloop.counter).Vendor }}</td>
</tr>

{{ form }}
{% endfor %}

(in the above case, Vendor is a field in product. So if I want to
access the first product when forloop counter is 1, the variable would
expland to "{{ product.1.Vendor }}")

Thanks!

felix

unread,
Sep 29, 2008, 9:12:33 PM9/29/08
to Django users
it might be easiest to write a custom tag there

{% vendor_of_product product forloop.counter %}

is product an array ?

SnappyDjangoUser

unread,
Sep 29, 2008, 9:19:47 PM9/29/08
to Django users
Yes, product is an array of many entries. It is actually a queryset
that is passed to the template and I am trying to access a specific
entry.

I have not worked with custom tags before, but I will start reading up
on it.

Malcolm Tredinnick

unread,
Sep 30, 2008, 3:10:16 AM9/30/08
to django...@googlegroups.com

You can't do indirect variable references like this in Django's
templating language. The reasoning is that it ends up complicating the
template structure when you wander down that path. Instead, factor it
out into a template tag (that can be passed the current context, so it
will have access to the forloop counter) or set up the data structures
you pass to your view a bit differently so that you can loop over the
forms and the products simultaneously (that is, pull apart the formset
forms and zip them together with the product entries in the view).

Usually the second approach works a bit more nicely, but either is
possible.

Regards,
Malcolm


SnappyDjangoUser

unread,
Sep 30, 2008, 11:05:33 AM9/30/08
to Django users
Hi Malcolm,

You suggested:

> set up the data structures
> you pass to your view a bit differently so that you can loop over the
> forms and the products simultaneously (that is, pull apart the formset
> forms and zip them together with the product entries in the view).

This is exactly what I like to do! I am still a bit confused on exact
implementation, however, because I have not found a way in Django to
loop through 2 structures at once in a template. The forloop.counter
seems that it is mostly used for printing the iteration through the
loop (not for indexing) and the "for loop" tag in Django is built only
to iterate through one structure at a time. Do you have any examples
how how to loop through 2 strucutres simultaneously?

Thanks!

-Brian



On Sep 30, 12:10 am, Malcolm Tredinnick <malc...@pointy-stick.com>
wrote:

Carl Meyer

unread,
Sep 30, 2008, 12:37:25 PM9/30/08
to Django users
On Sep 30, 11:05 am, SnappyDjangoUser <bpwall...@gmail.com> wrote:
> > set up the data structures
> > you pass to your view a bit differently so that you can loop over the
> > forms and the products simultaneously (that is, pull apart the formset
> > forms and zip them together with the product entries in the view).
>
> This is exactly what I like to do!  I am still a bit confused on exact
> implementation, however, because I have not found a way in Django to
> loop through 2 structures at once in a template.

{% for x,y in zipped %}

You need to set up "zipped" as an iterable of tuples in your view, of
course.

felix

unread,
Sep 30, 2008, 12:45:22 PM9/30/08
to Django users

malcom is suggesting this:

def view(request):
blah blah blah
...
zipped = []
for p in products:
v = find the vendor for this product
zipped.append( ( p, v) ) # add them as a tuple

# or more pythonically if its easy to find your vendor:
zipped = [ (p, vendor for product) for p in products ]
context = { 'products': zipped }


{% for product, vendor in products %}
{{product}} {{vendor}}
{% endfor %}

SnappyDjangoUser

unread,
Sep 30, 2008, 3:36:41 PM9/30/08
to Django users
This is extremely helpful! I didn't know this was possible in Django
to create a tuple and loop through both items using a for loop in the
template. Thank you!

I am currently hung up on one last part, however. In the example
above you assume that both p and v belong to products. In my case,
that is not the case. I have a queryset of products that contains the
vendor name, model name and model number. I also have a formset
containing forms. I am trying to combine these 2 lists of objects
into the tuple so I can iterate over both in the template.

# or more pythonically if its easy to find your vendor:
zipped = [ (form, << NEED HELP HERE product_queryset>>) for form
in formset.forms ]
context = { 'products': zipped }

{% for form, product in products %}
{{product.vendor}} {{product.model_name}} {{product.model_num}}
{{form}}
{% endfor %

Any suggestions?

felix

unread,
Sep 30, 2008, 6:11:39 PM9/30/08
to Django users


On Sep 30, 9:36 pm, SnappyDjangoUser <bpwall...@gmail.com> wrote:
>  In the example
> above you assume that both p and v belong to products.  

I just put them into a combined array called "products"


> In my case,
> that is not the case.  I have a queryset of products that contains the
> vendor name, model name and model number.  I also have a formset
> containing forms.  I am trying to combine these 2 lists of objects
> into the tuple so I can iterate over both in the template.

I don't know how the forms are indexed.

but I would suggest iterating through the product queryset in the
view,
and storing each result in a dict indexed by id. or look at queryset
in_bulk

then when building the tuples you can look up the vendor or product or
whatever it is in the dict.




another trick that I've done recently is to create a quick class

def view(request):
# this class just exists for use in this view
class Combo(object):
def __init__(self,form,product):
self.form = form
self.product = product

then instead of zipping together tuples, you make a list of these
Combos
and pass those in.
{{ combo.form }}
{{ combo.product }}

then I can add methods for things that I will need in that specific
view.
its much simpler than writing a template_tag.

SnappyDjangoUser

unread,
Sep 30, 2008, 6:17:20 PM9/30/08
to Django users
Malcolm, Carl and Felix,

Thanks for the help! I figured out a solution to my above problem by
using the suggested for loop approach to build the tuple of products
and forms. It may not be the most elegant python code, but it is
working and readable.

# Build a tuple of products and forms for each product
zipped = []
count = 0
for form in formset.forms:
product = product_queryset[count]
zipped.append( ( form, product) ) # add them as a tuple
count = count + 1

Thanks!

Malcolm Tredinnick

unread,
Sep 30, 2008, 10:17:24 PM9/30/08
to django...@googlegroups.com

On Tue, 2008-09-30 at 08:05 -0700, SnappyDjangoUser wrote:
> Hi Malcolm,
>
> You suggested:
>
> > set up the data structures
> > you pass to your view a bit differently so that you can loop over the
> > forms and the products simultaneously (that is, pull apart the formset
> > forms and zip them together with the product entries in the view).
>
> This is exactly what I like to do! I am still a bit confused on exact
> implementation, however, because I have not found a way in Django to
> loop through 2 structures at once in a template.

You don't loop through two structures at once in your template. I
suggested you change the datastructures in your (Python) view so that
you only loop through one data structure that happens to be a sequence
of pairs. Each pair contains on of the forms and one of the queryset
members. You do all the data structure munging at the Python level, not
at the template level.

Regards,
Malcolm


Reply all
Reply to author
Forward
0 new messages