5.4 Отношения таблиц в SQLAchemy
4 из 4 шагов пройдено

Пришло время применить знания на нашем проекте, давайте начнем с модели продуктов, для этого в файле models/products.py изменим код на следующий:

from app.backend.db import Base
from sqlalchemy import Column, ForeignKey, Integer, String, Boolean, Float
from sqlalchemy.orm import relationship
from app.models import *

class Product(Base):
    __tablename__ = 'products'

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String)
    slug = Column(String, unique=True, index=True)
    description = Column(String)
    price = Column(Integer)
    image_url = Column(String)
    stock = Column(Integer)
    category_id = Column(Integer, ForeignKey('categories.id'))
    rating = Column(Float)
    is_active = Column(Boolean, default=True)

    category = relationship('Category', back_populates='products')

У поля category_id мы устанавливаем связь "один ко многим". То есть у каждой категории будет несколько товаров.

Также изменим код для моделей наших категорий, для этого в файле model/category.py изменим код на следующий:

from app.backend.db import Base
from sqlalchemy import Column, Integer, String, Boolean
from sqlalchemy.orm import relationship
from app.models import *

class Category(Base):
    __tablename__ = 'categories'

    id = Column(Integer, primary_key=True, index=True)
    name = Column(String)
    slug = Column(String, unique=True, index=True)
    is_active = Column(Boolean, default=True)

    products = relationship("Product", back_populates="category")

 И в папке app/models создадим файл __init__.py, следующего содержания:

from .category import Category
from .products import Product

На данном этапе мы можем запустить наши модели, чтобы проверить, какой SQL код генерирует SQLAlchemy. Для этого можно добавить после моделей подобный код:

from sqlalchemy.schema import CreateTable
print(CreateTable(Product.__table__))

В результате получим следующую SQL инструкцию:

CREATE TABLE categories (
	id INTEGER NOT NULL, 
	name VARCHAR, 
	slug VARCHAR, 
	is_active BOOLEAN, 
	PRIMARY KEY (id)
)

CREATE TABLE products (
	id INTEGER NOT NULL, 
	name VARCHAR, 
	slug VARCHAR, 
	description VARCHAR, 
	price INTEGER, 
	image_url VARCHAR, 
	stock INTEGER, 
	category_id INTEGER, 
	rating FLOAT, 
	is_active BOOLEAN, 
	PRIMARY KEY (id), 
	FOREIGN KEY(category_id) REFERENCES categories (id)
)

Но самые внимательные могут заметить, что в модели Pydantic у нас присутствует поле, которое отвечает за создание подкатегорий товара:

class CreateCategory(BaseModel):
    name: str
    parent_id: int | None

Модель CreateCategory будет отвечать за создание категории товаров, и имеет 2 поля:

  • name: Имя категории, тип поля строка
  • parent_id: ID родительской категории, тип поля целое число

Поле slug мы будем заполнять автоматически, при создании категории.

 


Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.

Здравствуйте!

Возникает вот такая ошибка:

sqlalchemy.exc.InvalidRequestError: Table 'products' is already defined for this MetaData instance.  Specify 'extend_existing=True' to redefine options and columns on an existing Table object.

Если после 

__tablename__ = 'products'

сделать так:

__table_args__ = {'keep_existing': True}

То SQL запрос будет следующий:

CREATE TABLE categories (
    id INTEGER NOT NULL, 
    name VARCHAR, 
    slug VARCHAR, 
    is_active BOOLEAN, 
    PRIMARY KEY (id)
)

CREATE TABLE products (
    id INTEGER NOT NULL, 
    name VARCHAR, 
    slug VARCHAR, 
    description VARCHAR, 
    price INTEGER, 
    image_url VARCHAR, 
    stock INTEGER, 
    category_id INTEGER, 
    rating FLOAT, 
    is_active BOOLEAN, 
    PRIMARY KEY (id), 
    FOREIGN KEY(category_id) REFERENCES categories (id)
)

CREATE TABLE products (
    id INTEGER NOT NULL, 
    name VARCHAR, 
    slug VARCHAR, 
    description VARCHAR, 
    price INTEGER, 
    image_url VARCHAR, 
    stock INTEGER, 
    category_id INTEGER, 
    rating FLOAT, 
    is_active BOOLEAN, 
    PRIMARY KEY (id), 
    FOREIGN KEY(category_id) REFERENCES categories (id)
)

@Николай_Баранов, Почему у вас 2 инструкции создания таблицы products? 

'extend_existing': True

Означает что вы хотите наследоваться от нее, при создании таблицы.