iterating over a queryset?

2,018 views
Skip to first unread message

Johan Bergkvist

unread,
Sep 17, 2013, 4:29:38 PM9/17/13
to django...@googlegroups.com
Hi
I'm quite new to both django and python, and OOP for that matter. I do have some embedded programming experience though.
I have a question regarding querysets and dictionaries, I think.

I was trying to build a model that provides an overview for subscribed customers over their services and subscription status, etc.

I have a model like this:
class Customer (models.Model):
    user_id = models.AutoField( primary_key=True )
    auth_user = models.OneToOneField( User)
    subscription_type = models.ForeignKey( SubscType, related_name='type', null = 'true', blank = 'true' )
    first_name = models.CharField( max_length = 64, verbose_name = 'Fornavn' )
    last_name = models.CharField( max_length = 64, verbose_name = 'Efternavn' )
    email_address = models.EmailField( max_length = 75, verbose_name = 'eMail adresse' )
    join_date = models.DateField(auto_now_add = 'True', verbose_name = 'Oprettet dato')
    delivery_address = models.ForeignKey( Address, related_name='delivery', null = 'true', blank = 'true', verbose_name = 'Leveringsadresse')
    address = models.ForeignKey( Address, related_name='home', verbose_name = 'Hjemmeadresse' )
    phone_number = models.IntegerField(max_length = 10, verbose_name = 'Telefon nummer')
    mobile_number = models.IntegerField(max_length = 10, blank = 'true', null = 'true', verbose_name = 'Mobilnummer')
    image = models.ImageField(upload_to = 'Customer_img', blank = 'true', verbose_name = 'Billede')

class customerHistory (models.Model):
    customer_id = models.ForeignKey( Customer, related_name ='customer' )
    used_service = models.ManyToManyField(Services, related_name='services' )
    action_date = models.DateField(auto_now_add = 'True')
    notes = models.TextField(verbose_name = 'Noter til handling')

views like so:
class CustomerInfo(TemplateView):
    #info page, displays base info about customer such as address, phone number and  subscription entries
    template_name = "subscribtions/info.html"
  
   
    def get_context_data(self, **kwargs):
        context = super(CustomerInfo, self).get_context_data(**kwargs)
       
        context = Customer.objects.filter( auth_user = self.request.user ).values(
                                    'first_name',
                                    'last_name',
                                    'address',
                                    'delivery_address',
                                    'phone_number',
                                    'mobile_number',
                                    'email_address',
                                    'join_date',
                                    'subscription_type',
                                    'image'
                                    ).get()
        return { 'info' : context }

First of all, when I ommit the .get() method I cannot iterate over the above query, I just get an empty queryset when doing this:
        {% for key, value in info.items %}
            <h3>{{ key }}:</h3>    <p> {{ value }} </p>
            {% empty %}
            <p> no data </p>
        {% endfor %}

I guess this has something to do with it not being a dictionary without the .get() method. But in the documentation it seems that it should return a iterable, I might be using it wrong, any suggestions?

Second question is:
When I try to to a "backwards relation" in the template, like so:
{% for services in info.customerhistory_set.all %}
{{ services }}
{% endfor %}
It also winds up empty.
It might be that I'm interpreting the documentation wrong but I've been googling on this subject and tried several different combinations. Any help?

Thanks
Johan

Daniel Roseman

unread,
Sep 17, 2013, 6:02:21 PM9/17/13
to django...@googlegroups.com
Without the get(), you get a queryset, which is an iterable of all elements that match the query - in effect, a list of dicts. Even though only one record matches, you still get a queryset containing a single dict. So in order to use that in your template, you'd have to add an outer loop iterating through each item in the queryset, while the inner loop iterates over the elements in each dict.

Reverse relations work with a model instance. But you don't have one of those - you've got a dict, because you used .values(). If you dropped that call, you'd have an instance which you could use the backwards relation on, but you wouldn't be able to iterate over the fields with .items(). Note that most of the time you don't need to do that, so mostly you would use the instance rather than calling .values().

--
DR.

Johan Bergkvist

unread,
Sep 18, 2013, 11:39:34 AM9/18/13
to django...@googlegroups.com
Hi, thanks - that provides some perspective.

So if I omitted the .get() and .values() i will have to loop over the queryset and then each dict, doing something like:

{% for q in info %}
          {% for k, v in q.items %}
                   {{ k }} {{ v}}
          {% empty %}
                   no data
          {% endfor %}
{%endfor%}
?

Daniel Roseman

unread,
Sep 18, 2013, 2:14:47 PM9/18/13
to django...@googlegroups.com
Well, not quite. That will work if you just omit .get(), because then you'll have a ValuesQuerySet - basically, a list of dicts. However, if you omit .values() as well you'll have a plain old QuerySet - ie a list of model instances - and those instances aren't dicts and don't have an .items() method. There's not really a good way of iterating over all the fields in an instance with their names (you can muck about with the stuff in _meta, but I wouldn't recommend it).

