Querying a Django model with ForeignKey and ManyToMany - django

I'm trying to teach myself Django and built a simple model for a teacher listing app. There are course levels (primary, secondary, high school, etc), courses, teachers and teacher-course memberships.
I want to fetch course levels & courses whose teachers are subscribed to a specific membership. Currently I'm doing following (obviously a very bad practice, but as DB is very small it's working properly):
course_levels = CourseLevel.objects.prefetch_related('course_set')
# get mainpage teachers
# TODO: This is inefficient, there must be some cool way of doing the same.
for course_level in course_levels:
for course in course_level.course_set.
course.visible_teachers = course.teachers.filter(membership__type=Membership.TYPE_FRONT_PAGE)
And here is models.py
class Teacher(models.Model):
name = models.CharField(max_length=64)
class CourseLevel(models.Model):
name = models.CharField(max_length=64)
class Course(models.Model):
name = models.CharField(max_length=64)
# courses can have levels
level = models.ForeignKey(CourseLevel)
teachers = models.ManyToManyField(Teacher, through='Membership')
class Membership(models.Model):
(TYPE_FRONT_PAGE, TYPE_COURSE_PAGE, TYPE_BASIC) = (1,2,3)
teacher = models.ForeignKey(Teacher, related_name='membership')
course = models.ForeignKey(Course)
MEMBERSHIP_TYPES = (
(TYPE_FRONT_PAGE, _('Front Page')), # Display users on the front page
(TYPE_COURSE_PAGE, _('Course Page')), # Display users on the front of course page
(TYPE_BASIC, _('Basic Membership')), # Display users after
)
type = models.IntegerField(max_length=2, choices=MEMBERSHIP_TYPES)
What's the better way to fetch these records, instead of iterating over courses and fetching related teachers in Django Query API?
Thanks in advance.

I am not sure it this exactly answers what you want but, is this the type of search you want to do?
Membership.objects.filter(type = 1, course__level__name = 'college')
I made two teachers, both who are type 1, both teach the class 'fun', and one who teaches 'fun' in 'college' and another who teaches 'fun' in 'grade'. Here are these outputs of a couple of searches:
>>> members = Membership.objects.filter(type=1)
>>> members
[<Membership: Membership object>, <Membership: Membership object>]
>>> members.filter(course__level__name='college')
[<Membership: Membership object>]
>>> Membership.objects.filter(type=1, course__level__name='college')
[<Membership: Membership object>]
Maybe this search is most like the one you were asking for:
>>> Membership.objects.filter(course__name='fun', type=1)
[<Membership: Membership object>, <Membership: Membership object>]

Related

How to get the relation between user in my app?

