I couldn't solve it with the m2m field.
It's a little complicated, but you can get the result you want with the code below.
models.py
from django.db import models
class CourseRelation(models.Model):
low_level = models.ForeignKey(
'course.Course',
models.CASCADE,
related_name='relations_me_low'
)
high_level = models.ForeignKey(
'course.Course',
models.CASCADE,
related_name='relations_me_high'
)
def __str__(self):
return '%s -> %s' % (self.low_level, self.high_level)
class Course(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
@property
def pre_req_courses(self):
course_ids = CourseRelation.objects.filter(high_level=self).values('low_level')
return Course.objects.filter(id__in=course_ids)
@property
def next_courses(self):
course_ids = CourseRelation.objects.filter(low_level=self).values('high_level')
return Course.objects.filter(id__in=course_ids)
shell
>>> python_course = Course.objects.create(name='Python')
>>> web_course = Course.objects.create(name='Web')
>>> django_course = Course.objects.create(name='Django')
>>> CourseRelation.objects.create(low_level=python_course, high_level=django_course)
<CourseRelation: Python -> Django>
>>> CourseRelation.objects.create(low_level=web_course, high_level=django_course)
<CourseRelation: Web -> Django>
>>> python_course.pre_req_courses
<QuerySet []>
>>> python_course.next_courses
<QuerySet [<Course: Django>]>
>>> django_course.pre_req_courses
<QuerySet [<Course: Python>, <Course: Web>]>
>>> django_course.next_courses
<QuerySet []>
update
When I read Abdul Aziz Barkat's comment, I realized that a single line would solve it.
pre_req_courses = models.ManyToManyField(
'self',
related_name='next_courses',
symmetrical=False
)