sharataka
sharataka

Reputation: 5132

How do I display only distinct objects in a queryset that have values in them?

I have multiple objects saved in my database but I would only like to show items in my queryset that are unique and if they actually have an item saved.

models.py

class Everything(models.Model):
    profile = models.ForeignKey(User)
    playlist = models.CharField('Playlist', max_length = 2000, null=True, blank=True)
    platform = models.CharField('Platform', max_length = 2000, null=True, blank=True)
    video = models.CharField('VideoID', max_length = 2000, null=True, blank=True)
    def __unicode__(self):
        return u'%s %s %s %s' % (self.profile, self.playlist, self.platform, self.video)

views.py

playlist2 = Everything.objects.filter(profile=request.user)

template

<select name ="playlist2">
{% for item in playlist2 %}
  <option value="{{item.playlist}}">{{item.playlist}}</option>
{% endfor %}
</select>

There doesn't have to be a playlist because null=True and blank=True. Some of the items in playlist might also be duplicated. How do I show only the distinct items that have values in them?

Upvotes: 0

Views: 1869

Answers (2)

acjay
acjay

Reputation: 36691

You could just filter out all the null and blank objects.

playlist2 = Everything.objects.filter(playlist__isnull=False).exclude(playlist__exact='').distinct()

I edited the above to include handling of blanks, as noted by miki725. There's probably no need for the Q() functions though. Not that there's anything wrong with Q() functions, I just try to avoid them where readability could be increased. By DeMorgan's theorem, NOT (playlist is null OR playlist is blank) is equivalent to (NOT playlist is null) AND (NOT playlist is blank). I prefer filter to exclude, but exclude is necessary for the blanks, since there's no unequal field lookup. You could just as well exclude the null playlists, but what you can't do is combine the excludes into one call, unless you use Q functions, otherwise you get NOT (playlist is null AND playlist is blank), which is not equivalent.

Upvotes: 0

miki725
miki725

Reputation: 27869

You can use exclude and distinct queryset functions (docs).

However in your case it is not that simple since your CharField definitions allow both NULL (null=True) and empty string (blank=True) values. So that means you have to test for two conditions and for that you have to use Q (docs) objects:

 everything = Everything.objects.exclude(Q(playlist=None) | Q(playlist='')).distinct()

That is exactly why Django docs do not recommend to use null=True for string model fields (docs). Here is excerpt:

Avoid using null on string-based fields such as CharField and TextField unless you have an excellent reason. If a string-based field has null=True, that means it has two possible values for “no data”: NULL, and the empty string. In most cases, it’s redundant to have two possible values for “no data;” Django convention is to use the empty string, not NULL.

If you follow this conversion, then your filter lookup becomes much simpler:

 everything = Everything.objects.exclude(playlist=None).distinct()

Upvotes: 1

Related Questions