Django MPTT filter on related model - django

Let's say I have a model Album:
class Genre(MPTTModel):
name = models.CharField(max_length=50, unique=True)
parent = TreeForeignKey('self', null=True, blank=True, related_name='children', db_index=True)
And a model called Album like this
class Album(models.Model):
name = models.CharField(..)
...
genre = models.ForeignKey(Genre)
Let's also assume I have the following Genres:
Rock
- Hard Rock
- Classic Rock
Pop
....
Is it possible to filter all albums that have genres (or ancestor genres) ids in a list?
Basically, what I want to do:
Album.objects.filter(genre__ancestors__in=[id_of_rock, id_of_classical])
The closest thing I found is this:
genre_list = []
for id in genres:
genre_list.append(Genre.objects.get(pk=id).get_ancestors(include_self=True)
Album.objects.filter(genre__in=genre_list)
But that's pretty expensive. I'm sure it can be done in a single query using some MPTT strategy, but I couldn't find a thing online. Any help?

Related

Django access manytomany field from related_name in a view

I have what i think is a simple question but I am struggling to find out how it works. I get how related name works for foreign keys but with many to many fields it seems to break my brain.
I have two 3 models at play here. A User, TeamMember and Team Model as seen below.
User model is the built in django model.
#TeamMember Model
class TeamMember(models.Model):
member = models.ForeignKey(User, on_delete=models.SET(get_default_team_member), verbose_name='Member Name', related_name="team_members")
...
#Team Model
class Team(models.Model):
name = models.CharField(max_length=50)
manager = models.ForeignKey(TeamMember, on_delete=models.SET_NULL, related_name="managers", null=True, blank=True)
team_lead = models.ForeignKey(TeamMember, on_delete=models.SET_NULL, related_name="tls", null=True, blank=True)
tps = models.ForeignKey(TeamMember, on_delete=models.SET_NULL, related_name="tps", null=True, blank=True)
members = models.ManyToManyField(TeamMember, blank=True, related_name="members")
...
Now in a view i want to access a specific users team. I thought i could do this by doing something like this:
member = TeamMember.objects.get(pk=1)
member_team = member.members.name
However if I print member_name than it prints nothing. If I try to access any of the other fields on that model like member.members.team_lead.first_name it fails to find the team_lead field. I understand that this has a .all() attribute but i thought it was tied to the team object through the members field. So if that member matches the team it would give me the team. So I thought it might be an issue if the same member was linked to more than one team (which is possible) so i tired something like this member.members.all().first().name and i get an error that states it cannot get name from NoneType.
Is there an easy way to get the team name from a relationship like this or am i better off just doing a team query with the user?
Thanks,
jAC
First of all, I would like to point out that you are not using the related_name (and related_query_name parameters in a proper way). I think this SO post will help you to understand the concept in a better way.
So, I would change the related_name (and related_query_name) values in the Team model as below,
class Team(models.Model):
name = models.CharField(max_length=50)
manager = models.ForeignKey(
TeamMember,
on_delete=models.SET_NULL,
related_name="teams",
related_query_name="team",
null=True,
blank=True,
)
team_lead = models.ForeignKey(
TeamMember,
on_delete=models.SET_NULL,
related_name="teams",
related_query_name="team",
null=True,
blank=True,
)
tps = models.ForeignKey(
TeamMember,
on_delete=models.SET_NULL,
related_name="teams",
related_query_name="team",
null=True,
blank=True,
)
members = models.ManyToManyField(
TeamMember, blank=True, related_name="teams", related_query_name="team"
)
...
Now in a view i want to access a specific user's team.
Since the Team and TeamMember models are connected via ManyToManyField, you may have "zero or more" Teams associated with a single TeamMember
So, the following query will get you all the teams associated with a particular TeamMemeber
team_member = TeamMember.objects.get(pk=1)
all_teams = team_member.teams.all()
You can also iterate over the QuerySet as,
team_member = TeamMember.objects.get(pk=1)
for team in team_member.teams.all():
print(team.name)
For anyone wondering what I did based on JPG's advice was the for loop option
team_member = TeamMember.objects.get(pk=1)
teams = [t.name for t in team_member.members.all()]
I personally do not care which team i get as my need in this case is just to pass a team through even if it is none. So i just use team = team[0] if teams.count() > 0 else "No team"

which is the better design of database for article Like function?

I'm using Django to develop a news website.Now I'm developing the like function in news detail page, this function is like that at the bottom of the news, there is a like button, once you click it the amount of like will add 1.
Now I have 2 choices to design the table of the database in django we call it model.I'm not sure which design is better.
First:just use one News model
class News(models.Model):
...code..
is_up = models.BooleanField(default=True)
up_count = models.IntegerField(default=0)
Once is_up ,up_count will add 1.
Sceond:use 2 models,News model and a separate Like model
class News(models.Model):
...code..
up_count = models.IntegerField(default=0)
class Like(models.Model):
"""
点赞表
"""
nid = models.AutoField(primary_key=True)
user = models.ForeignKey('UserInfo', null=True, on_delete=models.CASCADE)
news = models.ForeignKey("News", null=True, on_delete=models.CASCADE)
is_up = models.BooleanField(default=True)
class Meta:
unique_together = [
('news', 'user'),
]
Any friend can tell which design is better ?
If you use the second one, you can know more information, depending on whether you need the data, or you can use ManyToManyField like this:
class News(models.Model):
...code..
likes = models.ManyToManyField('UserInfo')
This will record who liked this news.

Model design on alternative ingredients name

I am creating a simple application that captures the name of a product along with their respective ingredients. I have 2 models defined in my Django app for that
class Product(models.Model):
name = models.CharField(max_length=150, blank=False)
class Ingredient(models.Model):
# 1 ingredient belongs to many products.
products = models.ManyToManyField(Product)
name = models.CharField(max_length=150, blank=False)
As I was looking at random products and their ingredients, I noticed that there are alternative names of to an ingredient. For example, certain manufacturers would put water as, aqua, h2o, eau, purified water, distilled water and so on.
How can I best write a model that is able to capture these alternative names in an efficient manner?
I thought of putting in additional fields such as
alternativeName1 = models.CharField(max_length=150, blank=True)
alternativeName2 = models.CharField(max_length=150, blank=True)
alternativeName3 = models.CharField(max_length=150, blank=True)
But it doesn't seem like a good application design.
I suggest you to create a Variation model having foreign of Ingredient model, name and manufacturer information. This means you have many variations of a ingredient
class Variation(models.Model):
ingredient = models.ForeignKey(Ingredient, related_name="variations")
name = models.CharField(max_length=150, blank=False)
manufacturer = models.CharField(max_length=150, blank=False)
So in future if there are more names for any ingredient you can easily keep it.
Or alternatively you can add a JSONField() to Ingredient model
class Ingredient(models.Model):
...
# add json field and keep all name and manufacturer detail in dictionary
# [{'name':'aqua', 'manufacturer':'vendor name'},{},...]
data = JSONField()

Tree Database Design in Django for Organisation Feature

I want to implement an organisation feature in django 1.8.
- Organisation has multiple teams belonging to it.
- Any team can have multiple team below/under it.
I started with this core, but I don't know is this the good way to design model structure.
class Organisation(models.Model):
name = models.CharField(max_length=64)
description = models.TextField(max_length=1024)
logo = models.ImageField()
class Team(models.Model):
organisation = models.ForeignKey(Organisation)
name = models.CharField(max_length=64)
class ParentTeam(models.Model)
parent_team = models.OneToOneField(Team, null=True, blank=True)
child_team = models.ManyToManyField(Team)
Am I doing right or there should be other way to design?
Thanks,
You can club Team and ParentTeam model into one as
class Team(models.Model):
organisation = models.ForeignKey(Organisation)
name = models.CharField(max_length=64)
child_teams = models.ManyToManyField('self', blank=True, related_name='children')
Its something I would have done with it.

Group by in manytomany fields in Django

Ive got a simple task. There are two models
class Song(models.Model):
song_title = models.CharField(max_length=200)
song_genres = models.ManyToManyField(Genres, null=True, related_name='genres')
...
class Genre(models.Model):
genre_title = models.CharField(max_length=50)
genre_uri = models.SlugField(max_length=100, unique=True, blank=True)
...
I need to get list of most popular tags with song's count. For example:
[{<Genres: Pop>, 20}, {<Genres: Rap>, 15} ...]
For foreign key i can use
Song.objects.annotate(count=Count('song_genres')).order_by('-count')[:5]
but it doesn't work with manytomany fields. Any help would be much appreciated.
Assuming related_name on song model is 'songs', because it should be.
Genres.objects.annotate(songs_count=Count('songs')).order_by('-songs_count')[:10].values('id', 'songs_count')
This will give you id of all top 10 generes and songs_count in them.