In this lesson, we will explore how to apply inheritance as well as class attributes and methods.
Imagine you are working for a school administration. You want to keep track of all the students and all the courses. In this case, thinking about the relationship between the two, we can say that:
- A student has many courses
- A course has many students
This makes it a many-to-many relationship.
We can use a schedule table to connect them.
- Create intermediary class
- Build relationships to allow access between classes
- Build properties to ensure class connection
- GitHub repo: python-many-to-many-technical-lesson
Before we begin coding, let's complete the initial setup for this lesson:
- Go to the provided GitHub repository link.
- Fork the repository to your GitHub account.
- Clone the forked repository to your local machine.
- Open the project in VSCode
- Run
pipenv installto install all necessary dependencies - Run
pipenv shellto enter the virtual environment.
You need to build out a relationship between students and courses.
You will be tasked with:
- Creating an intermediary class
- Building relationships to allow access between classes
- Building properties to ensure class connection
Attributes:
- Student
- Course
- Grade
Properties:
- Student
- Course
Attributes:
- Title
- Teacher
Methods:
students
Attributes:
- Name
Methods:
coursescalculate_gpa
git checkout -b many-to-manyEnsure you understand Student and Course models. Then build the connecting Schedule class:
File: lib/many_to_many.py
class Student:
all =[]
def __init__(self, name, email):
self.name = name
self.email = email
Student.all.append(self)
class Course:
all =[]
def __init__(self, title, teacher):
self.title = title
self.teacher = teacher
Course.all.append(self)
class Schedule:
all =[]
def __init__(self, student, course, grade):
self.student = student
self.course = course
self.grade = grade
Schedule.all.append(self)Add properties to require that Schedule uses instances of Student and Course:
class Schedule:
all =[]
def __init__(self, student, course, grade):
self.student = student
self.course = course
self.grade = grade
Schedule.all.append(self)
@property
def student(self):
return self._student
@student.setter
def student(self, value):
if not isinstance(value, Student):
raise Exception
self._student = value
@property
def course(self):
return self._course
@course.setter
def course(self, value):
if not isinstance(value, Course):
raise Exception
self._course = valueAdd methods to link Student ↔ Course through Schedule.
class Student:
all =[]
def __init__(self, name, email):
self.name = name
self.email = email
Student.all.append(self)
def courses(self):
return [schedule.course for schedule in Schedule.all if schedule.student == self]
class Course:
def __init__(self, title, teacher):
self.title = title
self.teacher = teacher
Course.all.append(self)
def students(self):
return [schedule.student for schedule in Schedule.all if schedule.course == self]Build a calculate_gpa() method in Student:
class Student:
...
def calculate_gpa(self):
my_courses = self.courses()
summative = 0
for course in my_courses:
summative += course.grade
return summative / len(my_courses)Use this to calculate a student's GPA based on course grades via Schedule.
git commit -am "Completed many to many models"
git push origin many-to-many- Create a Pull Request (PR) on GitHub
- Merge the PR into
mainafter review
Then, pull the updated main branch and clean up:
git checkout main
git pull origin main
git branch -d many-to-many
# If needed:
git branch -D many-to-many- Add comments to explain code
- Clarify intent/functionality for others
- Add screenshots of completed work to README
- Update README text following makeareadme.com
- Delete stale branches
- Remove commented/unnecessary code
- Update
.gitignorefor sensitive data
Ternaries are used to clean up for-loops. For example:
# Standard loop
all_students = []
for schedule in Schedule.all:
if schedule.course == self:
all_students.append(schedule.student)
return all_students
# Same as:
return [schedule.student for schedule in Schedule.all if schedule.course == self]You can treat your own classes the same way you check for int or str using isinstance():
if not isinstance(value, Student):
raise Exception