Reputation: 78
Suppose that you want to simulate universities system, you have courses, teachers and students. We have some courses that are taught by some teachers and students choose some courses with some teachers.
For example:
Courses: math, physics
Teachers: Jack(math), Jane(math, physics)
Students: st1(math with Jack), st2(math with Jane), st3(physics with Jane and cant choose Jack!!), every score by default=-1.
With this code:
teachers = models.ManyToManyField(teacher.objects.filter(t_courses=s_courses), verbose_name='Ostad')
I got errors like:
raise AppRegistryNotReady("Models aren't loaded yet.")
and
django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet
from django.db import models
class profile(models.Model):
n_id = models.IntegerField(primary_key=True, verbose_name='code melli')
name = models.CharField(max_length=24, verbose_name='Full Name')
class Meta:
ordering = ('name',)
class course(models.Model):
name = models.CharField(max_length=24, verbose_name='Class Name')
unit = models.SmallIntegerField()
class Meta:
ordering = ('name',)
def __str__(self):
return self.name
class teacher(profile,models.Model):
t_id = models.AutoField(primary_key=True)
t_courses = models.ManyToManyField(course, verbose_name='Dars')
def __str__(self):
return self.name
class student(profile,models.Model):
s_id = models.AutoField(primary_key=True)
s_courses = models.ManyToManyField(course, verbose_name='Dars')
#teachers = ??????????????????????????
score = models.IntegerField(default=-1, verbose_name='Nomre')
def __str__(self):
return self.name
How do I code in the teachers part?
Thanks a lot.
Upvotes: 1
Views: 614
Reputation: 20682
You're trying to do two different things here: Define which teacher gives a course for each specific student and restrict the choices (which is more a validation thing).
You're missing the actual Class
model which links the course to the teacher and that you can use to define which classes the student is following:
class Teacher(models.Model):
name = models.CharField(max_length=100)
courses = models.ManyToManyField(Course, through="Class", related_name="teachers")
class Class(models.Model):
teacher = models.ForeignKey(Teacher, related_name="classes")
course = models.ForeignKey(Course, related_name="classes")
class Student(models.Model):
classes = models.ManyToManyField(Class)
The Class
model is now your intermediate model for linking teachers to courses. You could also add more information about the class, such as its number, schedule (e.g. list of weekdays and hours the class takes place) and room number. Now you can fetch all the other things like that:
# all courses a teacher teaches
teacher.courses.all()
# all teachers of a student
[class.teacher for class in student.classes.all()] # list
Teacher.objects.filter(classes__in=student.classes.all()) # QuerySet
# all courses of a student
Course.objects.filter(classes__in=student.classes.all())
Now because you associate the student with the a Class
instance, you can't select a wrong teacher. If for example you have a form where the user can pick a course, you'd present the classes belonging to that course in order to link the student to a course/teacher combination:
# teachers for a course
course.teachers.all()
If you want to keep track of the marks of the students for each class, you can add a Mark
model as an intermediate model for your m2m relationship:
class Mark(models.Model):
student = models.ForeignKey(Student, related_name='marks' ...)
class = models.ForeignKey(Class, ...)
grade = models.DecimalField(max_digits=3, decimal_places=1, default=-1)
class Student(models.Model):
classes = models.ManyToManyField(Class, through='Mark', related_name='students')
But probably a more suitable model is to keep track of all the marks, e.g. when there are many exams for one class and you want to keep track of all the results. Then you just keep the Mark
model above but don't use it as intermediate model to classes. In that way a student can have multiple grades for the same class:
student = Student.objects.get(id=1)
student.marks.filter(class__name='math').aggregate(Avg('grade'))
>> {'grade__avg': Decimal('8.3')}
Upvotes: 3