19

i have the following models:

class Tag(models.Model):
    tag_name = models.CharField(max_length=250)
    tagcat = models.ForeignKey('TagCat')

class Subject(models.Model):
    user = models.ManyToManyField(User)
    tags = models.ManyToManyField(Tag)

class TagCat(models.Model):
    cat_name = models.CharField(max_length=100)

So i have a subject, that has a tag. I want to loop the subjects and their appropriate tags, so I am trying to construct the right view. So far, I have:

def home(request):
    user1 = Subject.objects.filter(id=1)
    print(user1.tags.all())

I would expect to get the tags of the user through this print statement, but instead I get error

'QuerySet' object has no attribute 'tags'

How would I be getting the 'Subject' objects with their respective tags and pass them to template?

(Ideally all subjects. I did it with just one here, to simplify for the process of troubleshooting)

mgPePe
  • 5,677
  • 12
  • 52
  • 85

2 Answers2

34

filter returns a QuerySet (as you may have guessed), you want to do get instead

user1 = Subject.objects.get(id=1)

If the Subject does not exist you will get a Subject.DoesNotExist exception. There's also the get_object_or_404 shortcut in django.shortcuts that is useful if you're simply grabbing an object that is to be displayed in some way and you want to return a 404 if it is not available.

Daniel DiPaolo
  • 55,313
  • 14
  • 116
  • 115
  • Since I am a newbie, can I follow up on this with a short q?-> what exactly is the difference between get and filter? so to say they both get me the user, since I can print it's name. I am missing a major concept... if filter returns a queryset(not very clear what that is either) what does get return? – mgPePe Nov 30 '10 at 22:51
  • 3
    But `filter` doesn't really get you the user, it gets you another `QuerySet` which describes some criteria to choose a set of `Subject` s from your set of objects (`Subject.objects`). Think of it as the difference between a table and a row within the table. `QuerySet`s describe tables where the objects are the rows. In your case, your `QuerySet` is just a one-row table. `get` uniquely identifies an object out of the object set and returns that object instead of a single-row table. – Daniel DiPaolo Nov 30 '10 at 22:53
  • hm...More or less I get it. But get seems to retun only 1 item, since I get "'Subject' object is not iterable". This is the primary reason why I switched to filter, filter gave me something that I could loop. Now that I understand filter is wrong for the purposes, how do I get the 'get' to return many Subjects and their tags? – mgPePe Nov 30 '10 at 22:59
  • 3
    If you want multiple things you use `filter`, and then you can iterate over that. `for user in Subject.objects.filter([your filter criteria]):` will give you a `Subject` object in that `user` variable for each iteration. That variable will have all the attributes you seek! – Daniel DiPaolo Nov 30 '10 at 23:02
  • 1
    Awesome! got it to work, it's wonderful! You're wonderful too. – mgPePe Nov 30 '10 at 23:19
  • Though the logic is crooked, because essentially you are still doing a filter, and the fact that you are looping it and adding it to a list, doesn't seem to strike me where exactly the conversion from queryset to object is... – mgPePe Nov 30 '10 at 23:24
3

QuerySet.get() will either return a single model as given by the criteria passed by it, or it will raise an exception.

Ignacio Vazquez-Abrams
  • 776,304
  • 153
  • 1,341
  • 1,358