How to get reverse relationship in Django's ORM - django

I usually tend to avoid giving such explicit examples, but in this case it's necessary.
I have 5 entities:
Student
Group
StudentGroup
CourseGroup
Course (not relevant -- for completeness purpose only)
StudentGroup represents students who are part of a group. A CourseGroup is a course the whole group is taking part in.
I want to get all students that are part of a Group and are taking part in a specific Course. So far, I've only managed to get all students in a group:
students = Student.objects.filter(studentgroup=1)
Not sure why I can say studentgroup=1 but it's fortunate. However there's no studentgroupcourse=1 :) Any help?
Edit: My models are: http://pastebin.com/07z1iEcw

ASSUMING CourseGroup has a foreignkey to StudentGroup and a foreignKey to a Course
Student.objects.filter(studentgroup=1, studentgroup__coursegroup__course=your_course)

Related

I'm using django to build a website and I want to link tutors and students

I'm currently stuck with the best way of assigning tutors to students and then tutors can add lessons for these students and they can both see these lessons, but you can only assign one foreign key to the class "MyLessons". So I'm not sure whether it's worth creating a MyStudents class, storing students inside this (but their user is the same as tutors except is_tutor=false) and then for each student creating a MyLessons class that the tutor can add to.
I think I can make an approach I'm just worried it won't be very efficient or there will be some serious problems later on. Such as the other way was that each lesson would auto take in the tutors email (I set the username to email) and then when displaying the tutors lessons it would go through every lesson and display the lessons with a matching email... problems are though, if I reassign a student to a new tutor I'd like the new tutor to see the lessons but this would mean manually changing each and if there are too many lessons and students the process would get slow.
A Tutor has many students. A student potentially has more than one tutor. So at first glance that's a ManyToMany relational field.
One thing that's at first confusing is that the relationship is symmetric, but is defined on one object and only implicitly on the other. But the implicit and explicit fields both work the same, for manipulating a set of relationships.
class Tutor( models.Model)
students = ManyToManyField( Student, related_name='tutors', ...)
then
student_instance.tutors.add( tutor_instance)
tutor_instance.students.add( student_instance)
both accomplish the same. (In the simplest case. Read the doc for the exceptions).
It may or may not help to know that behind the scenes, Django is manipulating an implicit table whose objects have two fields, a ForeignKey to a student and a ForeignKey to a tutor. It can sometimes be useful to make this table explicit, so you can attach extra information to the relationship such as date created, who created it, etc. Look up the "through" option of ManyToMany if you want to do this.
Further examples here.

Association attributes in a Django one-to-many foreignkey relationship

I would like to model a relationship between a Story class and a Series class.
(I.e. a trilogy of novels)
The relationship is a "one to many" (a series can contain many Stories but a Story can only be part of one Series).
Model-wise this could simply be solved by a foreign key on Story,
part_of = models.ForeignKey(Series
, on_delete=models.CASCADE
, related_name='contains_story')
But I would like a sequence number as an attribute of this relationship.
i.e. (1:The long Earth, 2:The long war, 3:The long Mars, ...).
I could make it an attribute of Story but that's not clean, a Story not part of a Series should not have a sequence number.
In a "many-to-many" this can be solved using the "through" option.
by specifying a class and adding attributes to that class.
part_of = models.ManyToManyField(Series, through='SeriesPart')
But "part of a series" is not a "many-to-many" relationship and I want to avoid modelling it like this and having to restrict it in code, so how should I solve this best?
I'm not sure your objection makes much sense. The reason why you might store an extra attribute on the through table of a many-to-many relationship is precisely because each side of the relationship can have multiple items, and the attribute value is only relevant to one specific combination. (In the case of the example in the Django docs, John was in the Quarrymen before he was in the Beatles, so there are separate joined_date values for John<->Quarrymen, John<->Beatles, and Paul<->Beatles.)
In your case, a story can only be part of one series. There is no other position for The Long Earth other than as part 1 of the Pratchett/Baxter series; it can't simultaneously be part 1 of that but also part 2 of something else. So there's no reason not to store the series number on the story model itself. Stories that are not part of a series can simply leave that blank, just like they leave the FK to Series blank.

Relation (x > 1)-to-many