Suppose there is family, each family member can login to my app, when the user login, I want to show the relation between him and the other family member instead of just the family member name.
the real challenge is the relation is dynamic according to the login user, for example:
A is the father of B
C is the wife of B
B and C have a child D
if D login the relation will be
A = granddad
B = father
C = mother
D = me
but if A log in , the relation will be
A = me
B = son
C = daughter in law
D = grandson
the example is fairly simple but the real world situation is much more complicated, like borther and sister, aunt,uncle etc.
Am using django and this is how my model is defined:
class UserProfile(models.Model):
user = models.OneToOneField(User)
family = models.ManyToManyField(FamilyProfile,related_name='family_members')
realname = models.CharField(max_length=100)
date_of_birth = models.DateField(
'user born date', null=True, blank=True)
is_male = models.BooleanField(default=False) # True male
relation_level = models.IntegerField(null=False,blank=False,default=9999)
is_foreign = models.BooleanField(default=False) # True foreign
is_host = models.BooleanField(default=False) # Ture host,
objects = profileManager()
because the relation ship is dynamic , I can't save it to the database, instead, I use the profileManager to calculate the relation ship and add it to the member: member.relation_name, but this is too complicated for me, right now I'm using a lot of if...else statement and its really long, and really stupid, so please help me with this problem .
If you look at it from a DB point-of-view the correct way to do this is to add an 'id' field to the UserProfile model, and also add another class like:
class Relations(models.Model):
relation_id = models.IntegerField()
relation_name = models.CharField()
which would be filled with the relations (like: (1, "son of"), (2, "father of"), etc..) (you might also need to make one string for male and one for female. That's the least interesting point here.
After you've created this list of Relations you need to assign the relations to users, and therefore we make another model:
class UserToRelations(models.Model):
user_a_id = models.IntegerField()
user_b_id = models.IntegerField()
relation_id = models.IntegerField()
[You might just do that with the keys, I really don't remember django that well]
So now you need to populate the UserToRelations table just each time you add a member to the DB. You calculate the relationships there.
The selecting part is where you see the profit of this. Every time a member logs in, you just need to get all the relevant rows from the UserToRelations model and you just present them.

Django Query Does not exist

I'm been trying to create an app that allows users to follow each other profile since yesterday and today and I haven't been successful so far.
I'm having trouble creating a following function that allows me to retrieve users from a particular user he follows.
Example . If John follows Diana . I want to able to retrieve the user called Diana and use it with my modules.
I'm really sorry if this doesn't make sense . I'm trying my hardest to explain my situation.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
class Board(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
def __unicode__(self):
return self.name
Most of these solutions gave me no query
This was one of the solutions I tried.
class UserLink(models.Model):
from_user = models.ForeignKey(User , related_name = "following_set")
to_user = models.ForeignKey(User , related_name = "follower_set")
date_added = models.DateTimeField(default = datetime.now)
def __unicode__(self):
return "%s is following %s" % (self.from_user.username,self.to_user.username)
def save(self,**kwargs):
if self.from_user == self.to_user:
raise ValueError("Cannot follow yourself ")
super(UserLink , self).save(**kwargs)
class Meta:
unique_together = (('to_user','from_user'),)
I tried to retrieve the users that a particular user followed and use it against my modules such as Person but it gave me an error No query exist.
def Follow(request,username=""):
if request.method == "POST":
username = request.POST.get('follow',False)
user = User.objects.get(username=username)
UserLink.objects.create(from_user=request.user,to_user=user)
return HttpResponseRedirect(reverse('world:Profile'))
return HttpResponseRedirect(reverse('world:Profile'))
I also tried this following function but it only followed himself and I changed self to User but it didn't allow me to put the person to follow
class UserProfile(models.Model):
user = models.OneToOneField(User)
follows = models.ManyToManyField('self', related_name='followed_by', symmetrical=False)
>>>from pet.models import *
>>>from django.contrib.auth.models import User
>>>user = User.objects.get(username='Peter')
>>>user1 = User.objects.get(username='Sarah')
>>>p = UserProfile.objects.filter(user=user,follows=user1)
>>>Error no field called follows
How can I create a following class that allows retrieve the people that they followed and use it with my modules such as Person?
Can someone help me . Thannk you community!
If I understand correctly, youu are on the right track with the many to many relationship. What you need is to modify your existing Person class to include this information.
Since information about who someone follows or is following is essentially information about that person and so you shouldn't really need to define a new class to implement that functionality.
I would suggest modifying your Person like so.
class Person(models.Model):
user = models.ForeignKey(User)
name = models.CharField(max_length=100)
image = models.FileField(upload_to="images/",blank=True,null=True)
following = models.ManyToManyField('self', related_name='followers', symmetrical=False, blank=True, null=True)
What this line does is makes a many to many relationship between the class Person and its self.
Many to many relationships work a little different to other relationships and I suggest you read the Django documentation https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/.
But you should now be able to setup and access the relationship like this.
>>>john = Person.objects.get(name="John")
>>>diana = Person.objects.get(name="Diana")
>>>john.following.add(diana)//setup the many to many relationship
>>>john.save()
>>>john.following.all()
//This should return a queryset of Person objects which john is following.
//eg Diana
>>>diana.followers.all()
//This should return a queryset of Person objects which are following Diana.
//eg. John.
Easy, how awesome is Django!

DRY django models, creating a list of objects

I have some model for a user profile and I want to be able to store several types of information but with some deferences (like a home or work phone number) but I don't want to use a ForeignKey relation ...how would I do that?
something like:
class Profile(models.Model):
phone = ? list of some kind ?
class Phone(???):
TYPE_CHOICES = (
('H', 'Home'),
('W', 'Work'),
('F', 'Fax'),
)
type = models.CharField(max_length = 1, choices = TYPE_CHOICES)
number = models.CharField(max_length = 16)
private = models.BooleanField()
Thank you!
Edit: I didn't want to use a foreign key just because I originally wanted all information relating to a user to show up on the profile admin page. but... meh... that's not too critical
Why don't you want to use a foreign key? If you want to have multiple phone numbers, that's the way you need/must do it.
It's easy to work with Django and foreign keys, and you can easily add an inline model formset into the admin page to create/edit a user profile with plenty of phone numbers.
Your models should look like this:
class Profile(models.Model):
name = models.CharField(max_length=40, verbose_name="User name")
class Phone(models.Model):
TYPE_CHOICES = (
('H', 'Home'),
('W', 'Work'),
('F', 'Fax'),
)
profile = models.ForeignKey(Profile)
type = models.CharField(max_length = 1, choices = TYPE_CHOICES)
number = models.CharField(max_length = 16)
private = models.BooleanField()
Then, you could use something like this to easily add/edit multiple phone numbers per profile in one admin page.
In your example, you should do something like this (inside admin.py file, in your django app):
class PhoneInline(admin.TabularInline):
model = Phone
class ProfileAdmin(admin.ModelAdmin):
inlines = [
PhoneInline,
]
admin.site.register(Profile, ProfileAdmin)
Now, you can go to the admin interface and try to add a new profile. You will see that you can add multiple phones per profile. I hope it helps you...
Finally, i'll recommend you to take a tour on django's tutorials. You will understand a lot of things and you will get a good idea of how to work with it.

In Django, how can I perform the following many-to-many query (using a through table)?

In my model I have a table for users (who are students or instructors - I have a UserProfile table that is connected to auth.User), a table for courses, and a table called enrollment, which records which students are enrolled in which courses. My models.py is as follows:
class Course(models.Model):
name = models.CharField(max_length=40)
instructor = models.ForeignKey(UserProfile, related_name="Instructor")
students = models.ManyToManyField(UserProfile, through='Enrollment')
class UserProfile(models.Model):
user = models.OneToOneField(User, primary_key=True)
role = models.CharField(max_length=4, choices=ROLE_CHOICES) # 'stud' or 'inst'
class Enrollment(models.Model):
course = models.ForeignKey(Course)
student = models.ForeignKey(UserProfile)
For a given User, I would like to find all the courses s/he is enrolled in. How can I do this?
Also, where can I find a thorough explanation of how to do queries in Django, preferably with lots of examples that slowly increase in complexity?
If you have a UserProfile instance user_profile, then try:
courses = Course.objects.filter(students=user_profile)
if you have a User instance user, then you can use double underscore notation.
courses = Course.objects.filter(students__user=user)
For an explanation, I would start with the django docs for Making queries. Other people might have some other suggestions.
As an aside: in this case, unless you are using a legacy db, you don't really need to explicitly define the joining table Enrollment, as you haven't defined any extra fields.
If instead of a User instance you have the username field from the User instance you could do the following:
courses = Course.objects.filter(students__user__username='thespecificusername')
The scenario you're constructing is very similar to the one discussed here: https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships

Represent a Mixture with a Django Model

I'm trying to represent a mixture in Django. Something like:
Chemical #1 - 50%
Chemical #2 - 30%
Chemical #3 - 20%
I figured I would use a wrapper called composition as follows:
class Composition(models.Model):
""" Just a Wrapper """
def save(...):
#Validate ingredients add up to 100% and such
class Ingredient(models.Model):
composition = models.ForeignKey('Composition',related_name='ingredients')
name = models.CharField(max_length = 10)
percentage = models.IntegerField()
I'm pretty sure there's a better way to do this. Keep in mind that I'm doing it like this so I can later use inlines in the Django admin. What do you guys recommend? Thanks a lot =)
It seems to me as though it would be preferable to keep a list of ingredients then reference those when you create your compositions, rather than entering the ingredient names each time. You could do it using a many to many relationship and a through table, like so:
class Ingredient(models.Model):
name = models.CharField(max_length=10)
class Composition(models.Model):
name = models.CharField(max_length=255)
ingredients = models.ManyToManyField(Ingredient, through='CompositionIngredient')
def save(...):
#Validate ingredients add up to 100% and such
class CompositionIngredient(models.Model):
composition = models.ForeignKey(Composition)
ingredient = models.ForeignKey(Ingredient)
proportion = models.DecimalField()
See the Django docs for more information.
EDIT: Here's the documentation on how to deal with through tables in the admin interface.