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

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

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

from django.db import models
class Company(models.Model):
    name = models.CharField(max_length=30)
 
class Product(models.Model):
    company = models.ForeignKey(Company, on_delete = models.CASCADE)
    name = models.CharField(max_length=30)
    price = models.IntegerField()

здесь определены модели Company и Product, которые связаны связью "один-ко-многим": одна компания может иметь множество товаров.

В файле views.py определим все необходимые представления для работы с объектами Product:

from django.shortcuts import render
from .models import Company, Product
from django.http import HttpResponseRedirect, HttpResponseNotFound
 
# получение данных из бд
def index(request):
    products = Product.objects.all()
    return render(request, "index.html", {"products": products})

# добавление данных из бд
def create(request):
    create_companies()  # добавляем начальные данные для компаний

    # если запрос POST, сохраняем данные
    if request.method == "POST":
        product = Product()
        product.name = request.POST.get("name")
        product.price = request.POST.get("price")
        product.company_id = request.POST.get("company")
        product.save()
        return HttpResponseRedirect("/")
    # передаем данные в шаблон
    companies = Company.objects.all()
    return render(request, "create.html", {"companies": companies})

# изменение данных в бд
def edit(request, id):
    try:
        product = Product.objects.get(id=id)

        if request.method == "POST":
            product.name = request.POST.get("name")
            product.price = request.POST.get("price")
            product.company_id = request.POST.get("company")
            product.save()
            return HttpResponseRedirect("/")
        else:
            companies = Company.objects.all()
            return render(request, "edit.html", {"product": product, "companies": companies})
    except Product.DoesNotExist:
        return HttpResponseNotFound("<h2>Product not found</h2>")
    
# удаление данных из бд
def delete(request, id):
    try:
        product = Product.objects.get(id=id)
        product.delete()
        return HttpResponseRedirect("/")
    except Product.DoesNotExist:
        return HttpResponseNotFound("<h2>Product not found</h2>")

# добавление начальных данных в таблицу компаний
def create_companies():
     
     if Company.objects.all().count() == 0:
          Company.objects.create(name = "Apple")
          Company.objects.create(name = "Asus")
          Company.objects.create(name = "MSI")

Для упрошения добавления данных здесь также определена вспомогательная функция create_companies, которая добавляет данные компаний в бд, чтобы у нас были некоторые начальные данные.

Функция index получает из базы данных все объекты Product и передает их в шаблон.

Функция create, если запрос типа POST, то получает данные из запроса и сохраняет их в бд. Иначе получает набор компаний и передает их в шаблон для добавления.

Функция edit, если запрос типа POST, получает данные запроса и изменяет значения нужного товара. Если запрос типа Get, то передает в шаблон данные редактируемого товара и список компаний (чтобы можно было изменить компанию товара - представим, что мы можем изменить производителя товара)

Функция delete удаляет товар.

В каталоге приложения определим папку templates и добавим в нее три шаблона: index.html, create.html и edit.html

В шаблоне 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><th>Компания</th><th></th></thead>
        {% for product in products %}
        <tr>
            <td>{{ product.name }}</td>
            <td>{{ product.price }}</td>
            <td>{{ product.company.name }}</td>
            <td>
                <a href="edit/{{product.id}}">Изменить</a> | <a href="delete/{{product.id}}">Удалить</a>
            </td>
        </tr>
        {% endfor %}
    </table>
</body>
</html>

В шаблоне 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>
            <input type="number" name="price" />
        </p>
        <p>
            <label>Введите компанию</label><br>
            <select name="company">
            {% for company in companies %}
                <option value="{{company.id}}">{{company.name}}</option>
            {% endfor %}
            </select>
        </p>
        <input type="submit" value="Сохранить" >
    </form>
</body>
</html>

В шаблоне edit.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" value="{{product.name}}" />
        </p>
        <p>
            <label>Введите цену</label><br>
            <input type="number" name="price" value="{{product.price}}"/>
        </p>
        <p>
            <label>Введите компанию</label><br>
            <select name="company">
            {% for company in companies %}
                <option value="{{company.id}}"
                {%if company.id == product.company_id%}
                  selected
                {%endif%}
            >{{company.name}}</option>
            {% endfor %}
            </select>
        </p>
        <input type="submit" value="Сохранить" >
    </form>
</body>
</html>

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

from django.urls import path
from hello import views

urlpatterns = [
    path("", views.index),
    path("create/", views.create),
    path("edit/<int:id>/", views.edit),
    path("delete/<int:id>/", views.delete),
]

В итоге получится следующий проект:

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

При запуске проекта и обращении к главной странице по умолчанию нет никаких товаров. И для этого перейдем к добавлению и добавим какой-нибудь товар:

Добавление данных при связи один ко многим в Django

Подобным образом можно выполнить редактирование товара:

Редактирование данных при связи один ко многим в Django
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850