Рассмотрим простейший пример приложения с моделями со связью многие ко многим. Пусть в файле 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), ]
Добавим одного студента:
Подобным образом можно сделать редактирование и остальные операции с подобными моделями.