As I say though, in practice that's rarely a problem as you usually want to reference individual fields by name, rather than iterating over them.
--
DR.

Johan Bergkvist

unread,
Sep 18, 2013, 3:58:28 PM9/18/13
to django...@googlegroups.com
Hi
Yeah I see.
I tried it out just after writing, with little success, but without the .values() I do still have the {{ data.field_name }} available which Is probably more usefull than actually iterating over a dataset regardless of content.
Still the relationsships are only available as forwards and backwards relations on instances, right? Which, if I understand you correctly I only get when omitting the .get() method.
I probably should have started out with a Python tutorial before jumping in to django :) Well, no pain no gain I guess.
thanks by the way.

Bill Freeman

unread,
Sep 18, 2013, 4:20:08 PM9/18/13
to django-users
.get() actually gets you an instance, while the queryset without the get acts (somewhat) like a list of instances.  It is the .values() call that causes you to have dicts rather than instances.  .get() considers it an error if the queryset represents either zero objects, or two or more objects (it doesn't know which one to give you).  In this case you may actually want get, since I presume that there should only be one Customer per User.

Just for completeness, context[0] is similar to context.get().  It will still raise an error if there are no such Customer objects, but it won't complain if there are more than 1.

And, yes, the decision of which field is shown in what order should probably be in the template, since it is very much presentation, rather than logic, so passing in just the one instance and using things like {{ data.field_name }} is likely the way to go.


--
You received this message because you are subscribed to the Google Groups "Django users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to django-users...@googlegroups.com.
To post to this group, send email to django...@googlegroups.com.
Visit this group at http://groups.google.com/group/django-users.
For more options, visit https://groups.google.com/groups/opt_out.

Bill Freeman

unread,
Sep 18, 2013, 1:52:43 PM9/18/13
to django-users
No.  q will be a model instance, not a dict.  Your inner loop would, perhaps, loop over a sequence of names (like the arguments you were passing to value()) and use those names to access the attributes of q.

This might more cleanly handled with a method on the q object's class that returns the desired sequence.  You could, of course, name such a method "items", in which case your code above is exactly correct, but I think a more descriptive name is desireable.

Bill




--

Johan Bergkvist

unread,
Sep 21, 2013, 5:09:49 AM9/21/13
to django...@googlegroups.com
Daniel Roseman adviced me to use the Shell. This was a fantastic idea, and one I should have thought of myself! Anyway this helped me realize that I was referencing related models the wrong way. For some reason I thought that you should reference the model name and not the foreign key field name. It might just be me, but the documentation could seem a bit ambiguous on this point as all field names are lower case model names.
Thanks for the help!

kooliah

unread,
Sep 22, 2013, 5:56:58 AM9/22/13
to django...@googlegroups.com
Everyday i receive 5-10 mysterious error messages of this kind

....... ERRORS.....

File "....../satchmo/satchmo/apps/satchmo_store/shop/context_processors.py", line 31, in settings
'shop_name': shop_config.store_name,

AttributeError: 'NoneType' object has no attribute 'store_name'


<WSGIRequest
path:/plugins/tinymce_plugin/tiny_mce/plugins/more/editor_plugin.js,
GET:<QueryDict: {}>,
POST:<QueryDict: {}>,

....

File ".../satchmo/satchmo/apps/satchmo_store/shop/context_processors.py", line 31, in settings
'shop_name': shop_config.store_name,

AttributeError: 'NoneType' object has no attribute 'store_name'


<WSGIRequest
path:/admin/login.aspx,
GET:<QueryDict: {}>,

....

File "..../django/db/backends/postgresql_psycopg2/base.py", line 52, in execute
return self.cursor.execute(query, args)

DatabaseError: server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.



<WSGIRequest
path:/art_folder/text-image_Series-1.jpg,
GET:<QueryDict: {}>,
POST:<QueryDict: {}>,

....

....

....

.......END ERRORS......

All of them do not depend by my code but by django/satchmo source code,
and never rise on developing server....but the thing I don't understand
is paths.... I have no paths like them...Why it does not give "page not
found" but Errors ??
If i give that url in browser it correctly gives me "page not found"........

Thank you

Kooliah

kooliah

unread,
Sep 22, 2013, 6:08:23 AM9/22/13
to django...@googlegroups.com
Sorry...I wanted open a new discussion but i reply instead...

kooliah

unread,
Sep 22, 2013, 6:09:14 AM9/22/13
to django...@googlegroups.com
Reply all
Reply to author
Forward
0 new messages