views:

24

answers:

1

I am somewhat new to Django and have searched for some simple examples of creating objects with subobjects in views so that in templates I can have nested for loops.

Here is my models.py for this application...

from django.db import models
from django import forms

class Market(models.Model):
    name   = models.CharField('Market name', max_length=150)
    state  = models.CharField('State', max_length=2)

    def __unicode__(self):
        return self.name

class Location(models.Model):
    name   = models.CharField('Location name', max_length=150)
    address1  = models.CharField('Address 1', max_length=200)
    address2  = models.CharField('Address 2', max_length=200,blank=True)
    city   = models.CharField('City', max_length=100)
    state   = models.CharField('State', max_length=2)
    zip_code = models.CharField('ZIP', max_length=10)
    phone  = models.CharField('Phone', max_length=20)
    hours  = models.TextField('Hours of operation', max_length=255)
    quote_text = models.TextField('Customer quote', max_length=500)
    quote_by = models.CharField('Customer name', max_length=30)
    yelp_url = models.URLField('Yelp URL', max_length=300,blank=True)
    image_store = models.ImageField('Storefront image', upload_to='images/locations', max_length=300,blank=True)
    image_staff = models.ImageField('Staff image', upload_to='images/locations', max_length=300,blank=True)
    market  = models.ForeignKey(Market, verbose_name='Regional market', null=True)

    def __unicode__(self):
        return self.name

Markets data may look as follows...

id = 1
state = 'MO'
name = 'St. Louis - Central'

id = 2
state = 'MO'
name = 'St. Louis - West'

id = 3
state = 'IL'
name = 'Chicago - South'

id = 4
state = 'IL'
name = 'Chicago - North'

In my views.py I'd like to create an object with a list/array of grouped Market states (distinct) in descending order, each with a subarray of the individual Market names in that State in order to complete a nested forloop in the template.

The templating language in Django is really cool in how it prevents a ton of logic from residing betwixt the html, which I like. But I am still wrapping my head around both Python syntax and the need to create all objects exactly the way they need to iterate in the template.

Here's what views.py looks like ...

def locations_landing(request):
    marketList = Market.objects.values('state').order_by('-state').distinct()
    return render_to_response('locations.html', locals()) 

How to return an object so that my template can perform the following nested looping...

{% for st in stateList.all %}
    <h4>{{ st.state }}</h4>
    {% for mkt in stateList.marketList.all %}
        <p>* <a href="#">{{ mkt.name }}</a></p>
    {% endfor %}
{% endfor %}

This would result in the following rendered in html based on my data samples above...

<h4>MO</h4>
<p>* St. Louis - Central</p>
<p>* St. Louis - West</p>
<h4>IL</h4>
<p>* Chicago - South</p>
<p>* Chicago - North</p>

BTW, there are no errors in any of the .PY code samples above, all is well, I just need some guidance on creating the object correctly in the view so the template does it's thing.

+1  A: 

I don't see a need to use distinct here. By representing the states as separate model and using relations you would gain much more flexibility.

I suggest you create a third State model and use a ForeignKey to relate the models together so that each Market has a one to many relation to single State, i guess you also want Location model related to the Market model.

class State(models.Model):
    name   = models.CharField('State name', max_length=150)

class Market(models.Model):
    name   = models.CharField('Market name', max_length=150)
    state  = models.ForeignKeyField(State)

class Location(models.Model):
    state  = models.ForeignKeyField(Market)
    ...

In your view, all you need to do is take all the states and pass them into the template:

def locations_landing(request):
    state_list = State.objects.all()
    return render_to_response('locations.html', {'state_list':state_list}) 

And finally, in your template, iterate over the state list and use a backward relation queryset to get all the markets in that state:

{% for state in state_list %}
    <h4>{{ state }}</h4>
    {% for market in state.market_set.all %}
        <p>* <a href="#">{{ market }}</a></p>
        {% for location in market.location_set.all %}
           <p> {{ location }} </p>
        {% endfor %}
    {% endfor %}
{% endfor %}
rebus
Brilliant, not sure why I couldn't find that but great answer. Will do just that. The Market model wasn't normalized properly anyway with the state field containing duplicate values. So will separate as you suggest. Cheers.
sansjoe