It's probably more a generic question about database, than a django one but let's go.
I have very often what could be considered as 2-to-many relations.
For example, I have a class Match in my project, which is an encounter between two teams.
At first, I was using many-to-many:
Match(Model):
teams = ManyToManyField('Team', related_name='matches') #Always two teams
It ended up being very inefficient for match related pages. Especially in django 1.3, because there is no equivalent to select_related for many_to_many relation. And it's a bit painful having to iterate when you now there is exactly two elements.
Then I switched to this model :
Match(Model):
teams = ManyToManyField('Team', related_name='matches') #Always two teams
team1 = ForeignKey('Team')
team2 = ForeignKey('Team')
When I want to display match related pages, I can use select_related and display very efficiently the two teams.
And when I'm on the team page, I can follow the "matches" relation to get all the matches as before.
But I find that 3 fields to deal with one relation is totally horrible.
Am I doing it right ? What would you recommend ?
I see few solutions there.
1.
If you're not anticipating that in future a match will be played between other number of teams than two it may be best for you to just remove a ManyToMany field from your second design:
Match(Model):
team1 = ForeignKey('Team')
team2 = ForeignKey('Team')
It'll remove a redundation in a database and makes Match modifications easier (you don't have to worry about cohesion between team field and corresponding team1, team2 fields). It also makes impossible to create a Match with other number of corresponding teams than two, which leads to database consistency.
On the other hand you're losing a flexiblity and it's harder to write queries, because of two fields to check instead of one.
2.
You may want to use a cache. In fact - those two fields you have are nothing other than that, but moving it to a dedicated cache database can make it more efficient and separates your main database from cached values, which leads to a clearer database design.
3.
Write your own ManyToMany fetcher. It's not very hard to do, but rather ugly. You have to select teams you're interested in and then somehow attach them to Match objects, e.g.:
matches # Match QuerySet
related_teams = Team.objects.filter(match__in=matches)
matches_map = {}
for t in related_teams:
matches_map[t.match_id]= matches_map.get(t.match_id, []).append(t)
for m in matches:
m.fetched_teams = matches_map[m.pk]
3.5.
New version of Django will have a prefetch_related() method which is meant to work with ManyToMany queries, but I suppose you don't have so much time.

django models question

I am working on a django model and not being a database expert I could use some advice. I essentially have a model which contains a many to many relationship with another model. But I need to store unique values for each relationship each time I include something.
So for instance in chemistry you may have many elements that include hydrogen, but each element has a unique amount of hydrogen in it. So for instance a water entry would be connected to hydrogen and oxygen and the amount would be two hydrogen atoms and one oxygen.
I want hydrogen and water in this scenario to be stored in the database as elements, so I can query against them for other elements using them.
What is the best way to model this?
Thanks!
Read the documentaion here and pay close attention to the Beatles example, it's exactly what you need.
Person -> Element
Group -> Chemical_Compound
Membership -> Element_2_Chemical
Element_2_Chemical should have an int field which details how many elements you have in each chemical compound.
In your metaphor, you say "I want hydrogen and water in this scenario to be stored in the database as elements, so I can query against them for other elements using them."
Does it mean that "water" may be on any part of the relationship you are modeling? Do "water" relate to "hydrogen" in the (almost) same way as "milk" relates to "water"?
If the answer is Yes, then you should use a directed-acyclic-graph model (hopefully, you won't have cycles in your relationship: A->B->C->A). Look into the django-dag ( http://pypi.python.org/pypi/django-dag/ ) and django-treebeard-dag ( http://pypi.python.org/pypi/django-treebeard-dag/0.2 ) packages.
If the answer in No, so yo have a clear distinction between what's a "container" and what's a "containee", use a normal many-to-many rel between two different models, like the "Membership" example in django documentation ( https://docs.djangoproject.com/en/dev/topics/db/models/#extra-fields-on-many-to-many-relationships ).
In any case you'll have to add more info to the "edge" of the relationship.
Following strictly your chemical metaphor, you are maybe not modeling enough information, because some molecules have the same composition but different structure (they are called "isomers"). For instance the pentane, the 2-methylbutane and the 2,2-dimethylpropane have all five carbons and twelve hydrogens, but they are very different one another...
With this I am saying that when you are doing an "enhanced many-to-many" it's generally a complex model, so take care of not leaving anything out of it.

What are the advantages of using ForeignKey in Django?

This is an extremely naive question. As you can tell, it comes from someone who doesn't know much about either databases or Django.
What are the advantages of using ForeignKeys in Django?
Maybe an example will help me understand better. I have tables like this already:
City:
id = IntegerField() # e.g. 15
name = CharField() # e.g. 'Rome'
Country:
name = CharField() e.g. 'Italy'
capital = IntegerField() # e.g 15
Should I bother changing capital to ForeignKey(City), and if so, why? Do certain things become quicker, more convenient, or otherwise better?
thanks!
Foreign keys are constraints on your data model that allow you to ensure consistency. Basically, in your example, if you didn't have capital as a ForeignKey to a City it could potentially contain an id of a City that didn't exist! When you use ForeignKey instead, it places a constraint on the database so that you cannot remove things that are currently referenced by other things. So if you tried to delete the City named "Rome" before deleting the Country named "Italy" who has that city as its capital, it wouldn't allow you to.
Using ForeignKey instead would make sure you never had to worry about whether or not the "thing" on the other end of the relationship was still there or not.
Using ForeignKeys enables Django to "know" about the relations. So you can follow the relations without taking care about how they are stored, eg you can do the following without having to care how the relation is stored:
country = Country.objects.get(pk=1)
print country.capital.name
italy = Country.objects.get(capital__name="Rome")
Also for keeping constraints Django will follow the relations when deleting objects that are referenced by a ForeignKey. Django also keeps track of the reverse relationships (without needing to explicitly define them), so you can do something like countries = rome.country_set.all() (which makes not so much sense in this example, since it would make more sense to use a OneToOneField here...
Referential integrity. OTOH it is quite possible to have a database that neither knows nor cares about FKs - in fact I work with a legacy db like this at work.