Nafiul Islam
Nafiul Islam

Reputation: 82450

Specialized django query

As you can guess from the title, I'm not exactly sure how to describe what I want. Please take a look at the following classes:

from django.db import models
from django.contrib.auth.models import User as Auth_User


class User(Auth_User):

    Portfolio = models.ManyToManyField('PortfolioItem', through='SkillTag')
    Age = models.IntegerField(blank=False)

    @property
    def full_name(self):
        return self.first_name + ' ' + self.last_name

    def __unicode__(self):
        return self.full_name


class PortfolioItem(models.Model):

    Title = models.CharField(max_length=200, blank=False)


class SkillTag(models.Model):

    User = models.ForeignKey('User')
    PortfolioItem = models.ForeignKey('PortfolioItem')

    Tag_Name = models.CharField(max_length=200, blank=False)

What I need to do, is for every user, get all the Tag_Name values of it's SkillTags, how do I do this?

Upvotes: 0

Views: 61

Answers (2)

karthikr
karthikr

Reputation: 99620

You can do something like this

class User(Auth_User):
    #other attributes
    def tag_names(self):
        return self.skilltag_set.values_list('Tag_Name', flat=True)

So, here, we are doing a couple of things:

Since you are not using a related_name in the ForeignKey attribute, by default django would assign the model name (lowercase) followed by _set attribute, which makes it .skilltag_set.all()

Returns a ValuesQuerySet — a QuerySet subclass that returns tuples when used as an iterable, rather than model-instance objects.

Example: [('a'), ('b'), ('c')]

Basically, you are retriving an iterable of ValuesQuerySet (think of it as a list or any other iterables) consisting of tuples.

  • flat=True

This basically flattens the on-tuples into single values.

Example: ['a', 'b', 'c']

Upvotes: 4

Javier
Javier

Reputation: 62573

most obvious: using the reverse relationship of ForeignKey fields:

def skill_names_1(user):
  return [t.name for t in user.skilltag_set.all()]

The same thing, but explicitly selecting for the user. also, it fetches only the required field from the database.

def skill_names_2(user):
  return SkillTag.objects.filter(User=user).values_list('Tag_Name',flat=True)

Either of these can also work as a method of User. Of course, typically the argument would be called self instead of user.

All the skills for a group of users:

def skill_names_3(users):
  return SkillTag.objects.filter(User__in=users).values_list('Tag_Name',flat=True)

Upvotes: 3

Related Questions