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 install
to install all necessary dependencies - Run
pipenv shell
to 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:
courses
calculate_gpa
git checkout -b many-to-many
Ensure 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 = value
Add 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
main
after 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
.gitignore
for 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