django queryset for many-to-many field - django

I have the following Django 1.2 models:
class Category(models.Model):
name = models.CharField(max_length=255)
class Article(models.Model):
title = models.CharField(max_length=10, unique=True)
categories = models.ManyToManyField(Category)
class Preference(models.Model):
title = models.CharField(max_length=10, unique=True)
categories = models.ManyToManyField(Category)
How can I perform a query that will give me all Article objects that are associated with any of the same categories that a given Preference object is related with?
e.g. If I have a Preference object that is related to categories "fish", "cats" and "dogs", I want a list of all Articles that are associated with any of "fish", "cats" or "dogs".

Try:
preference = Preference.objects.get(**conditions)
Article.objects.filter(categories__in = preference.categories.all())

Article.objects.filter(categories__in=myPreferenceObject.categories.all())

Related

Django query categories, exclude those without posts

I have these two models, post and categories.
class Category(models.Model):
""" Categories """
name = models.CharField(max_length = 80, help_text="Enter a descriptive and unique category name.")
slug = models.SlugField(max_length = 250, help_text="The slug is used to link category pages.")
class Post(models.Model):
""" Blog posts """
author = models.ForeignKey(User, related_name='blog_posts', on_delete = models.CASCADE)
category = models.ForeignKey(Category, related_name = 'blog_posts', on_delete = models.CASCADE)
title = models.CharField(max_length=250)
body = models.TextField(help_text = "Type your blog post using plain text or mark-down format.")
I am trying to query all the categories that have posts, excluding categories which don't have yet posts. The SQL equivalent of:
SELECT * FROM category WHERE id IN (SELECT DISTINCT(category_id) FROM post)
Many thanks!
You can use annotation to count the posts and then filter based on the result:
from django.db.models import Count
Category.objects.annotate(posts_count=Count("blog_posts")).filter(post_count__gt=0)

How do I create this queryset?

I have the following three models:
class Category(models.Model):
name = models.CharField(max_length=120)
class Experiment(models.Model):
name = models.CharField(max_length=50, unique=True)
categories = models.ManyToManyField(Category)
class Ad(models.Model):
experiment = models.ForeignKey(Experiment, related_name='ads', on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.PROTECT, blank=True, null=True)
I want to create a queryset which returns all ads where ad.category is in ad.experiment.categories.
Some example data to talk through:
Category: ['Cat1', 'Cat2', 'Cat3', Cat4', 'Cat5']
Experiment: [['Exp1',['Cat2','Cat3]],['Exp2',['Cat5','Cat1']]]
Ad: [['Exp1','Cat4'],['Exp1','Cat2']]
The queryset I'm hoping to create would only return the second ad because the ad's category is in the ad's experiment's category.
Any help would be appreciated!
You need to traverse the reverse relationship for experiment and then use an F object to access the ad's category field in the query. The distinct is used because the experiment will have many categories so one ad may have multiple matches on the comparison.
from django.db.models import F
Ad.objects.filter(experiment__category=F('category')).distinct()

How to write model for tags database

I want to create an object with tags and categories. I read on https://stackoverflow.com/a/20871 that the tags schema should be like this,
> Table: Item Columns: ItemID, Title, Content
>
> Table: Tag Columns: TagID, Title
>
> Table: ItemTag Columns: ItemID, TagID
However, I want to associate every tags with a category.
What I want is an item can have only one category and multiple tags. And the tags are also associated with/group in the category.
I am not very clear how to use the model relationship, this is what I come up with:
class Item(models.Model):
title = models.CharField(max_length=100)
content = models.TextField(blank=True)
class Tags(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
class ItemTag(models.Model):
itemid = models.ForeignKey(Item) #not sure if this is correct to use foreignkey
tagid = models.ForeignKey(Tags)
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
#not sure how to do this category grouping
class CategoryTags(models.Model):
catid = models.Foreignkey(Category)
tagid = models.Foreignkey(Tags)
There are plenty tags will be created, and it will be use in the search keyword for the Items. Not sure if this is the best idea to cope with.
Based on your task description (An item can have only one category and multiple tags. And the tags are also associated with/group in the category.) I'd suggest the following schema:
class Category(models.Model):
name = models.CharField(max_length=100)
slug = models.SlugField(unique=True)
class Tag(models.Model):
name = models.CharField(max_length=100, db_index=True)
slug = models.SlugField(unique=True)
# the tag belongs to a category
category = models.ForeignKey(Category, blank=True)
class Item(models.Model):
title = models.CharField(max_length=100, db_index=True)
content = models.TextField(blank=True)
# the item belongs to one category
# if having a category is required please remove blank=True
category = models.ForeignKey(Category, blank=True)
tags = models.ManyToManyField('Tag')
ForeignKey is a many-to-one relationship. In your case many items belong to one category.
See also ManyToMany field.

How to filter relationship item in Django?

Lets say I have 2 model class. Category has a name and multiple tags and Tag has a name, can be visible or not.
EDIT : Lets say that I have a list of categories and for each category I would like to only display the tags that have visible=True, how should I proceed ?
class Category(models.Model):
name = models.CharField(max_length=255, unique=True)
tags = models.ManyToManyField(Tag)
class Tag(models.Model):
name = models.CharField(max_length=255, unique=True)
visible = models.BooleanField(default=False)
Something like this:
category_list = Category.objects.all() #Or you can filter according to your choice
for c in category_list:
tagnames = c.tags.filter(visible=True).values("name")
print c.name, tagnames

django, many to many relation get_field name

I had two django models connected with many to many relationship.
First model:
class Category(models.Model):
name = models.CharField(max_length=255)
products = models.ManyToManyField(Product, related_name='categories',
blank=True, null=True,
verbose_name=_('Products'),
)
second model:
class Product(models.Model):
description = models.TextField(verbose_name=_('Description'), default='')
manifactor = models.CharField(verbose_name=_('Manifactor'), default='Blackberry', max_length=255)
ok, so:
product = Product.objects.all()[0]
product.categories - give me a list of categories for this product.
but:
product._meta.many_to_many - return empty list [].
and product._meta.get_field('categories') - return None.
Why ?
How can I get the verbose name of category field from product object ?
You can add
categories = models.ManyToManyField(Category,
through=Category.products.through)
to your Product model