A naive Django model could look like this:
from django.db import models
class Graph(models.Model):
name = models.CharField(max_length=100)
description = models.TextField()
class Node(models.Model):
name = models.CharField(max_length=100)
graph = models.ForeignKey(Graph, on_delete=models.CASCADE)
class Edge(models.Model):
name = models.CharField(max_length=100)
graph = models.ForeignKey(Graph, on_delete=models.CASCADE)
from_node = models.ForeignKey(Node, on_delete=models.CASCADE, related_name="from_node")
to_node = models.ForeignKey(Node, on_delete=models.CASCADE, related_name="to_node")
This lets you store arbitrary graph information. In your case the nodes would be the courses and the edges would be the dependencies. For working with this information a relational database is not an ideal tool. Maybe you could minimize queries by querying a whole graph and process this data with graph related tools like e.g. NetworkX.
Another issue of this model I would like to point out is that it is generally possible to store edges that go from one to another graph. Also other graph related properties like duplicate edges or loops have to be considered.