Практический пример связи многие ко многим

Последнее обновление: 23.08.2022

Рассмотрим простейший пример приложения с моделями со связью многие ко многим. Пусть в файле models.py будут определены следующие модели:

from django.db import models

class Course(models.Model):
    name = models.CharField(max_length=30)

class Student(models.Model):
    name = models.CharField(max_length=30)
    courses = models.ManyToManyField(Course, through="Enrollment")

class Enrollment(models.Model):
    student = models.ForeignKey(Student, on_delete=models.CASCADE)
    course = models.ForeignKey(Course, on_delete=models.CASCADE)
    date = models.DateField()   # дата поступления
    mark = models.IntegerField()  # полученный балл

Здесь модели Student и Course связаны связью многие ко многим через промежуточную модель Enrollment.

В файле views.py определим пару функций-представлений для вывода и создания объектов Student:

from datetime import date
from django.shortcuts import render
from .models import Student, Course
from django.http import HttpResponseRedirect
 
# получение данных из бд
def index(request):
    # фильтрация
    students = Student.objects.all()
    return render(request, "index.html", {"students":students})

# добавление данных в бд 
def create(request):
    initialize()
    # если запрос POST, сохраняем данные
    if request.method == "POST":
        student = Student()
        student.name = request.POST.get("name")
        course_ids = request.POST.getlist("courses")
        student.save()
        # получаем все выбранные курсы по их id
        courses = Course.objects.filter(id__in=course_ids)
        student.courses.set(courses,  through_defaults={"date": date.today(), "mark":0})
        return HttpResponseRedirect("/")
    # передаем данные в шаблон
    courses = Course.objects.all()
    return render(request, "create.html", {"courses": courses})

def initialize():
    # Student.objects.all().delete()
    # Course.objects.all().delete()
    if Course.objects.all().count() == 0:
        Course.objects.create(name = "Python")
        Course.objects.create(name = "Django")
        Course.objects.create(name = "FastAPI")

Здесь определена вспомогательная функция initialize, которая запускается при старте приложения и добавляет в таблицу курсов, если таблица пустая, три курса.

функция index получае список студентов и передает их в представление index.html.

Функция create, если запрос типа POST, получает данные из запроса. Предполагается, что на сервер будут приходить id курсов. Соответственно после добавления студента для установки для него курсов сначала находим по id эти курсы в базе данных. Затем найденные курсы передаем студенту через метод student.courses.set(). Если запрос представляет тип GET, то возвращаем шаблон create.html и передаем в него список курсов.

Далее определим в каталоге приложения папку templates, а в нее добавим файл index.html для вывода всех студентов:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>METANIT.COM</title>
</head>
<body>
    <h2>Список студентов</h2>
    <a href="create/">Добавление студента</a>
    <table>
        <thead><th>Имя</th><th>Курсы</th></thead>
        {% for student in students %}
        <tr>
            <td>{{ student.name }}</td>
            <td>
                {% for course in student.courses.all %}
                    {{course.name}} 
                {% endfor %}
            </td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

И также в папке templates определим шаблон create.html для добавления студента:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>METANIT.COM</title>
</head>
<body>
    <h2>Добавление студента</h2>
    <form method="POST">
        {% csrf_token %}
        <p>
            <label>Введите имя</label><br>
            <input type="text" name="name" />
        </p>
        <p>
            <label>Выберите курсы</label><br>
            <div>
            {% for course in courses %}
                <input type="checkbox" name="courses" value="{{course.id}}" />{{ course.name}} <br />
            {% endfor %}
            </div>
        </p>
        <input type="submit" value="Сохранить" >
    </form>
</body>
</html>

При добавлении студента будет доступен выбор курсов. Для каждого курса будет создан элемент <input type="checkbox">. Его свойство value будет хранить id соответствующего курса. И таким образом при выборе определенных курсов на сервер будут отправляться их id.

В конце в файле urls.py настроим маршурты:

from django.urls import path
from hello import views

urlpatterns = [
    path("", views.index),
    path("create/", views.create),
]

Добавим одного студента:

Связь многие ко многим в Django

Подобным образом можно сделать редактирование и остальные операции с подобными моделями.

Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850