In Django ORM, A "Student - Course" Model design
I would like to design a model for an online private school in Django. It focuses on relation among Students, Tutors and Courses.
The most important factor that should be considered is that Students can add and Tutors can create courses.
I'd like to extend built-in Djano's "User" and extend its functionality.
I have designed a very draft model like this:
from django.db import models from django.contrib.auth.models import User , Group from django.utils.translation import ugettext as _ class Course(models.Model): name = models.CharField(max_length = 70) slug = models.SlugField() created = models.DateTimeField(auto_now = True) updated = models.DateTimeField(auto_now_add = True) description = models.TextField() student = models.ManyToManyField('Student' , null = True, blank = True, related_name = _('Student courses')) tutor = models.ManyToManyField('Tutor' , null = True, blank = True , related_name = _('Tutor courses')) def __unicode__(self): return self.name class Meta: verbose_name = ('course') verbose_name_plural = ('courses') class Student(models.Model): user = models.ForeignKey(User , blank = True) #photo = models.ImageField(_('photo'), upload_to='photos/', blank=True) class Tutor(models.Model): user = models.ForeignKey(User , blank = True) #photo = models.ImageField(_('photo'), upload_to='photos/', blank=True)
First of all: is it a correct approach? I'd like to have User, so I can use it in View and Template layers.
Second, how can I query that which student has got which courses?
Thank you beforehand ..
Rather than have a Student and Tutor model I would look at using the user profiles supported by Django. Also the auth module has a fairly complete permissions model, that you could use instead of creating your own system to allow only some users to create courses.
As @cberner says, you should look into user profiles. At the end of the day you want both the students and tutors be true-blue Users so you can access them from the request, after they're logged in.
That being said, there's still some merit in having separate models, as long as those are proxy models. You can think of proxy models as a type of alias. They can't add additional fields to the database, but they can have their own unique methods, managers, etc. For example:
class Student(User): class Meta: proxy = True def __unicode__(self): return u'Student: %s' % super(Student, self).__unicode__()
That's a very basic example, but it's meant to illustrate that even though this is still a User as far as the database is concerned, you can override and add methods that make it unique in its own right.
Of course, though, you'll need some way to differentiate a Student from a Tutor and even a regular old User. I find groups to be the best way to accomplish this for User proxies. For example, you can create "Student" and "Tutor" groups and then any user assigned to the "Student" group, for example, can be obtained through the Student model.
class StudentManager(models.Manager): def get_query_set(self): return self.filter(groups__name='Student') class Student(User): class Meta: proxy = True def save(self, *args, **kwargs): super(Student, self).save(*args, **kwargs) if not self.groups.filter(name='Student').exists(): group, created = Group.objects.get_or_create('Student') self.groups.add(group)
That assures that any time you create a Student, it's automatically added to the "Student" group, and if you retrieve objects with Student (e.g. Student.objects.all()), you only get Users that belong to the "Student" group.
Because these are separate models, you can also reference them individually in the admin, so you can have a separate changelist and change form for a Student, for a Tutor, and for a regular User, if you want.
Assigning them to groups also makes it very easy to restrict parts of the admin. For example, since only Tutors should be able to create, change or delete courses you can add the following methods to your CourseAdmin:
def has_add_permission(self, request): return request.user.is_superuser or request.user.groups.filter(name='Tutor').exists() def has_change_permission(self, request, obj=None): return request.user.is_superuser or request.user.groups.filter(name='Tutor').exists() def has_delete_permission(self, request, obj=None): return request.user.is_superuser or request.user.groups.filter(name='Tutor').exists()
And only superusers or members of the "Tutor" group will be able to add a brand new or change or delete an existing course.