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
)