To implement many-to-many correctly with peewee, you will therefore create the intermediary table yourself and query through it:

    To query, let’s say we want to find students who are enrolled in math class:

    1. .select()
    2. .join(StudentCourse)
    3. .join(Course)
    4. .where(Course.name == 'math'))
    5. for student in query:
    6. print(student.name)

    To query what classes a given student is enrolled in:

    To efficiently iterate over a many-to-many relation, i.e., list all students and their respective courses, we will query the through model StudentCourse and precompute the Student and Course:

    1. query = (StudentCourse
    2. .select(StudentCourse, Student, Course)
    3. .join(Course)
    4. .switch(StudentCourse)
    5. .join(Student)
    6. .order_by(Student.name))

    Since we selected all fields from Student and Course in the select clause of the query, these foreign key traversals are “free” and we’ve done the whole iteration with just 1 query.

    The provides a field-like API over many-to-many fields. For all but the simplest many-to-many situations, you’re better off using the standard peewee APIs. But, if your models are very simple and your querying needs are not very complex, ManyToManyField may work.

    Modeling students and courses using :

    1. from peewee import *
    2. db = SqliteDatabase('school.db')
    3. class BaseModel(Model):
    4. database = db
    5. class Student(BaseModel):
    6. name = CharField()
    7. class Course(BaseModel):
    8. name = CharField()
    9. students = ManyToManyField(Student, backref='courses')
    10. StudentCourse = Course.students.get_through_model()
    11. db.create_tables([
    12. Student,
    13. Course,
    14. StudentCourse])
    15. # Get all classes that "huey" is enrolled in:
    16. huey = Student.get(Student.name == 'Huey')
    17. for course in huey.courses.order_by(Course.name):
    18. print(course.name)
    19. # Get all students in "English 101":
    20. engl_101 = Course.get(Course.name == 'English 101')
    21. print(student.name)
    22. # When adding objects to a many-to-many relationship, we can pass
    23. # in either a single model instance, a list of models, or even a
    24. # query of models:
    25. huey.courses.add(Course.select().where(Course.name.contains('English')))
    26. engl_101.students.add(Student.get(Student.name == 'Mickey'))
    27. engl_101.students.add([
    28. Student.get(Student.name == 'Charlie'),
    29. Student.get(Student.name == 'Zaizee')])
    30. # The same rules apply for removing items from a many-to-many:
    31. huey.courses.remove(Course.select().where(Course.name.startswith('CS')))
    32. engl_101.students.remove(huey)
    33. # Calling .clear() will remove all associated objects:
    34. cs_150.students.clear()

    Attention

    Warning

    It is strongly recommended that you do not attempt to subclass models containing ManyToManyField instances.

    A , despite its name, is not a field in the usual sense. Instead of being a column on a table, the many-to-many field covers the fact that behind-the-scenes there’s actually a separate table with two foreign-key pointers (the through table).

    Therefore, when a subclass is created that inherits a many-to-many field, what actually needs to be inherited is the through table. Because of the potential for subtle bugs, Peewee does not attempt to automatically subclass the through model and modify its foreign-key pointers. As a result, many-to-many fields typically will not work with inheritance.