# Асинхронная SQLAlchemy 2.0 | alembic миграции | Отношения между таблицами | Не FastAPI | Видео 3

https://www.youtube.com/watch?v=LKkn-2FId8w
Translation: en

[00:00] Привет меня зовут Сурен в этом видео.
  Hello, my name is Suren. In this video.

[00:02] продолжим работать с Fast API и сегодня.
  We will continue working with Fast API, and today.

[00:04] больше внимания уделим SQL чими и.
  We will pay more attention to SQL Alchemy and.

[00:06] посмотрим на связи между моделями связи.
  We will look at the relationships between model relationships.

[00:09] один к одному и один ко многим также.
  One-to-one and one-to-many, also.

[00:11] посмотрим на правильное создание таблиц.
  We will look at the correct creation of tables.

[00:13] в базе данных при помощи миграций.
  in the database using migrations.

[00:15] миграция мы будем применять при помощи.
  We will apply migrations using.

[00:17] olimpic ОМК дословно это перегоном куб.
  Alembic. Literally, it's a "transfer cube".

[00:19] Мы работаем с алхимией SQL чми поэтому.
  We are working with SQLAlchemy, therefore.

[00:22] вполне логичное название у ОМК очень.
  Alembic has a very logical name.

[00:24] подробная документация мы сегодня с вами.
  Detailed documentation. Today we will.

[00:25] пройдёмся по паре страниц и применим его.
  go through a couple of pages and apply it.

[00:28] в нашем проекте Зачем нам вобще.
  in our project. Why do we generally.

[00:30] использовать ОМК смотрите до этого мы.
  use Alembic? Look, before this, we.

[00:32] создавали новые таблицы при помощи Base.
  created new tables using Base.

[00:35] metadata Create All для того чтобы.
  metadata.create_all. In order to.

[00:37] сделать это в асинхронном движке мы.
  do this in an asynchronous engine, we.

[00:39] делали Connection Run Sync и передавали.
  did Connection.run_sync and passed.

[00:41] сюда синхрон ную функцию но так мы.
  a synchronous function here, but since we.

[00:44] создаём только новые таблицы мы можем.
  only create new tables, we can.

[00:46] создать новую таблицу при помощи Create.
  create a new table using Create.

[00:47] All но если мы в ту же самую таблицу.
  All. But if we, in the same table.

[00:49] например в таблицу product вот у нас.
  for example, in the product table, here we have.

[00:51] есть модель product добавим новое Поле.
  a product model, let's add a new field.

[00:53] любое поле совершенно неважно Какое.
  Any field, it doesn't matter what.

[00:55] может быть это будет просто Price 2.
  It could be just Price 2.

[00:57] то мы тут же столкнётся с проблемой что мы.
  Then we will immediately face the problem that we.

[00:59] не можем добавить это поле просто.
  cannot add this field simply.

[01:01] выполнив Base metadata Create All заново
  Having performed Base metadata Create All anew

[01:03] потому что bas metadata Create All
  because bas metadata Create All

[01:05] только создаёт таблицы которых ещё нет в базе данных
  only creates tables that are not yet in the database

[01:07] конечно же мы не хотим вручную описывать миграции
  of course we don't want to manually describe migrations

[01:08] Поэтому придётся использовать какой-то инструмент для того чтобы применять эти миграции на базу данных
  Therefore, we will have to use some tool to apply these migrations to the database

[01:13] Да конечно мы можем подключиться к базе данных и написать SQL команду для того чтобы добавить Новую колонку или наоборот удалить ненужную
  Yes, of course, we can connect to the database and write an SQL command to add a new column or, conversely, delete an unnecessary one

[01:20] Но это лишние ручные действия
  But these are unnecessary manual actions

[01:22] И это время мы лучше потратим на описание новых схем и выполнение новых миграций
  And we'd better spend this time describing new schemas and performing new migrations

[01:28] эти рации будут генерироваться автоматически при помощи olimpik
  these rations will be generated automatically with the help of olimpik

[01:32] перейдём в терминал и установим ОМК
  let's go to the terminal and install OMC

[01:34] мы используем поэтри
  we use poetry

[01:36] Поэтому нужно будет выполнить команду poet Add olimpic
  Therefore, we will need to execute the command poet Add olimpic

[01:39] мы устанавливаем ОМК это специальный инструмент который требует за собой ещё и Алхимию
  we are installing OMC, it is a special tool that also requires Alchemy

[01:43] так как она у нас установлена то он не потянулся дополнительно
  since it is installed on our end, it was not pulled additionally

[01:45] Ну и он ещё тянет за собой markup Save и maco
  Well, it also pulls markup Save and maco

[01:49] эти инструменты нужны для работы с шаблонами
  these tools are needed for working with templates

[01:51] мы с вами чуть подробнее посмотрим что за шаблоны тут вообще используются
  we will look in a little more detail at what templates are used here at all

[01:54] но для начала Давайте вернёмся к документации ОМК и посмотрим что он вообще делает
  but to start, let's return to the OMC documentation and see what it does

[01:57] перейдём на Туториал для начала
  let's go to the tutorial to start

[01:59] после установки olimpik нужно создать environment
  after installing olimpik, you need to create an environment

[02:03] есть окружение для работы с миграция и
  There is an environment for working with migration and

[02:05] тут описаны файлы которые мы будем использовать
  Here are the files that we will use

[02:07] обычно создание environment окружения делается простой командой
  Usually, creating an environment is done with a simple command

[02:09] alimpic init olimpic он создаёт нужные файлы и папки с которыми будет дальше работать
  alimpic init olimpic it creates the necessary files and folders that it will work with further

[02:16] olimpic - это обращение к самому Olympic ИТ - это команда Ну и olimpik - это параметр который мы указываем в качестве имени
  olimpic is a call to Olympic itself, init is a command, and olimpik is a parameter that we specify as the name

[02:22] что будет использоваться в качестве имени для всех файлов и папок будет использоваться ОМК
  which will be used as the name for all files and folders will be OMK

[02:26] мы можем назвать это например migration это тоже будет вполне рабочим вариантом
  we can call it, for example, migration, this will also be a perfectly working option

[02:30] но все знают что такое ОМК и поэтому если выведет папку с названием olimpic сразу будет понятно что там
  but everyone knows what OMK is, and therefore if it outputs a folder named olimpic, it will be immediately clear what is there

[02:36] и поэтому не нужно придумывать никакого другого имени
  and therefore there is no need to come up with any other name

[02:40] в alimpic сразу есть несколько разных шаблонов которые позволяют нам заранее настроить под наш проект миграции
  in alimpic there are immediately several different templates that allow us to pre-configure migrations for our project

[02:46] например generic - Это стандартные миграции а SN - это то что нам пригодится взаимодействие с асинхронной базой данных
  for example, generic - these are standard migrations, and SN is what we will need for interaction with an asynchronous database

[02:52] ну точнее через асинхронный движок Ну и ль db - это если мы работаем с несколькими базами данных
  or rather, through an asynchronous engine. Well, and db is if we work with multiple databases

[02:56] сейчас это нам не актуально так вот мы можем можем отредактировать потом созданный и файл
  currently this is not relevant to us. So, we can edit the created file later

[03:00] То есть файл конфигурации в котором есть
  That is, the configuration file in which there is

[03:04] описаны все правила для работы с alimic
  All rules for working with alimic are described.

[03:07] то есть какие он будет использовать настройки для создания миграций и для их выполнения
  that is, what settings it will use for creating migrations and for their execution.

[03:13] также мы здесь можем найти что мы можем указать дополнительные параметры там для таймзоны для всего остального это нас сейчас не сильно волнует
  We can also find here that we can specify additional parameters there for the timezone, for everything else, this does not concern us much right now.

[03:18] самое главное мы в и файле можем указать путь для того чтобы подключаться к базе данных
  The most important thing is that we can specify the path in the ini file to connect to the database.

[03:23] и здесь пример с pog мы с вами pog ещё обязательно посмотрим пока что работаем с sqlite но суть одна
  And here is an example with pog, we will definitely look at pog later, for now we are working with sqlite, but the essence is the same.

[03:30] Нам нужно в ини файле указать SQL chm URL
  We need to specify the SQL chm URL in the ini file.

[03:33] и получается намм придётся в двух местах указывать подключение
  And it turns out we will have to specify the connection in two places.

[03:35] мы указываем ссылку на подключение в Core config и пишем здесь db URL
  We specify the connection link in the Core config and write db URL here.

[03:39] а также нам Придётся делать это ещё и в alimpic ине конечно же мы хотим избежать дублирования кода
  And we will also have to do this in the alimpic ini, of course, we want to avoid code duplication.

[03:46] поэтому SQL URL мы будем переопределять всё же не в alic и не файле а немного в другом
  Therefore, we will redefine the SQL URL not in the alic ini file, but somewhere else.

[03:50] Ну давайте посмотрим как вообще создаются миграции
  Well, let's see how migrations are created in general.

[03:52] olimpic предлагает генерировать миграцию следующим образом
  olimpic suggests generating a migration as follows.

[03:56] olimpic revision то есть Обращаемся к команде olimpic создаём новую ревизию и добавляем какое-то сообщение мину M - это message и дальше в кавычках какое-то сообщение например Create account Table
  olimpic revision, that is, we call the olimpic command, create a new revision, and add some message, minus M - this is message, and then in quotes some message, for example, Create account Table.

[04:05] он создаёт новый файл миграции тут
  He creates a new migration file here.

[04:07] какой-то Случайный revision ID то есть
  Some random revision ID, that is.

[04:09] какой-то идентификатор Ну и дальше текст
  Some identifier. Well, and then the text.

[04:11] который мы указали только уже для имени
  which we specified, but already for the name.

[04:13] файла то есть без пробелов и мы видим
  of the file, that is, without spaces, and we see.

[04:14] что внутри будут созданы две функции
  that two functions will be created inside.

[04:17] upgrade и downgrade upgrade - это
  upgrade and downgrade. Upgrade is.

[04:19] выполнить создание А downgrade - это
  to perform creation. And downgrade is.

[04:21] выполнить откат на самом деле в upgrade
  to perform rollback. In fact, in upgrade.

[04:23] мы не обязательно должны создавать
  we don't necessarily have to create.

[04:24] что-то мы там можем что-то обновить
  Something, we can update something there.

[04:26] добавить или удалить самое главное в
  add or delete. The most important thing in.

[04:28] downgrade вернуть всё к к состоянию до
  downgrade is to return everything to the state before.

[04:31] выполнения upgrade это нужно для того
  performing the upgrade. This is necessary for.

[04:32] чтобы мы могли миграцию применить вперёд
  so that we can apply the migration forward.

[04:34] и откатить назад alic автоматически
  and roll back. Alic automatically.

[04:37] генерирует дишни для ревизии поэтому мы
  generates IDs for the revision, so we.

[04:39] здесь просто ничего не трогаем мы можем
  here simply don't touch anything. We can.

[04:41] модифицировать Что находится внутри
  modify what is inside.

[04:42] upgrade и downgrade и здесь для примера
  upgrade and downgrade. And here, for example.

[04:45] делают upgrade создание таблицы акаунт с
  they do an upgrade: creating an account table with.

[04:48] колонками ID name description а
  columns ID, name, description. And.

[04:49] downgrade нужно отменить что мы делали в
  downgrade, we need to cancel what we did in.

[04:52] upgrade в upgrade мы создавали таблицу
  upgrade. In upgrade, we created a table.

[04:54] значит в downgrade мы эту таблицу
  So, in downgrade, we will.

[04:57] откатывать olimpic Upgrade и мы обновим
  roll back the Olympic Upgrade. And we will update.

[05:00] до Head то есть до самого последнего
  to Head, that is, to the very last.

[05:02] скрипта миграции и мы можем также
  migration script. And we can also.

[05:04] добавлять новые миграции тогда новая
  add new migrations. Then a new.

[05:06] миграция будет зависеть от предыдущий
  The migration will depend on the previous one.

[05:08] вот down revision - это куда будет откат
  So, the down revision is where the rollback will be.

[05:10] и тут мы можем например добавить колонку
  And here we can, for example, add a column.

[05:11] на аккаунт и мы добавляем такую-то
  To the account, and we add such a column.

[05:13] колонку А в обратную сторону Down grade
  Column. And in the opposite direction, downgrade,

[05:16] мы эту колонку с таблицы акаунт удаляем
  we remove this column from the account table.

[05:19] заметьте мы не удаляем всю таблицу
  Note that we are not deleting the entire table.

[05:20] аккаунт мы удаляем только колонку в
  Account, we are only deleting the column in it.

[05:22] общем-то Это всё что нам нужно от alic
  In general, this is all we need from alic.

[05:25] На данном этапе То есть это создание
  At this stage, that is, it is the creation

[05:27] новых миграций и их выполнение и Давайте
  of new migrations and their execution. And let's

[05:30] посмотрим как быть с asino когда мы
  see how to handle async when we

[05:32] используем асинхронный движок мы можем
  use an asynchronous engine, we can

[05:33] просто использовать другой шаблон async
  simply use another async template

[05:36] который сгенерирует нам точно также
  which will generate for us exactly the same

[05:38] alimic конфигурацию но только с запуском
  alimic configuration, but only with the launch

[05:40] asn миграций и ASN тут будет заключаться
  of async migrations. And async here will consist

[05:43] в том что будет создана асинхронная
  in the fact that an asynchronous function will be created,

[05:45] функция Run async migrations которая
  RunAsyncMigrations, which

[05:48] будет выполнена в Run migrations online
  will be executed in RunMigrationsOnline

[05:50] через asy Run внутри этой функции будет
  via async Run. Inside this function will be

[05:52] выполнено подключение через асинхронный
  executed the connection via the asynchronous

[05:54] движок и внутри выполнение Run Sync для
  engine and inside the execution of RunSync for

[05:57] выполнения миграций уже в S синхронном
  executing migrations already in a synchronous

[06:00] виде то есть сами миграции Мы описываем
  form. That is, we describe the migrations themselves

[06:01] также в синхронном виде и просто через
  also in synchronous form and simply through

[06:03] асинхронный движок через прослойку runs
  the asynchronous engine, through the runs layer,

[06:05] мы будем это всё выполнять Давайте же
  we will execute all of this. Let's

[06:09] сгенерирует - T async и в терминале в pycharm выполню alic - T async пробел alimic То есть я генерируют добавлена папка alic внутри versions ещё Script Pie файл добавлен NP rmi и Давайте на это всё посмотрим для начала файл на Верхнем уровне - это файл Olympic in тут конфигурация для миграций например по умолчанию все миграции называются так revision и slag revision - это просто какой-то ID ревизии А slag - это кусочек текста из названия например что мы видели в документации мы создаём новую миграцию Add colum тогда файл для этой миграции называется какой-то ID Случайный и затем Add A colum то есть тот же текст просто приводится к названию это вполне нормальный вариант генерации имени для ревизий но если например мы хотим видеть все ревизии по порядку сверху вниз то нам будет удобнее указать немного другое название это делать необязательно но вы

[07:10] если хотите можете раскомментировать
  if you want you can uncomment

[07:12] файл template и здесь будет год месяц
  the template file and here will be the year month

[07:15] число дальше час минута И после этого
  day then hour minute And after that

[07:18] уже тот самый ID ревизии и какой-то
  already that same revision ID and some

[07:20] текст в таком случае все ревизии будут
  text in this case all revisions will be

[07:23] идти всегда сверху вниз по порядку
  going always from top to bottom in order

[07:25] потому что год месяц число будут только
  because the year month day will only

[07:27] увеличиваться Ну и ещё час минута в
  increase Well and also hour minute in

[07:30] таком виде вы сможете всегда находить
  this form you will always be able to find

[07:31] последнюю ревизию очень легко а не
  the latest revision very easily and not

[07:33] делать это через терминал потому что
  do it through the terminal because

[07:35] olimpic через терминал позволяет
  olimpic through the terminal allows

[07:36] посмотреть порядок выполнения миграций
  to view the order of migration execution

[07:38] здесь же мы можем найти ещё и другие
  here we can also find other

[07:40] настройки например тот же самый с клоча
  settings for example the same cron

[07:43] URL но давайте пока что оставим этот
  URL but let's leave this for now

[07:45] файл как он есть потом мы к нему ещё
  file as it is we will come back to it later

[07:47] вернёмся теперь взглянем на папку alimic
  return now let's look at the alimic folder

[07:49] в которой создано несколько файлов rmi
  in which several rmi files have been created

[07:52] здесь просто написано что эта папка
  it just says here that this folder

[07:53] нужна как раз-таки для того чтобы
  is needed precisely in order to

[07:55] работать с миграция есть файл Script P
  work with migrations there is a file Script P

[07:57] mao и что мы здесь видим видим здесь код
  mao and what do we see here we see code here

[08:00] очень похожий на Python но всё-таки это
  very similar to Python but still it is

[08:02] не совсем Python код например тут есть
  not quite Python code for example there is

[08:04] обращение через доллар и фигурную скобку
  referencing through a dollar and curly brace

[08:06] и это работа с шаблонами тут мы видим
  and this is working with templates here we see

[08:08] что мы сюда подставим либо какое-то
  that we will substitute here either some

[08:10] значение если оно есть либо просто текст
  value if it exists or just text

[08:13] Pass ну и сверху подставляется message и так далее
  Pass, and on top of that, message is substituted, and so on.

[08:17] Это шаблон на основе которого как раз-таки инструмент maco будет создавать новые миграции
  This is a template based on which the maco tool will create new migrations.

[08:21] Ну и в файле nfp у нас знакомый Python CDE и тут мы можем найти например Run assn migrations
  And in the nfp file, we have the familiar Python CDE, and here we can find, for example, Run assn migrations.

[08:27] и этот Run assn migrations выполняется внутри Run migrations online
  And this Run assn migrations is executed inside Run migrations online.

[08:30] и тут просто aso Run то есть Мы выполняем асинхронную функцию в синхронном коде
  And here it's just aso Run, meaning we are executing an asynchronous function in synchronous code.

[08:36] если мы прямо сейчас перейдём в терминал И сгенерирует вот так olimpic revision
  If we go to the terminal right now and generate it like this, olimpic revision.

[08:43] и после этого нужно указать ещё и название миграции
  And after that, you need to specify the migration name as well.

[08:46] например Create account Table
  For example, Create account Table.

[08:49] то будет сгенерирована новая миграция с тем шаблоном имени который мы указали ранее
  Then a new migration will be generated with the name template that we specified earlier.

[08:53] можем в папке versions посмотреть на эту миграцию
  We can look at this migration in the versions folder.

[08:55] и Тут видно что Ука ревизия то есть новый ID для этой ревизии
  And here you can see the revision, meaning a new ID for this revision.

[09:01] down revision - это куда откатываться
  down revision is where to roll back to.

[09:03] N branch labes и depends on нас сейчас даже не волнует
  N branch labels and depends on don't even concern us right now.

[09:07] просто здесь какие-то значения по умолчанию проставлены
  There are just some default values set here.

[09:08] и вот в upgrade и dade мы можем прописать свои значения
  And in upgrade and downgrade, we can write our own values.

[09:10] но мы не хотим писать миграцию вручную Зачем нам
  But we don't want to write the migration manually. Why should we?

[09:15] делать это вручную Я вообще удалю этот файл если мы уже вручную описали модели
  Doing this manually, I will delete this file if we have already described the models manually.

[09:19] вот Core moduls У нас есть модель product у нас также будет ещё модель для юзера
  Here are the core modules. We have a product model, and we will also have a model for the user.

[09:24] Зачем нам описывать модель здесь а потом ещё описывать миграцию отдельно в olimp
  Why should we describe the model here and then describe the migration separately in Olimp?

[09:29] конечно нас интересует автогенерация миграций И olimpic это тоже позволяет Давайте в NP укажем откуда брать информацию о существующих таблицах
  Of course, we are interested in automatic migration generation, and Olimp also allows this. Let's specify in NP where to get information about existing tables.

[09:38] и нам для этого достаточно указать Target metadata Мы из нашего Core Models импортируем Base и оттудаберём Base metadata
  And for this, it is enough to specify the Target metadata. We import Base from our Core Models and take the Base metadata from there.

[09:46] Давайте здесь так и сделаем From Core Models импортируем Base и на основе этого Base мы передаём в olimpic metadata метаданные для того чтобы знать а какие модели вообще существуют
  Let's do it this way: import Base from Core Models, and based on this Base, we pass metadata to Olimp so that it knows which models exist at all.

[10:00] Но для того чтобы генерировать миграции автоматически нам нужно сравнивать текущее состояние базы данных с целевым целевое Мы описываем в моделях
  But in order to generate migrations automatically, we need to compare the current state of the database with the target state. We describe the target in the models.

[10:08] получается Мы в моделях SQL lch будем описывать то как база данных должна выглядеть у нас не будет SQL кода
  It turns out that in SQL lch models, we will describe how the database should look; we will not have SQL code.

[10:15] для описание базы данных у нас будет Python код для описания базы данных
  For describing the database, we will have Python code for describing the database.

[10:18] и для того чтобы SQL L chm а точнее ОМК через SQL lch мог сравнивать что у нас сейчас в базе данных и что мы ожидаем видеть нам нужно указать как подключаться к этой базе данных
  And in order for SQL LCH, or more precisely OMK, through SQL LCH to compare what we currently have in the database and what we expect to see, we need to specify how to connect to this database.

[10:27] Мы помним что в ОМК ине есть SQL CH URL и можно указать здесь ссылку
  We remember that in OMK there is an SQL CH URL and you can specify a link here.

[10:33] Но как Только мы меняем значение Или например укажем в переменных окружения какая у нас будет ссылка то есть заменим её то сразу же в этот момент мы ломаем совместимость
  But as soon as we change the value, or for example, specify in the environment variables what our link will be, that is, replace it, then immediately at this moment we break compatibility.

[10:42] и ОМК больше не будет подключаться по правильной ссылке поэтому неправильно указывать здесь отдельной ссылкой то что мы уже указываем где-то в Python коде
  And OMK will no longer connect via the correct link, so it is incorrect to specify here with a separate link what we are already specifying somewhere in the Python code.

[10:50] давайте мы config я импортируют сделать config не только Get Main Option Как нам тут показывают А ещё и config Set Main Option
  Let's import config, I will import config, make config not just Get Main Option as shown here, but also config Set Main Option.

[11:07] сюда мы передаём название и эта настройка указана в olimpic вот у нас SQL lch URL
  Here we pass the name, and this setting is specified in olimpic, here is our SQL LCH URL.

[11:15] он находится в главной секции которая тут называется Olympic и мы вот это значение SQL churl которую мы указываем в config Давайте попробуем выполнить миграции заново для этого создадим авто сгенерирован ную миграцию я выполняю команду olimpic revision autogenerate и в message после autogenerate я передам текст Create products Table вот Я создаю новую миграцию давайте мы на неё посмотрим что у нас в этой миграции Мы видим что тут не произошло ничего в upgrade и дай
  It is in the main section which is called Olympic here and we this SQL churl value which we specify in the config. Let's try to run the migrations again. For this, we will create an auto-generated migration. I run the command olimpic revision autogenerate and in the message after autogenerate I will pass the text Create products Table. Here, I am creating a new migration. Let's look at it. What do we have in this migration? We see that nothing happened in the upgrade and give

[11:54] почему же так вышло Дело в том что olic сравнивает какое сейчас состояние базы данных и что нужно сделать чтобы база данных приняла такое состояние которое описано у нас в моделях А в моделях у нас описан продакт если мы посмотрим на базу данных который мы подключаемся то здесь уже есть таблица products и в этой таблице уже есть не только колонки но ещё и записи и получается что в этой миграции дополнительно делать ничего не
  Why did this happen? The fact is that olic compares the current state of the database and what needs to be done for the database to adopt the state described in our models. And in the models, we have the product described. If we look at the database we are connecting to, then the products table is already there, and this table already has not only columns but also records. And it turns out that in this migration, there is nothing more to do.

[12:16] нужно Я удалю эту миграцию а также я удалю всю базу данных
  I need to delete this migration and I will also delete the entire database.

[12:21] сейчас у нас там ничего важного не хранится поэтому можно полностью от неё избавиться
  Currently, nothing important is stored there, so we can get rid of it completely.

[12:25] теперь в терминале я выполню создание миграции заново та же самая команда и и генерируется новая миграция
  Now in the terminal, I will perform the creation of the migration again, the same command, and a new migration is generated.

[12:31] посмотрим на versions и новую миграцию и тут мы видим уже создание Таблицы products с колонкой name description Price ID и на ID Мы ещё дове primary key constraint
  Let's look at versions and the new migration, and here we see the creation of the Products table with columns name, description, Price, ID, and on ID we will add a primary key constraint.

[12:40] и в обратную сторону откат - это удаление таблицы products
  And in the reverse direction, the rollback is the deletion of the Products table.

[12:44] легко заметить что тут код не очень-то красиво отформатирован
  It's easy to notice that the code here is not very nicely formatted.

[12:46] Я люблю forter Black и он у меня активен по умолчанию
  I love Black formatter, and it's active by default for me.

[12:50] и я рассказывал про него в предыдущем видео
  And I talked about it in the previous video.

[12:52] Поэтому я тут просто отформатирую нажму Command Shift L или Command Option L зависит от ши настроек
  Therefore, I will just format it here, press Command Shift L or Command Option L, depending on the system settings.

[12:59] и при помощи Black будет отформатирован этот код
  And with the help of Black, this code will be formatted.

[13:01] Теперь его гораздо легче читать
  Now it's much easier to read.

[13:04] Но мы же не хотим каждый раз вручную эти миграции форматировать нажимать какие-то сочетания клавиш или искать в поиске например Black и выполнять формат для текущего файла
  But we don't want to manually format these migrations every time, press some key combinations, or search in the search, for example, for Black, and execute format for the current file.

[13:13] нет поэтому мы можем настроить чтобы ОМК сам применял
  No, so we can configure it so that the ORM applies it automatically.

[13:17] какие-то формате Ну или другие инструменты к только что созданным файлам
  some format or other tools for newly created files

[13:21] я снова удалю файл миграции пока мы его не применяли можно спокойно удалять этот файл
  I will delete the migration file again, as long as we haven't applied it, this file can be safely deleted

[13:27] и у нас уже установлен Black мы ставили его на на одном из предыдущих занятий
  and we already have Black installed, we installed it in one of the previous classes

[13:29] и этот Black мы будем использовать здесь для работы с alimic
  and we will use this Black here to work with alimic

[13:34] в alimic ине мы укажем что нам нужен Post wr hook Post Right hook то есть после того как мы записали новую миграцию нужно выполнить какой-то ook
  in alimic, we will specify that we need a Post wr hook, Post Right hook, that is, after we have recorded a new migration, some hook needs to be executed

[13:41] к - это крючок то есть мы за что-то дёргал неет какое-то действие
  k - it's a hook, meaning we pull something, some action

[13:45] например в hooks можно указать Black и этот самый Black мы просто применим здесь
  for example, in hooks, you can specify Black, and we will simply apply this Black here

[13:50] название будет Black у Black Tip console scripts то есть Это скрипт который выполняется в консоли
  the name will be Black, Black Tip console scripts, meaning it's a script that runs in the console

[13:56] и Black entry Point - это Black а options мы передаём line такая-то строчка
  and Black entry Point is Black, and options, we pass a line, such and such a string

[14:01] Ну например 79 мало можно 99 поставить Ну или хотя бы 89
  Well, for example, 79 is too little, you can put 99, or at least 89

[14:05] и revision Script name - это им скрипта который уже нужно будет отредактировать
  and revision Script name is the name of the script that will need to be edited

[14:08] сохраним эту конфигурацию Как вы видите olic её даже рекомендует потому что она есть в стандартном сгенерированного конфиге
  let's save this configuration, as you can see, olic even recommends it because it is in the standard generated config

[14:14] вернёмся в терминал и заново
  let's go back to the terminal and again

[14:23] сгенерирует что на неё сразу же применил
  will generate that it was immediately applied to it

[14:26] Black Давайте проверим Что будет в этом файле и сразу же в файле всё красиво отформатировано
  Black Let's check what will be in this file and immediately in the file everything is beautifully formatted

[14:31] вы могли заметить что уже была создана база данных db SQL 3 но
  you might have noticed that a database db SQL 3 was already created but

[14:33] если мы сейчас обновим что у нас тут тут не будет таблица products эта база данных была создана автоматически
  if we update now what we have here here there will be no products table this database was created automatically

[14:40] так как olimpic ищет А какое есть содержимое в этой базе данных и так как sqlite автоматически создаёт новый Файлик если мы пытаемся подключиться к базе данных
  as olimpic searches for what content is in this database and since sqlite automatically creates a new file if we try to connect to the database

[14:48] то вот этот файл создан тут уже есть таблица Olympic version её тоже автоматически создал ОМК но тут Пока что нет никаких значений
  then this file is created here there is already an Olympic version table it was also automatically created by OMC but there are no values here yet

[14:56] мы не получаем здесь никакую верси потому что мы ещё не выполнили ни одной миграции
  we do not receive any version here because we have not yet performed a single migration

[14:59] давайте выполним миграцию для этого нужно написать olimpic upgrade Head
  let's perform a migration for this we need to write olimpic upgrade Head

[15:03] и мы обновим до последней миграции Create products Table обновим состояние базы данных
  and we will update to the latest migration Create products Table update the database state

[15:08] и мы видим что появилась табличка products
  and we see that the products table has appeared

[15:10] так при помощи olimpic миграции вы создали новую таблицу её же легко откатить
  so using olimpic migration you created a new table it is also easy to roll back

[15:14] можно сделать вместо upgrade downgrade и сказать -1 на единицу откатить назад
  you can do downgrade instead of upgrade and say -1 by one to roll back

[15:18] и мы откатится назад будет выполнен downgrade это удаление
  and we will roll back a downgrade will be performed this is deletion

[15:25] таблицы products посмотрим что у нас там
  Let's look at the products table to see what we have there.

[15:27] в базе данных обновим состояние и
  We will update the state in the database and

[15:29] таблица products больше нет но мы можем
  the products table is no longer there, but we can

[15:31] заново Её легко создать при помощи
  easily recreate it using

[15:33] команды Olympic upgrade Head обновим и
  the Olympic upgrade Head command. We will update it and

[15:36] здесь снова будет видно таблицу products
  the products table will be visible here again.

[15:39] важно отметить что если я сейчас решу
  It's important to note that if I now decide

[15:41] удалить эту миграцию то в базе данных у
  to delete this migration, then in the database

[15:44] нас-то останется версия какая у нас
  a version will remain. What version do we have

[15:45] сейчас версия такая версия и в products
  now? The version is like this, and in products

[15:48] у нас уже есть таблица поэтому удаление
  we already have a table, so deleting

[15:50] этого файла приведёт к проблемам
  this file will lead to problems,

[15:52] конфликтом в ОМК ОМК не сможет
  conflicts in OMC. OMC will not be able to

[15:55] генерировать новые миграции так как у
  generate new migrations because we have

[15:57] нас будет неактуальная миграция в базе
  an outdated migration in the database.

[15:59] данных в базе данных уже какой-то номер
  In the database, there is already some number,

[16:01] есть а в файлах такой миграции нет
  but there is no such migration in the files.

[16:04] поэтому мы больше не удаляем этот файл
  Therefore, we no longer delete this file

[16:06] миграции если мы его выполнили либо
  of migration if we have executed it, or

[16:09] делаем откат назад и потом только
  we roll back and only then

[16:11] удаляем файл и поэтому все миграции базы
  delete the file. And therefore, all database migrations,

[16:14] данных Обязательно все миграции схем всё
  all schema migrations, everything

[16:16] что Оле генерирует нужно добавлять в гит
  that Ole generates, must be added to the Git

[16:19] репозиторий я нажимаю Command K Ну или
  repository. I press Command K, or

[16:21] можно кликнуть вот здесь слева на comit
  you can click here on the left on Commit.

[16:23] и сохраняю всё что у нас здесь было
  And I save everything that was here.

[16:25] добавлено то есть для начала добавим
  Added. That is, to begin with, let's add

[16:26] весь ОМК но без новой версии и в P
  The whole OMK but without the new version and in P

[16:30] Project tomal мы устанавливали olic
  Project tomal we were installing olic

[16:32] поэтому я напишу Install olic или можно
  So I will write Install olic or you can

[16:35] даже чтобы не писать end Потому что
  even not to write end Because

[16:37] когда мы пишем end значит что можно
  when we write end it means that it is possible

[16:38] разделить comit на два вот я делаю один
  to divide the commit into two here I am doing one

[16:41] comit просто Install oic и затем новый
  commit just Install oic and then a new

[16:45] comit будет init olic без версии пишем
  commit will be init olic without version we write

[16:48] init olic и мы Коми конфигурацию olic И
  init olic and we commit the configuration of olic And

[16:52] после этого мы ещё ком новую миграцию
  after that we also commit a new migration

[16:55] так и напишем Create migration for
  so we will write Create migration for

[16:59] products Table и нажимаю commit всё
  products Table and I press commit everything

[17:02] когда мы используем alic мы больше не
  when we use alic we no longer

[17:04] выполняем автоматическое создание таблиц
  perform automatic table creation

[17:06] можно полностью избавиться здесь от B
  you can completely get rid of B here

[17:09] Data Create All совсем нам это тут
  Data Create All at all we don't need this here

[17:11] больше не пригодится При желании тут
  anymore If desired here

[17:12] можно добавить вызов ОМК и делать тут
  you can add a call to OMК and do here

[17:14] абгрейд Каждый раз когда мы запускаем
  upgrade every time we launch

[17:16] новое приложение но не рекомендую это
  a new application but I do not recommend this

[17:18] делать потому что если вы вдруг
  doing because if you suddenly

[17:19] создадите миграцию в которой будут
  create a migration in which there will be

[17:21] ошибки а приложение автоматически
  errors and the application automatically

[17:22] перезапустить вы получите ту миграцию
  restarts you will get that migration

[17:25] придётся откатываться ещё смотреть чтобы
  you will have to roll back and also make sure that

[17:26] приложение снова не перезапустил и не
  the application does not restart again and does not

[17:28] сделало новый
  made a new one

[17:29] поэтому делайте миграции только вручную
  so do migrations only manually

[17:31] при локальной разработке А из Main Можно
  during local development. And from Main, you can

[17:34] даже удалить Base и db Helper потому что
  even delete Base and db Helper because

[17:36] они будут нужны в дальнейшем в других
  they will be needed later in other

[17:38] модулях а в Main можно его не
  modules, and in Main, you can not

[17:39] использовать lifespan можно пока
  use it. Lifespan can be for now

[17:41] оставить потому что может быть
  left because it might be

[17:42] пригодится потом сюда добавить некоторые
  useful later to add some

[17:44] новые действия Давайте сразу же
  new actions. Let's immediately

[17:46] закоммитить
  commit

[17:48] Create All при старте приложения No More
  Create All at application start. No More

[17:52] Create all on App Start вот и всё Мы
  Create all on App Start. That's all. We

[17:56] создали миграции при помощи olimpic и
  created migrations using olimpic and

[17:59] будем выполнять их для создания новых
  will execute them for creating new

[18:01] таблиц Теперь давайте перенесём юзера в
  tables. Now let's move the user to

[18:03] API V1 и создадим ему модель в Core
  API V1 and create a model for him in Core

[18:07] Models для этого в Models Я создам новый
  Models. For this, in Models, I will create a new

[18:09] файл это будет файл User мы называем его
  file. It will be the User file. We name it

[18:12] по имени класса который мы будем
  after the class name that we will be

[18:14] создавать тут мы создавали product А в
  creating. Here we created product, and in

[18:16] User мы создадим клас User Он точно
  User, we will create the User class. It will exactly

[18:19] также будет наследником Base это
  also be a descendant of Base, this is

[18:21] обязательно и у него Пусть например
  mandatory. And let him have, for example,

[18:23] будет username если мы хотим чтобы
  username. If we want

[18:25] username был уникален необходимо из SQL
  username to be unique, it is necessary from SQL

[18:27] orm импортировать maped colum пишем что
  orm to import mapped column. We write that

[18:30] username - это maped string равно maped colum и добавляем сюда Unique True если мы хотим ограничить по длине username мы можем ещё из SQL lch импортировать объект string Напишите From SQL lch import string и на основе этого string можно сделать ограничение тут мы уже указали что это строка но добавив string и в скобках Какой длины ограничения мы получим username лимитированный по длине
  username is a mapped string equal to the mapped column and we add Unique True here if we want to limit the length of the username we can also import a string object from SQL alchemy Write From SQL alchemy import string and based on this string we can make a limitation here we have already indicated that it is a string but by adding string and in parentheses what length of limitation we will get a username limited by length

[18:55] пока что пользователю можно больше ничего не добавлять мы если что добавим Новые поля при помощи миграции этого юзера нужно добавить в init чтобы Base metadata знал про него поэтому я из то User импортируют Base Мы импортируем в NP в olimpik то мы можем перейти в терминал и сгенерировать новую миграцию у нас новая миграция будет называться Create users Table
  for now the user can't add anything else we will add new fields if necessary using migration this user needs to be added to init so that Base metadata knows about it so I import Base from User We import into NP into olimpik then we can go to the terminal and generate a new migration our new migration will be called Create users Table

[19:23] Давайте посмотрим что получится у нас новый файл Он внизу потому что у нас сортировка по имени А в имени у нас будет всегда порядок по возрастанию и мы
  Let's see what happens we have a new file it's at the bottom because we have sorting by name and in the name we will always have ascending order and we

[19:32] видим что вот создание новой таблицы
  We see that here is the creation of a new table

[19:34] users добавляем колонку username и длина
  users, we add the username column and the length

[19:37] у этой колонки не более 32 nullable
  for this column is not more than 32, nullable

[19:40] false потому что мы не указывали там
  false because we did not specify there

[19:42] None и колонка ID тоже nullable false
  None, and the ID column is also nullable false

[19:44] колонка ID - это primary Ke а колонка
  the ID column is the primary key, and the column

[19:46] username - это Unique constrain то есть
  username is a Unique constraint, that is

[19:49] username должен быть уникален откат
  username must be unique. Rollback

[19:50] обратно - это удаление таблицы users Всё
  back is the deletion of the users table. That's all.

[19:52] мы просмотрели всю миграцию обязательно
  We have reviewed the entire migration, it is mandatory

[19:55] каждый раз всю миграцию просмотреть
  to review the entire migration every time.

[19:56] глазами если что-то где-то поправить
  with your eyes. If something needs to be corrected somewhere,

[19:58] нужно то можно поправить вручную либо в
  then it can be corrected manually, either in

[20:00] миграции либо в моделях если это
  the migration or in the models if it

[20:02] применимо для модели и после этого мы
  is applicable to the model, and after that we

[20:04] можем применить эту миграцию напишем
  can apply this migration. We write

[20:05] alic upgrade Head и будет применена эта
  alic upgrade Head, and this will be applied

[20:08] миграция смотрим Что у нас в базе данных
  migration. Let's see what we have in the database.

[20:11] обновим состояние и увидим что появилась
  We will update the state and see that it has appeared

[20:13] таблица users Давайте теперь создадим
  the users table. Let's now create

[20:15] модель с которой пользователь будет
  a model with which the user will be

[20:16] связан ко многим То есть к одному
  associated with many. That is, to one

[20:18] пользователю можно привязать несколько
  user, several can be attached

[20:20] элементов например это могут быть посты
  elements. For example, these could be posts

[20:23] пользователя То есть он пишет какие-то
  of the user. That is, he writes some

[20:25] публикации посты и мы хотим чтобы на
  publications, posts, and we want so that for

[20:28] одного пользователя приходилось любое
  one user there are any

[20:30] количество публикаций то есть Может быть
  number of publications. That is, there may be

[20:32] два поста У пользователя может быть 10
  two posts. The user may have 10

[20:33] постов У пользователя может быть ноль

[20:35] или один пост У пользователя самое

[20:37] главное что у одного поста всегда будет

[20:39] один пользователь выходит что с поста к

[20:43] юзеру это связь к одному а с юзера к

[20:46] постам будет Связь ко многим Да мы

[20:48] разрабатываем micros маленький

[20:50] магазинчик но допустим у нас есть ещё

[20:52] возможность писать посты потом дойдём

[20:54] ещё и до работы с товарами там будут

[20:56] связи посложнее и вот этот этор которого

[20:59] Мы создали должен быть связан с постами

[21:01] для начала перед тем как двигаться

[21:02] дальше я предлагаю закоммитить всё что

[21:04] мы здесь написали это будет Create User

[21:07] Model и также мы Коти миграцию миграция

[21:12] где мы создаём эту таблицу то есть

[21:14] migration for users Table и ком это тоже

[21:19] перейдём к моделям и нам нужно создать

[21:21] новую модель пост который будет связана

[21:24] с Юзе Я создаю новый Python фай Post и

[21:27] он точно также как и User как и прок

[21:30] будет наследником Base только мы

[21:32] называем этот класс Post и у него больше

[21:35] не будет юзернейм у него будет

[21:36] какой-нибудь title title тоже будет

[21:38] обязательной строчкой то есть не None не

[21:40] nullable и не надо чтобы была уникальная

[21:43] строчка То есть можно указать Unique

[21:44] false либо вообще убрать потому что по

[21:46] умолчанию Unique false и строка например

[21:48] будет по длине 100 у нас ограничение на

[21:51] заголовок 100 символов думаю этого

[21:52] достаточно также укажем текст этой

[21:55] статьи Пусть тут будет например Body

[21:57] Body можно указать также Map string и

[21:59] просто ничего не указывать дополнительно

[22:01] либо Давайте расширим информацию о теле

[22:04] этой статьи Мы импортируем ещё текст из

[22:06] SQL lch и укажем что тут тип - это текст

[22:10] а также укажем дефолтное значение

[22:12] дефолтное значение для алхимии будет

[22:14] просто пустая строчка это кавычки

[22:16] открыть и кавычки закрыть А ещё я укажу

[22:19] Север default и тоже укажу пустую

[22:21] строчку В чём разница default и Server

[22:23] default default используется когда мы

[22:26] создаём новый экземпляр прямо в алхимии

[22:28] а Север default используется на стороне

[22:30] сервера какой у нас сервер сервер - это

[22:32] база данных и на стороне сервера Мы тоже

[22:35] можем указывать значение по умолчанию

[22:36] чтобы даже если Мы залезли вручную в

[22:38] базу данных и попытались создать новую

[22:40] запись у полей в которой мы не записали

[22:42] значение проставить значение по

[22:44] умолчанию указывать сервер дефолт

[22:46] необязательно и дефолт тоже указывать

[22:48] необязательно но хорошим тоном будет

[22:50] если вы всегда при создании дефолта

[22:52] будете указывать ещё и Север default и

[22:54] вот мы описали пост Можно даже его

[22:56] импортировать в moduls in для этого из

[22:59] dopost я

[23:04] импортируют намм нужно строго привязать

[23:07] этот пост к пользователю который будет

[23:10] эти посты создавать поэтому добавим туда

[23:12] внешний ключ User ID это будет внешний

[23:15] ключ Я укажу что это maped integer

[23:18] потому что ID у нас integer и это будет

[23:21] maped colom который будет внутри

[23:24] принимать for и на этот for Нам нужно

[23:27] будет ещё докинути что мы используем в

[23:30] качестве внешнего ключа Foreign K будет

[23:32] таблица users поле ID то есть мы

[23:35] указываем Foreign user.id Да чисто

[23:38] технически Сюда можно сослаться через

[23:40] модель то есть Foreign Ke указать модель

[23:43] User который у нас есть в отдельном

[23:45] модуле и указать поле ID но мы не можем

[23:47] сюда импортировать этого юзера Потому

[23:49] что будет циклический импорт и я оставлю

[23:51] ссылку именно через название таблицы и

[23:54] через точку поле которое нужно будет

[23:56] использовать в качестве внешнего ключа

[23:57] тут Важно ещё указать что User не может

[24:00] быть None мы указали здесь просто int не

[24:03] указывали что у нас или None поэтому тут

[24:06] автоматически будет не nullable поле Но

[24:09] если вы вдруг не указываете аннотацию

[24:11] можно указать явно nullable false Однако

[24:13] здесь это делать необязательно потому

[24:15] что мы уже указали что здесь не может

[24:17] быть None в аннотации через mapt вот

[24:20] такую таблицу мы уже можем создать

[24:22] давайте сделаем новую миграцию я перейду

[24:24] в терминал и

[24:28] Table посмотрим что будет создано в этом

[24:30] файле новый файл для создания таблицы

[24:33] posts здесь мы добавляем колонку title с

[24:35] ограничением в 100 также у нас будет

[24:37] Body уже тип не string а текст и Server

[24:41] default тоже указан User ID nullable

[24:43] false Как вы видите nullable false не

[24:45] обязательно указывать здесь явно потому

[24:47] что мы указываем через аннотацию что

[24:49] здесь должен быть именно integer а не

[24:51] integer или None поэтому мы просто

[24:53] избавляемся от лишнего кода и вот здесь

[24:55] nullable false указано ID тоже nullable

[24:57] false Fork constraint - это внешний ключ

[25:00] ограничение по ссылке на другую таблицу

[25:03] мы ссылается с колонки User ID на

[25:06] таблицу users на поле ID в этой таблице

[25:09] и дальше primary K на ID всё понятно в

[25:11] обратную сторону откат - это удаление

[25:13] таблицы Post нас всё устраивает Давайте

[25:15] выполним миграцию Olympic upgrade Head И

[25:18] если всё успешно прошло можно ещё и

[25:20] закоммитить изменения Давайте посмотрим

[25:21] что таблица posts создана Ну и теперь

[25:24] можно всё сохранить что мы с вами

[25:25] написали перед коммитом обязательно

[25:27] проверьте что вы тут тут вообще написали

[25:29] модель Нас устраивает и в init Мы тоже

[25:31] её добавили Create posts Model и после

[25:35] того как мы эту модель объявили можно

[25:37] ещё и сохранить что мы там делали в

[25:40] миграции миграцию мы уже проверили и

[25:42] глазами и выполнили у нас это устраивает

[25:45] поэтому у нас будет migration for posts

[25:48] Table нажимаю comit и вот мы закоммитить

[25:51] Давайте посмотрим как мы можем работать

[25:53] с этими моделями вот у нас есть пост и

[25:56] эти посты строго связаны с

[25:58] пользователями мы можем ещё Добавить

[26:00] сюда связи между моделями То есть тут у

[26:03] нас есть таблицы которые связаны друг с

[26:05] другом через Fork но модели User и Post

[26:09] пока что не связаны А мы можем это

[26:10] добавить для этого нужно использовать

[26:12] relationship и я укажу что пост

[26:14] ссылается на юзера для этого я использую

[26:17] User это будет maped но maped что здесь

[26:21] maped User Однако мы не можем просто так

[26:23] импортировать этого юзера у нас будет

[26:24] циклический импорт потому что в юзер мы

[26:26] импортируем пост но в в аннотация типов

[26:29] мы можем использовать один такой Хак из

[26:31] typing импортируем специальный флаг Type

[26:34] Checking и Type Checking - это сейчас

[26:36] идёт проверка типов Мы спрашиваем А

[26:39] сейчас идёт проверка типов если сейчас

[26:41] идёт только проверка типов а не

[26:42] выполнение кода то мы делаем From User

[26:46] import User и импортируем юзера и тут

[26:48] можем указать его так либо в кавычках

[26:49] лучше указать в кавычках Чтобы наверняка

[26:51] и получится что мы

[26:53] ссылают мы импортируем только при

[26:56] проверке типов а при реальном выполнении

[26:58] кода этого импорта не происходит и

[27:00] поэтому не будет циклических импортом Ну

[27:02] и мы указываем что тут уже не maped

[27:04] colum А тут relationship мы

[27:08] ссылают указать Какое поле мы используем

[27:10] для того чтобы попасть сюда наоборот с

[27:12] юзера и с юзера мы попадаем сюда через

[27:14] posts то есть на Юре мы обратимся к

[27:16] posts и получим этот пост Ну точнее

[27:18] список из постов Давайте же на Юзе

[27:21] объявим в обратную сторону posts будет

[27:24] maped Post этот пост точно также нужно

[27:27] ипор поэтому From tying импортируем Type

[27:31] Checking и делаем If Type Checking From

[27:34] dopost импортируем пост и этот пост Мы

[27:38] указываем в аннотации типа дальше нам

[27:40] нужно указать конечно что это аннотация

[27:42] после этого пишем равно и будет

[27:44] relationship снова relationship который

[27:48] мы указываем в качестве значения по

[27:50] умолчанию для этой колонки и Back это

[27:53] обратно что мы получим доступ сюда через

[27:56] User то есть с поста мы Обращаемся к

[27:59] юзеру через юзер А с юзера Обращаемся к

[28:03] постам через posts Однако мы Обращаемся

[28:07] к постам а не к одному посту А тут Я

[28:10] указал пост важно Уточнить что мы будем

[28:12] загружать не один пост А мы будем

[28:15] загружать список из постов там может

[28:17] быть ноль постов один пост 2 3 10 100 и

[28:20] так далее и важно указывать в аннотации

[28:22] типа что мы получаем именно список из

[28:25] постов и Вот так мы настроили связь

[28:27] между моделями юзер ссылается на список

[28:30] из постов а пост ссылается на юзера этот

[28:33] юзер обязательно присутствует на посте

[28:35] при этом не обязательно что у юзера

[28:37] будет хоть какое-то количество постов их

[28:39] может быть и ноль всё это не меняет

[28:41] состояние базы данных То есть это

[28:43] никакие не изменения в таблицах Это

[28:45] только изменения в нашем коде упрощающие

[28:47] взаимодействие с orm object relational

[28:49] mapping Поэтому если мы пытаемся сделать

[28:51] какую-то новую миграцию даже с тем же

[28:53] названием то мы увидим что в этой новой

[28:55] миграции нет никакого кода в агре или

[28:58] dade не произошло Никаких изменений мы

[29:00] добавили эти ссылки друг на друга только

[29:03] для того чтобы было удобнее работать в

[29:05] orm Давайте сохраним эти изменения я

[29:08] перейду к пост проверю что мы здесь

[29:12] ссылаются на posts это всё можно

[29:15] сохранить и напишем Create

[29:18] relationships

[29:20] between User and po и важно что мы это

[29:24] Коти вместе потому что связка

[29:25] двусторонняя мы Сыла с юзера на пост а с

[29:28] постов мы Сыла через поле юзера обратно

[29:31] к юзеру Ну и в обратную сторону с поста

[29:32] мы высылаем се вот к юзеру А через пост

[29:35] мы получим доступ к этим постам я делаю

[29:38] один общий комит И теперь у нас созданы

[29:40] модели с связкой один ко многим Теперь

[29:43] давайте посмотрим на связку один к

[29:45] одному и такое тоже иногда нужно

[29:47] например у одного пользователя может

[29:49] быть только один профиль и зачастую этот

[29:51] профиль должен обязательно

[29:52] присутствовать мы такое тоже можем

[29:54] сделать Давайте в Models объявим новую

[29:56] модель и после того как мы это всё

[29:58] создадим ещё посмотрим на запросы этих

[30:00] данных прой это будет новый модуль мы

[30:03] сделаем там то же самое что и в юзеры

[30:06] называем новую модель например

[30:09] прой и нам нужно обязательно здесь

[30:12] указать какие-то данные Ну на которые мы

[30:15] вообще создаём этот Профиль то есть для

[30:16] чего он нам нужен например тут может

[30:18] быть First name и мы будем хранить всю

[30:20] информацию о пользователе которая уже

[30:22] личная через профиль вот у нас есть Map

[30:25] string например First name у нас будет

[30:27] не более чем 40 символов также мы укажем

[30:31] что он не UN то есть либо UN fse либо

[30:33] просто удаляем это свойство после этого

[30:36] укажем Last name и тут будет ещё и

[30:39] фамилия точно так же с ограничением в 40

[30:41] символов при этом эти поля мы допускаем

[30:44] что будут пустые потому что пользователь

[30:46] не обязан заполнять информацию о себе

[30:48] поэтому мы укажем что тут либо string

[30:50] либо None в этот Профиль можно добавлять

[30:52] всё что угодно например ещё какая-нибудь

[30:54] биография bap тоже будет string или Ну и

[30:58] тут не будем делать ограничение по длине

[31:00] вот мы указали различные значения на

[31:03] этой модели и теперь модель профиля надо

[31:06] связать с пользователем для этого в

[31:07] проверке Type Checking импортируем юзера

[31:10] и здесь будет класс User а также нужно

[31:12] ещё и сам Foreign импортировать из SQL

[31:15] lch объявим ссылку на юзера User ID и

[31:20] тут будет maped и мы указываем integer

[31:23] равно maped colum и тут будет уже

[31:27] Foreign ке и мы указываем куда ссылается

[31:30] на

[31:31] users ID и также мы можем указать что

[31:34] это уникальная поле Unique True почему

[31:37] оно должно быть уникальным потому что у

[31:39] одного пользователя не может быть более

[31:41] одного профиля по-хорошему конечно чтобы

[31:43] всегда был ровно один профиль но

[31:44] допустимо чисто технически что профиля

[31:47] может совсем не быть но посмотрите что

[31:49] мы тут сделали Мы объявили поле которое

[31:51] очень-очень Похоже на то что мы делаем

[31:54] ещё и в пост в пост Мы точно так же

[31:56] ссылается на юзер ID делаем maped int

[31:59] Map colum и указываем здесь users ID

[32:01] получается мы копируем Код Да здесь ещё

[32:03] FL Unique но в любом коде У нас есть

[32:06] какие-то флаги и от места к месту мы

[32:08] меняем какой-то один-два параметра чтобы

[32:10] не писать это заново Давайте создадим

[32:12] mixin то есть прис который будет

[32:14] добавлять это поле туда где мы добавляем

[32:17] ссылку на юзера Я в Models объявлю новый

[32:20] Python файл это будет файл mixins это

[32:22] будет просто клас User relation Mix и

[32:27] тут мы добавим declared terter из SQL

[32:30] lch orm нужно импортировать declared

[32:34] atter и мы укажем что здесь будет

[32:36] свойство declared terter которое

[32:39] ссылается на User ID пользователя и

[32:42] внутри мы просто вернём Новую колонку

[32:45] как это делать в declared atter даже

[32:47] есть пример что мы тут можем сделать Вот

[32:49] первый же пример с пользователем

[32:51] которого мы можем подмешать Тут они

[32:52] указывают User ID на Верхнем уровне а

[32:55] внутри declared делают relationship но

[32:57] мы можем можем указать всё в declared

[32:58] terter Почему так будем делать потому

[33:00] что у нас могут быть разные значения вот

[33:02] смотрите я сюда User ID укажу нам

[33:04] конечно же нужно ещё импортировать maped

[33:06] и maped colum и импортируем ещё и

[33:09] Foreign Ke но мы хотим указать что в

[33:12] каком-то случае maped colum должно быть

[33:14] Unique поэтому я укажу что у нас тут

[33:17] будет ещё флаг User ID Unique и по

[33:20] умолчанию тут будет false Я указываю

[33:23] false и внутри declared atter User ID мы

[33:27] сделаем возврат этой колонки просто

[33:30] Return maped colum мы можем указать что

[33:31] мы возвращаем тут maped colum integer и

[33:35] делаем Return Map colum Fork User ID у

[33:39] нас будет просто табличка users ID и

[33:43] добавляем лаг Unique равно Self и

[33:47] указываем что у нас будет User ID Unique

[33:50] на самом деле это не Self а CS и

[33:52] по-хорошему нужно поменять на Л S

[33:54] поэтому укажем что это л S название

[33:57] конечно же не меняет сути но так будет

[33:59] сразу понятно что мы работаем с

[34:00] свойством на классе давайте избавимся от

[34:03] этого значения и напишем как будет

[34:05] выглядить просто ссылка на юзера Мы

[34:07] возвращаем отсюда maped User

[34:08] соответственно нам нужно сделать If Type

[34:11] Checking который мы импортируем из

[34:14] typing мы делаем From do User import

[34:18] User и из свойства User мы возвращаем

[34:20] maped User это будет relationship

[34:23] указываем что нам нужно импортировать

[34:24] relationship а также хорошо бы указать

[34:27] ещё и Back populate Ну куда Back

[34:29] populate опять же давайте укажем это на

[34:31] уровне класса Вполне себе нормальный

[34:33] вариант User Back populate то есть куда

[34:35] мы ссылают сторону и мы ссылается через

[34:39] свойство Back populate только это

[34:41] конечно же будет не buan здесь он нам

[34:43] подскажет что мы ожидаем не бун а string

[34:46] Давайте укажем string и пусть тут будет

[34:48] по умолчанию даже NAN поэтому допустим

[34:50] что у нас NAN то есть ничего не передано

[34:52] А если передано то мы укажем как

[34:54] раз-таки ту строчку куда мы ссылают

[34:56] важно указать имя класса к которому мы

[34:59] делаем ссылку потому что вот эта

[35:00] аннотация Map User она скорее для нас и

[35:03] нам не будет понятно что этот relation

[35:05] Ship ссылается именно на того юзера но

[35:07] так как мы прямо в relationship

[35:08] указываем на какой класс Мы ссылается то

[35:10] уже будет всё нормально и Алхимия

[35:12] сделает эту связку Давайте отформатирую

[35:13] при помощи Black и добавим переносы

[35:15] чтобы было чуть более читабельно И

[35:17] теперь этот User relation mixin мы можем

[35:19] добавить и к Post и к прой давайте для

[35:22] начала применим его в пост для этого я

[35:24] сюда добавлю новый mixin мы можем

[35:26] Добавить его в начале в конце не так

[35:27] важно главное из do mixins импортировать

[35:31] User relation mixin и я избавляюсь от

[35:34] обоих этих полей в кне User relation мы

[35:37] указывали User ID Unique но тут у нас

[35:39] ещё есть допустимый nullable True то

[35:41] есть вдруг там True а не false давайте

[35:43] такой флаг тоже добавим и по умолчанию

[35:45] пусть будет User ID nullable false и

[35:49] получается что там не может быть null и

[35:51] укажем это тут тоже будет nullable ра

[35:54] CLS userid nullable и вот это это

[35:57] свойство мы теперь укажем ещё и на

[36:00] классе Post мы можем указать User ID

[36:02] nullable false для явность User ID

[36:05] Unique false но так как это значение по

[36:08] умолчанию их указывать тут не

[36:09] обязательно Мы можем перезаписать их как

[36:11] раз-таки в профиле где это уже

[36:12] отличается User ID мы больше вот так не

[36:16] указываем и User мы не указываем но Back

[36:18] pulat надо будет указать posts поэтому

[36:20] мы добавим здесь свойство User Back

[36:23] popul ра Post и тогда вот это свойство

[36:26] попадёт уже в этот класс Давайте

[36:28] применим этот же mixin к профилю

[36:30] пользователя избавимся от лишнего кода

[36:33] только у нас здесь будет Unique True и я

[36:35] доме сюда User relation mixin сделаем

[36:38] import From mixins User relation mixin и

[36:42] нам надо добавить что это свойство

[36:45] должно быть уникальным то есть User ID

[36:47] Unique True N L false Там и так по

[36:49] умолчанию Ну и User Back P pulat мы

[36:52] обязательно укажем что мы сюда попадаем

[36:54] через прой то есть мы с юзера можем

[36:56] получить доступ на профиль через

[36:59] свойство профа и свойство ссылка на

[37:01] юзера будет приходить именно из declared

[37:05] Давайте на пользователя укажем ссылку

[37:06] обратно на профиль для этого на User я

[37:09] добавлю то же самое что было с posts

[37:11] только называться будет прой и тут будет

[37:14] maped просто профиль не лист из профилей

[37:17] а один профиль для этого я импортируют

[37:21] Profile Profile и relationship Back

[37:25] точно также User Мы через поле User

[37:26] получаем доступ к юзеру с профиля тут

[37:29] надо указать что это профиль вот и всё

[37:32] давайте сделаем миграцию и проверим что

[37:34] у нас поменялось если в посте технически

[37:37] ничего не изменилось то новой миграции

[37:39] на пост не будет Вот и посмотрим найдёт

[37:41] ли Олимпик разницу Я создам новую

[37:44] миграцию при помощи Olympic region

[37:45] autogenerate Create Profile Table и Мы

[37:49] выполняем миграцию смотрим на новый файл

[37:52] он сгенерирован успешно значит ошибок в

[37:53] коде нет и смотрим Что тут произошло

[37:55] upgrade Дай у нас пустые Почему Потому

[37:58] что в init Нужно обязательно

[37:59] импортировать Несмотря на то что мы

[38:01] добавляем здесь аннотации Мы импортируем

[38:03] здесь юзера Ну он кстати нам тут больше

[38:05] не нужен и наоборот мы делаем в этом Юзе

[38:08] ссылку на профиль только если проверка

[38:10] типов а при выполнении миграции нет

[38:12] проверки типов поэтому удалим миграцию

[38:14] которая нам не пригодилась мы добавим в

[38:17] init уже этот профиль From do Profile

[38:20] import Profile для красоты добавим Его

[38:22] ещё и в All и посмотрим что будет если

[38:24] сгенерировать миграцию заново Давайте

[38:26] выполним revision A generate Create

[38:28] Profile Table смотрим на новый файл

[38:30] миграции тут уже появилась новая

[38:33] миграция на профиле заметьте откатывать

[38:35] мы только создание профилей То есть у

[38:37] нас не произошло Никаких изменений над

[38:39] таблицей Post получается что в пост при

[38:41] помощи этого кына мы не добавили ничего

[38:44] нового и не удалили ничего существующего

[38:46] Давайте уберём здесь лишние куски кода

[38:49] которые нам больше не пригодятся вот эти

[38:51] лишние импорты и для примера можно будет

[38:54] ещё из поста убрать что-нибудь и увидеть

[38:56] что по СТ всё также версионирование

[39:00] миграцию её Нужно обязательно проверить

[39:03] мы создаём таблицу profiles First name

[39:05] nullable True lastname nullable True Bio

[39:08] просто string nullable True User ID

[39:10] nullable false то есть профиль должен

[39:12] обязательно ссылаться на пользователя ID

[39:14] N false логично и мы

[39:16] ссылали users ID primary constraint ID

[39:20] Ну и Unique constraint User ID то есть

[39:22] User ID будет уникален и в таблице

[39:24] profiles не может быть двух профилей

[39:26] ссылающихся на одного Поль откат обратно

[39:28] - это удалить таблицу profiles и нас это

[39:30] всё устраивает Давайте выполним миграцию

[39:31] alimpic upgrade Head всё прошло успешно

[39:34] посмотрим на базу данных у нас появилась

[39:36] новая таблица profiles и здесь есть все

[39:39] те колонки Давайте сохраним изменения

[39:41] для этого я перейду в commit и напишем

[39:44] что мы сделали User relation mixin для

[39:47] начала можно добавить это только в пост

[39:50] я напишу Create User relation mixin и

[39:55] также нам нужно ещё и обозначить что мы

[39:58] создали профиль пользователя вот мы

[40:00] добавляем профиль пользователя вот мы в

[40:02] юзер ссылается на профиль пользователя

[40:04] Create Profile for User и также мы

[40:07] выполнили миграцию поэтому Добавим что

[40:09] мы создали новую миграцию и тут у нас

[40:11] было уже migration for profiles Table

[40:15] вставим сюда и нажмём commit всё Мы

[40:17] сохранили все изменения в коде мы

[40:20] закоммитить всё что мы написали давайте

[40:22] убедимся что пост всё ещё отслеживается

[40:24] например Мы хотим чтобы тайтл больше не

[40:27] было я создам новую миграцию перейду в

[40:30] терминал и напишу Olympic revision мину

[40:33] - generate - M допустим update posts

[40:36] Table и посмотрим что будет в новой

[40:39] миграции перехожу к новому файлу и мы

[40:41] видим что таблица posts версионирование

[40:57] то есть Точно та же самая строчка длиной

[40:59] 100 и nullable false это все те свойства

[41:01] которые были на модели пока мы не

[41:04] применили эту миграцию можно вернуть Всё

[41:06] как было и удалить миграцию которую мы

[41:08] только что создали давайте убедимся что

[41:10] никаких изменений сейчас на posts нет и

[41:12] в новой миграции в апгрейды даунгрейд

[41:14] будет пусто вот действительно Здесь всё

[41:16] пусто получается у нас пока что

[41:18] актуальное состояние базы данных и

[41:20] моделей следить за версиями olic можно

[41:23] при помощи разных команд например

[41:25] olimpic history покажет нам историю

[41:27] миграции и вот Мы начинали с базовой

[41:29] миграции Ну там ничего ещё нет мы

[41:31] добавляем таблицу products потом

[41:32] добавляем ещё таблицу users добавляем

[41:34] таблицу Post и добавляем таблицу про

[41:36] файл также мы можем посмотреть где мы

[41:37] сейчас находимся Olympic current и мы

[41:40] можем откатываться или наоборот

[41:42] прикатывать на любую миграцию вот сейчас

[41:44] мы на самой последней но мы можем

[41:46] откатиться например при помощи alimpic

[41:48] downgrade на две миграции назад куда мы

[41:50] откатится мы откатится на две миграции

[41:53] назад То есть когда у нас была создана

[41:54] таблица с пользователями но ещё нет

[41:56] Таблицы с постами Давайте проверим и вот

[41:58] нет таблицы posts и мы можем выполнить

[42:00] Olympic current и увидеть что сейчас мы

[42:02] на миграции cfa если сделать Olympic

[42:06] history то мы увидим что вот у нас есть

[42:09] всё что мы создавали но сейчас мы на

[42:12] этой миграции cfa Вот она Create users

[42:14] Table следующая строчка где тут cfa это

[42:17] уже миграция с Create users Table на

[42:20] Create Post Table чтобы применить все

[42:22] миграции мы можем просто сделать alimpic

[42:24] upgrade Head и мы попадём на самую

[42:27] последнюю версию вот у нас есть и posts

[42:29] и profiles чтобы откатиться в самый

[42:31] конец можно использовать downgrade и не

[42:34] минус какой-то а просто указать Бейс и

[42:37] так мы откате на самое-самое начало мы

[42:39] видели что тут базовая миграция так

[42:41] называется Бейс Вот мы откатились и в

[42:42] базе данных не осталось ничего кроме

[42:44] Olympic version Ну и SK Master Мы даже в

[42:46] расчёт не берём сделаем заново upgrade

[42:48] Head и будут выполнены все миграции

[42:50] потому что они работают во все стороны

[42:52] Теперь давайте посмотрим как делать

[42:54] запросы на создание или чтение этих

[42:57] данных из базы при помощи связей то есть

[42:59] мы например хотим создать юзера И для

[43:02] него создать профиль для этого я пока

[43:04] что для демонстрации создам новый Файлик

[43:07] который тоже назову crd и тут мы

[43:09] посмотрим на различные действия для

[43:11] начала объявите Main и тут будет блок

[43:14] Main предлагаю тут сразу же сделать ass

[43:16] I Run и вызовем здесь функцию Main

[43:20] которую мы объявим в виде async Def Main

[43:23] и тут мы будем уже выполнять все запросы

[43:25] Нам нужно будет воспользоваться тем тем

[43:27] же самым dbhelper поэтому предлагаю

[43:28] сделать From Core Models import db

[43:33] Helper и сделаем assy with db Helper

[43:37] Session Factory получим здесь сессию и с

[43:41] этой сессией мы можем делать запросы

[43:43] дальше мы можем уже сделать например

[43:44] asing with Session begin и выполнять

[43:47] какие-то запросы Ну или даже без begin

[43:49] просто вызывать например взаимодействие

[43:52] с таблицами с базой данных сделаем

[43:54] сначала создание пользователя для этого

[43:56] я и и Cor Models ещё и юзера и User

[43:59] Profile и также нам пригодится пост

[44:02] сделаем различные запросы я создам новую

[44:05] функцию asy Def и тут у нас будет Create

[44:09] User мы получаем сюда сессию Session

[44:12] которая будет assy Session давайте

[44:15] укажем аннотацию мы импортируем ass

[44:17] Session из SQL extension и в качестве

[44:19] аргумента функции нам также нужно

[44:21] указать рй пользователя которого мы

[44:22] создаём отсюда мы вернём созданного

[44:24] пользователя вот Я создаю здесь новый

[44:26] экземпляр User равно User и указываю ему

[44:29] username username надо указать в виде

[44:31] кейворда потому что мы сюда доки дым

[44:33] свойства всё остальное пока что мы не

[44:35] указываем вот он User мы добавляем его в

[44:37] сессию действие синхронное оно не

[44:40] взаимодействует с базой данных просто

[44:42] передаём сюда instance User а затем

[44:44] делаем Session commit вот о так сохраним

[44:47] пользователя но уже нужно сделать evade

[44:49] потому что это асинхронное действие

[44:50] после этого вернём отсюда пользователя

[44:52] Давайте добавим пользователю красивое

[44:53] строковое представление чтобы мы могли

[44:55] его легко распечатать я сделаю Def

[44:57] string и вернём отсюда например просто F

[45:00] строчку где мы укажем имя текущего

[45:03] класса Self CL то name и в скобочках

[45:06] передадим username равно Self username

[45:10] указательный знак R чтобы был

[45:11] репрезентативный вид И ещё я

[45:16] докинути класса Вот так мы сохраним этот

[45:19] стринг и также добавим ещё reper чтобы

[45:22] мы могли ещё и в списке пользователей

[45:24] видеть точно так же я сделаю просто

[45:25] string от себя string от Self и так мы

[45:28] получим строковое представление там где

[45:29] у нас ещё и р посмотрим на создание

[45:31] этого пользователя для этого я вызову

[45:33] Create User вот здесь в контекстном

[45:35] менеджере сделаем Create User

[45:37] обязательно подождём потому что это

[45:38] асинхронная функция передадим Session

[45:40] равно Session и username равно John Так

[45:43] мы создаём нового пользователя John и

[45:45] также создадим пользователя SM Давайте

[45:47] распечатаем Что у нас там придёт я

[45:49] предлагаю чтобы избавиться от копипасты

[45:51] распечатать пользователя Когда мы уже

[45:53] его создали здесь будет User и мы

[45:55] распечатаем посмотрим на него конечно же

[45:58] эти принты нужны только сейчас такой для

[45:59] быстрой отладки выполним Main и

[46:02] посмотрим что у нас получилось User ID 1

[46:05] и username John будет User ID 2

[46:07] посмотрим на базу данных и в таблице

[46:09] users есть оба этих пользователя так как

[46:11] мы используем db Helper мы подключаемся

[46:13] к той же самой базе данных То есть мне

[46:15] не пришлось ничего менять вот он

[46:16] dbhelper подключается через settings db

[46:18] URL Кстати мы можем ещё и в этих

[46:20] настройках разнести различные конфиги на

[46:23] вложенные модели предлагаю сейчас это

[46:24] сделать потому что Это займёт совсем

[46:26] немного времени из piden я

[46:30] импортируют bas Model для identic модели

[46:33] и назову например db config или db

[46:37] settings Наследник от Base Model и

[46:42] внутри Мы объявим те же самые свойства

[46:44] которые указывали ранее Давайте укажем

[46:45] здесь db URL и db Echo А на этот db

[46:49] settings мы будем ссылаться Из основной

[46:51] настройки settings кстати давайте мы

[46:53] здесь добавим ещё и s в конце не

[46:57] сделаем тут db и можно указать просто db

[47:01] двоеточие db settings равно db settings

[47:04] я укажу значение по умолчанию потому что

[47:06] у нас тут есть значение по умолчанию

[47:07] получается в settings db будут свойства

[47:10] db URL и db Echo и мы можем избавиться

[47:12] от этих префиксов потому что и так

[47:14] понятно что в db settings URL - Это

[47:16] ссылка на db на Database Давайте ещё вот

[47:19] тут сделаем чуть-чуть более красиво я

[47:21] строил путь внутри строчки хотя у нас и

[47:23] так P lep который прекрасно строит пути

[47:25] Поэтому я сделаю dbp или db URL Ну

[47:28] давайте здесь будет dbp равно и мы

[47:31] сделаем Просто Base dirar SL то есть ну

[47:34] разделить по сути На вот эту строчку db

[47:37] SQL 3 и вот этот dbpath мы уже вставим

[47:40] сюда в виде строчки так будет более

[47:42] Правильно Потому что мы строим новый

[47:43] путь вот и всё давайте мы

[47:54] переиспользовать обращение к Сен

[47:57] db URL и settings db eo и то же самое

[48:02] ещё и в NP в олимпике тут у нас будет

[48:05] settings db И вот этот URL - это

[48:08] вложенный объект в db settings сохраним

[48:11] изменения и Давайте перейдём обратно к

[48:14] OT чтобы посмотреть на создание профиля

[48:16] для пользователя для того чтобы создать

[48:18] профиль для пользователя нужно этого

[48:19] пользователя вытащить поэтому мы сделаем

[48:21] простой запрос мы уже с вами знаем как

[48:23] искать пользователя по ID Мы искали

[48:25] продукт по ID можем посмотреть это в apv

[48:28] 1 crot и тут было Get product по ID мы

[48:32] делали Просто Session Get поэтому

[48:34] сделаем фильтрацию тут мы ещё не делали

[48:36] фильтрацию сделаем поиск по юзернейм у

[48:38] нас будет asy Def Get User by username

[48:44] получаем сюда сессию Session assy

[48:46] Session и сам username это будет строчка

[48:49] мы либо найдём пользователя либо нет

[48:51] поэтому мы возвращаем либо пользователя

[48:53] либо NAN и у нас может быть найден

[48:55] максимум один пользователь поэтому мы

[48:57] делаем statement равно Select этот

[49:00] Select нужно импортировать из SQL lch и

[49:03] мы ищем пользователя User добавляем

[49:05] фильтрацию Where То есть как и в SQL

[49:07] запросе Select Where Select Where User

[49:11] то username ра урней вот и всё это весь

[49:14] мен тут мы можем сделать двумя

[49:16] вариантами либо как мы уже делали вкд

[49:19] сначала получаем result Потом делаем

[49:20] scalers но так как мы хотим найти один

[49:23] экземпляр мы можем сделать например

[49:25] scaler One или SC One or None для этого

[49:28] я воспользуюсь тем же самым

[49:31] Session execute получу сюда result и мы

[49:35] получаем Session execute statement

[49:37] обязательно Добавим сюда аннотацию чтобы

[49:39] нам подсказали что мы забыли сделать ещё

[49:41] и evate импортируем из SQL lch result он

[49:45] находится в SQL lch Engine берём отсюда

[49:50] result и тут нам подсказывают что

[49:52] вообще-то ты может быть хотел сделать

[49:54] evade поэтому мы делаем evate и получаем

[49:57] уже сюда результат нам нужно вытащить

[49:59] юзера мы допускаем что юзер может быть

[50:02] не найден тогда мы делаем scaler One or

[50:04] None то есть мы нашли одного

[50:06] пользователя User и он будет либо

[50:08] пользователь либо None и мы этого юзера

[50:11] вернём то есть мы можем распечатать

[50:13] Print found User и выведем сюда

[50:16] пользователя но мы можем его не найти

[50:18] поэтому давайте мы сюда добавим ещё

[50:20] отдельно username и тут может быть

[50:21] просто None давайте сделаем вызов этой

[50:24] функции Get User by username я рую

[50:27] создание пользователя и поищем разных

[50:29] пользователей evade Get User by username

[50:31] тут укажем например SM а также сделаем

[50:34] Bob конечно же и тут и тут нам нужна ещё

[50:36] и сессия передадим Session равно Session

[50:39] и username равно username посмотрим на

[50:42] выполнение этого кода Run и мы видим

[50:44] found User Sam с таким-то ID и found

[50:47] User Bob None если бы мы точно знали что

[50:50] пользователь существует прямо уверены и

[50:52] мы готовы рискнуть то мы можем сделать

[50:55] SC One без or Итак мы получим значение

[50:58] или исключение вот мы нашли пользователя

[51:01] SM но так как Bob мы не нашли то

[51:04] получили исключение можно его поймать в

[51:05] TR Accept И если мы точно уверены что

[51:07] пользователь есть лучше использовать SC

[51:09] One чтобы мы не наткнулись на None

[51:11] Потому что если мы натыкается на NAN то

[51:13] мы не сможем например обратиться к

[51:14] юзернейм это важно и ещё мы можем тут

[51:17] чуть-чуть сократить количество кода

[51:19] сделав User ра AV Session SC и сюда

[51:25] передать Stat смотрите что будет

[51:27] выполним код заново и мы видим что тут

[51:29] либо User SM либо User None и получается

[51:33] что тут Точно также будет User или None

[51:36] мы можем получить это при помощи Session

[51:38] scaler и нам не придётся работать с

[51:40] result и из него отдельно брать scaler

[51:42] One or None вот мы вытащили пользователя

[51:44] Теперь для этого пользователя можно

[51:45] создать профиль давайте сделаем Это я

[51:48] объявлю новую функцию async Def Create

[51:52] User Profile и мы можем сюда принимать

[51:55] сессию как обычно Session и либо

[51:58] пользователя User либо User ID давайте

[52:01] сделаем User ID потому что мы в итоге

[52:02] ссылается всё-таки на ID пользователя

[52:04] это будет integer Ну и отсюда мы вернём

[52:07] профиль пользователя У пользователя не

[52:09] может быть больше одного профиля поэтому

[52:10] мы на каждого пользователя создадим по

[52:12] одному профилю Ну не будем пытаться даже

[52:13] создавать два прой равно прой и в

[52:17] профиль мы можем передать дополнительные

[52:19] параметры которые мы хотим можем Ничего

[52:21] здесь не указывать или у кого-то указать

[52:23] First name или что-то ещё поэтому

[52:24] Давайте дом First name это либо STR либо

[52:27] None также Last name - это либо string

[52:31] либо N Ну и B сейчас не будем просто

[52:33] тратить время не станем записывать

[52:35] Давайте отформатирую чтобы это было на

[52:37] новых строчках и в профа докини User ID

[52:41] равно userid мы Сыла на этого

[52:42] пользователя First name равно First name

[52:44] Ну и Last name равно Last name Вот Мы

[52:47] создали новый экземпляр нужно его

[52:49] добавить Session Add Profile и делаем AV

[52:53] Session commit то есть сохраняем всё в

[52:55] базу Ну и делаем Return прой не будем

[52:58] ему сейчас строковое представление

[52:59] добавлять просто посмотрим на то что

[53:00] получится в базе данных вот мы вытащили

[53:02] пользователей Мы точно нашли

[53:03] пользователя SM поэтому мы воспользуемся

[53:04] им а Бобом Можно даже не пользоваться я

[53:07] это закомментировать

[53:11] Например какого-нибудь юзера joh

[53:14] которого мы точно создавали создадим

[53:15] профиль для этих пользователей начнём с

[53:17] Джона evade Create Profile и вот у нас

[53:20] Create User Profile Session = Session

[53:23] User ID = User John ID First name будет

[53:28] например joh Last name не будем даже

[53:30] указывать вот у нас есть joh всё Last

[53:32] name можно не указывать поэтому мы

[53:33] добавим здесь значение по умолчанию N Ну

[53:35] и на самом деле First name тоже можно

[53:37] указать N самое главное передать User ID

[53:39] и создадим профиль ещё и для

[53:41] пользователя SM То есть у нас будет

[53:43] профиль для юзера SM и у него будет SM и

[53:47] Давайте добавим ему ещё и Last name

[53:49] равно White Так мы добавим профиль для

[53:52] этих пользователей Давайте выполним код

[53:53] мы находим пользователей и создаём их

[53:55] выполня и видим что мы этих

[53:58] пользователей нашли и Давайте посмотрим

[53:59] в базе данных Мы в profiles добавили два

[54:02] профиля у Джона нет lastname и Boo но

[54:05] есть ссылка на User ID Ну и У Сэма есть

[54:08] и First name и Last name и у него есть

[54:10] ID Окей давайте посмотрим на то какие у

[54:14] этих пользователей вообще профили то

[54:16] есть я могу запросить этих пользователей

[54:18] по юзернейм и посмотреть на их профили

[54:20] давайте я сделаю отдельную функцию мы

[54:23] будем искать пользователей и выводить

[54:25] профили можно смотреть даже не на

[54:27] каждого отдельно А на всех подряд async

[54:29] Def Show users with profiles и в

[54:33] profiles мы укажем Session обязательно I

[54:37] Session Ну и отсюда мы можем вернуть

[54:38] всех пользователей Но это не обязательно

[54:40] ну мы сделаем аннотацию что мы

[54:41] возвращаем список из юзеров получаем

[54:45] всех пользователей объявим statement

[54:46] Select User мы обязательно запрашиваем

[54:49] юзеров можем ещё для красоты

[54:50] отсортировать Order byy

[54:53] user.id и надо выполнить execute result

[54:56] это будет result равно avait Session

[54:59] execute мы там кстати можем взять ещё

[55:01] Session scalers но там немного другой

[55:03] подход выполняем тут statement и можем

[55:06] пойти по всем юзера то есть users равно

[55:08] result то scalers это один из вариантов

[55:11] Либо мы сделаем avid Session scalers

[55:15] сюда передать Точно также statement мы

[55:18] указываем что это будет users Но на

[55:19] самом деле здесь не список ИС

[55:21] пользователей А здесь будет SC result и

[55:23] Давайте попробуем по ним пойти for User

[55:25] in users и распечатаем самого юзера То

[55:28] есть у нас будет User и мы просто пока

[55:31] что его выводим Давайте выполним этот

[55:33] код и я укажу Show users with profiles

[55:37] aade и передаём сюда сессию Session

[55:39] равно Session выполним этот код и мы

[55:41] увидим что вот они пользователи первый и

[55:44] второй Давайте посмотрим на их профили

[55:46] мы можем сделать Print User и также User

[55:51] Profile обратиться к профилю и вывести

[55:53] например First name Потому что тут мы

[55:55] работаем уже с профилем пользователя на

[55:58] users профа у нас указана аннотация типа

[56:00] что тут будет

[56:05] профайлскул

[56:07] код заново и мы видим здесь ошибку что

[56:10] это за ошибка он попытался сделать новый

[56:13] запрос в сеть и мы вытащили первого

[56:15] пользователя Однако мы не смогли

[56:16] запросить профиль Давайте посмотрим что

[56:18] тут реально происходит с базой данных

[56:20] указав в конфиге Эхо True я просто пока

[56:22] что закомментировать

[56:26] Увидим что мы сначала запросили

[56:28] пользователя вот мы запрашиваем

[56:29] пользователя мы его запросили успешно а

[56:31] потом мы запрашиваем профиль Дело в том

[56:33] что профиль по умолчанию не подгружается

[56:34] А в asino критично подгружать всё сразу

[56:38] потому что если мы ещё в синхронном

[56:39] подходе можем на ходу что-то загружать

[56:41] то в асинхронном уже это делать нельзя

[56:43] Поэтому нам нужно добавить

[56:45] дополнительные параметры к выполнению я

[56:47] укажу Select то options и докинути

[56:51] параметры нужно тоже импортировать из

[56:53] SQL orm для этого из SQL

[56:56] or Я

[57:01] импортирует запрос параметры я сделаю

[57:04] Joint Load и скажу что мы хотим

[57:07] загрузить сюда ещё и профиль

[57:09] пользователя User Profile Давайте

[57:11] посмотрим что получится теперь выполним

[57:13] тот же самый код и в одном запросе мы

[57:16] запросили и юзера и его профиль и вот мы

[57:19] вводим username

[57:21] имя имя давайте посмотрим более

[57:24] внимательно на этот SQL для этого содам

[57:26] новый Файлик queries и здесь будет новый

[57:30] файл

[57:31] queries SQL и сюда Я вставлю всё что

[57:35] было выполнено на стране SQL lch и вот

[57:38] мы видим что идёт запрос юзеров и к ним

[57:41] присоединяются профили и мы делаем это

[57:43] одним запросом если я выполню этот код

[57:46] прямо здесь Давайте мы его выполним на

[57:47] базу данных у нас будет стандартная

[57:50] сессия консоль то мы получим в ответ

[57:52] юзеров с их профилями всё в одном месте

[57:55] мы просили эти поля на юзеры Вот и Bio и

[57:58] Last name и First name и здесь есть

[58:00] ссылки на юзеров поэтому Алхимия смогла

[58:03] это всё прочитать правильно распарсить и

[58:05] связать пользователя с его профилем

[58:07] Давайте уберём вот эту аннотацию мы всё

[58:09] равно ничего не возвращаем и посмотрим

[58:11] теперь на создание постов к пользователю

[58:14] И как мы там

[58:17] подгружает в конфиге как было Эхо fse

[58:19] потому что никогда их ру не должно

[58:20] оставаться это нужно только для моментов

[58:22] отладки и создадим новые посты для

[58:25] пользователя assn Def Create posts и я

[58:29] передам сюда Session assy Session а

[58:31] также Пусть это будет posts titles это

[58:35] будут строчки но мы их накида в любом

[58:37] количестве И самое главное На какого

[58:38] пользователя мы ссылается User ID - это

[58:40] будет integer отсюда мы вернём посты я

[58:43] добавлю аннотацию что мы возвращаем

[58:45] отсюда список из постов и добавим Тут

[58:48] ещё запятую и отформатирую чтобы всё

[58:50] было на новых строчках так будет более

[58:53] читабельно на посте Давайте добавим тоже

[58:55] строковое представление и я предлагаю

[58:57] сделать Почти то же самое что было на

[58:59] юзеры то есть мы возьмём и string и

[59:02] reper оттуда но здесь ланей Post ID

[59:05] такой же а вместо username у нас будет

[59:07] title всё остальное оставляем как было

[59:08] так нам будет легко понять какой пост Мы

[59:10] создали теперь вернёмся в CR и создадим

[59:14] новые посты posts равно это будет список

[59:17] for title in Post titles создаём

[59:20] экземпляр пост и передаём сюда title

[59:23] равно title а также User ID равно userid

[59:26] на этого юзера мы ссылаясь User relation

[59:30] mixin и мы можем User ID задавать

[59:33] Давайте посмотрим что будет с этим

[59:35] постом когда мы его создадим Для этого

[59:36] необходимо сделать Session Add All то

[59:38] есть мы добавляем сюда список и передаём

[59:40] Просто posts потом мы делаем ait Session

[59:43] commit сохраняем все изменения Ну и

[59:46] вернём эти посты Return posts можно ещё

[59:49] для информации добавить Print чтобы

[59:51] посмотреть на созданные посты вот мы

[59:53] создаём эти посты для разных

[59:54] пользователей Create Po я добавлю Create

[59:58] мы сюда передадим Session также мы сюда

[01:00:01] передадим User ID Пусть Например у нас

[01:00:04] будет User John и User который создают

[01:00:07] посты вот мы передаём

[01:00:10] user.id и доки два Post titles например

[01:00:15] sq20 затем пусть будет SQ joints Ну и

[01:00:19] пара постов для него хватит и тоже самое

[01:00:21] сделаем ещ и для

[01:00:23] пользователя Us

[01:00:26] и пусть он нам создаёт посты для Fast

[01:00:29] API тут будет Fast API Intro потом у нас

[01:00:33] будет ещё Fast API Advanced Ну и можно

[01:00:37] добавить Fast API More у нас будет

[01:00:39] какое-то количество постов от разных

[01:00:41] пользователей могут быть пользователи у

[01:00:43] которых нет постов для этого Давайте

[01:00:44] создадим ещё одного пользователя и пусть

[01:00:46] этого пользователя зовут Эс сделаем

[01:00:49] дубликат и Пусть это будет El выполним

[01:00:51] этот код и посмотрим что получится Мы

[01:00:54] создали пользователя El спросили

[01:00:56] пользователей Сэм и Джон и создали посты

[01:00:58] первый второй пост у первого

[01:00:59] пользователя Ну и третий четвёртый пятый

[01:01:01] у второго пользователя Кстати чтобы мы

[01:01:03] могли видеть Какой пост у какого

[01:01:05] пользователя можно прямо на пост ещё в

[01:01:08] строковое представление добавить кто у

[01:01:10] него автор Поэтому я сделаю User ID =

[01:01:13] Self то userid Ну так будет более

[01:01:16] Понятно Чей это пост вернёмся в КД и

[01:01:19] посмотрим как загрузить юзеров с их

[01:01:20] постами и как загрузить посты с их

[01:01:22] пользователями начнём с юзеров с их

[01:01:25] постами async Def Get users with posts и

[01:01:29] тут мы получаем сессию Session 2то async

[01:01:32] Session А больше ничего указывать тут и

[01:01:34] не надо мы будем получать пользователей

[01:01:37] и печатать их сделаем запрос statement и

[01:01:40] точно так же мы запрашиваем Select User

[01:01:42] но если мы просто Запроси юзеров даже

[01:01:44] там отсортированных не отсортированных

[01:01:46] мы получим ошибку как только попытаемся

[01:01:47] обратиться к постам этого пользователя

[01:01:50] поэтому я обязательно добавляю Тут ещё и

[01:01:52] options и указываю что мы

[01:01:55] То есть присоединяем то что мы получаем

[01:01:58] по User po мы загружаем все посты дальше

[01:02:02] мы получаем всех юзеров users равно AV

[01:02:04] Session scalers и получаем тут результат

[01:02:07] по statement пойдём по всем юзера и

[01:02:10] посмотрим for User in users печатаем

[01:02:13] юзера и также мы распечатаем все посты

[01:02:16] Давайте здесь добавим для красоты вот

[01:02:18] так пару звёздочек даже можно умножить

[01:02:21] так на 10 и печатаем юзера и печатаем

[01:02:24] все посты пользователя for Post in User

[01:02:27] posts и надо обратиться к юзеру posts мы

[01:02:30] тут работаем с юзера можно добавить

[01:02:31] аннотацию вот так вот Type двоеточие Юр

[01:02:34] то есть мы Обращаемся именно к юзеру и

[01:02:35] печатаем например тут какой-нибудь минус

[01:02:37] запятая ну и сам пост Вот так мы выведем

[01:02:40] все посты Вот так мы сделали селек User

[01:02:42] присоединили к ним посты к всем

[01:02:44] пользователям и дальше печатаем всех по

[01:02:46] одному давайте сделаем тот же самый

[01:02:48] вызов создание нам больше не нужно и

[01:02:50] делаем aate Get users with Post Session

[01:02:53] Рав Session Ну а тут нам создание и

[01:02:56] получение пока что больше не нужно

[01:02:58] выполним этот код и Давайте сразу же ещё

[01:03:00] и в config добавим снова Echo True

[01:03:03] потому что нам важно посмотреть в каком

[01:03:05] виде будет сделан запрос Как вы видите

[01:03:07] тут мы получили ошибку Unique Method

[01:03:09] must be invoked on This result смотрите

[01:03:11] что у нас вышло мы делаем запрос в

[01:03:13] котором мы тянем пользователей вместе с

[01:03:15] постами но у одного пользователя может

[01:03:17] быть несколько постов посмотрим на qu

[01:03:19] SQL я сделаю здесь новый запрос И мы

[01:03:22] просим загрузить пользователей а также

[01:03:25] мы просим загрузить посты Но если это

[01:03:27] сделать в таком виде мы получим в

[01:03:29] результате список из пользователей

[01:03:31] которые повторяются потому что на

[01:03:32] каждого пользователя мы подгружает да у

[01:03:35] кого-то совсем нет постов но мы тоже

[01:03:37] подгрузить этого пользователя Потому что

[01:03:38] тут используется Left outer Join Если бы

[01:03:40] не было outer Join А был бы просто Join

[01:03:43] то мы бы Эс не подтянули но нам-то нужно

[01:03:45] чтобы мы подтянули пользователей по

[01:03:46] одному То есть каждый раз запрашивать

[01:03:48] Джона на каждый из постов Ну не лучшее

[01:03:50] решение Однако тут мы можем сделать так

[01:03:53] можно и с result Colors работать то есть

[01:03:54] тут сделать то

[01:03:56] UN Вот так и мы получим то что нам нужно

[01:03:58] Давайте выполним и в этот раз всё будет

[01:04:00] Вот первый пользователь его посты 1 2

[01:04:03] вот второй пользователь его посты 435 и

[01:04:05] вот пользователь 3 и у него тут нет

[01:04:07] постов но вместо того чтобы делать Вот

[01:04:09] этот к мы можем посмотреть на другой

[01:04:10] способ присоединения другой Join давайте

[01:04:13] я закомментировать

[01:04:17] без Session scalors А через result

[01:04:20] result дто result равно avit Session

[01:04:23] execute тот же самый statement для

[01:04:25] начала и users будет список из

[01:04:28] пользователей Ну почти это будет

[01:04:29] sequence и users будет result то Unique

[01:04:34] и тут мы к Unique уже Обращаемся scalers

[01:04:37] и получаем уникальные значения тогда тут

[01:04:39] не будет ошибки мы можем сделать тут то

[01:04:41] же самое обратимся просто к списку изс

[01:04:44] пользователей Ну точнее

[01:04:45] последовательности из пользователей и

[01:04:47] получим такой же результат у нас будет

[01:04:48] такой же запрос но мы можем

[01:04:49] воспользоваться ещё одним помощником это

[01:04:51] будет Select in Load его очень хорошо

[01:04:53] использовать для связи ко многим а

[01:04:55] смотрите у нас связь с пользователя к

[01:04:58] постам ко многим поэтому мы можем тут

[01:05:00] сделать вместо Joint Load просто Select

[01:05:04] in Load я укажу тут другой вариант и у

[01:05:07] нас будет Select in Load и Select in

[01:05:10] Load делает отдельный запрос и

[01:05:11] подгружает все посты отдельно и повторно

[01:05:14] пользователи запрошены не будут тут уже

[01:05:16] не нужно использовать Unique я это тоже

[01:05:18] закомментировать обойтись без Unique и в

[01:05:21] таком виде мы получим точно такие же

[01:05:23] результаты смотрите мы видим тех же

[01:05:25] пользователей с теми же постами Но в

[01:05:27] этот раз было два запроса в базу данных

[01:05:30] посмотрим на эти запросы идём в queries

[01:05:33] и я сюда вставлю эти значения мы

[01:05:35] получаем пользователей с айди никами 1 2

[01:05:38] 3 делаем первый запрос и нам

[01:05:40] возвращаются пользователи Давайте

[01:05:41] посмотрим вот наш первый запрос - это

[01:05:43] просто пользователи и в этом запросе мы

[01:05:45] видим всех пользователей дальше Алхимия

[01:05:47] собирает с них ID и делает новый запрос

[01:05:50] и в этом запросе уже выполняется поиск

[01:05:53] постов для пользователей с этими ID то

[01:05:55] есть пост по ID фильтруется и если у нас

[01:05:58] совпадает User ID то мы получаем эти

[01:06:01] посты Как видите мы делаем

[01:06:02] дополнительный запрос но зато мы

[01:06:04] экономим на дублировании больше нет

[01:06:05] дублирования юзеров мы получаем

[01:06:07] уникальных пользователей и получаем

[01:06:08] уникальные посты Давайте посмотрим что у

[01:06:11] нас тут и мы всё остальное делаем точно

[01:06:13] так же То есть можно идти и по Session

[01:06:15] execute и тут будет scalers Либо мы

[01:06:17] можем сделать просто users равно AV

[01:06:20] Session SC и передать сюда statement мы

[01:06:23] получим точно такой же результат

[01:06:24] смотрите и у на У нас тут всё выводится

[01:06:26] в том же виде Давайте Запроси посты с

[01:06:29] пользователями то есть в обратную

[01:06:30] сторону из поста на пользователя У нас

[01:06:32] связь к одному Поэтому Там мы будем

[01:06:34] использовать Joint lad Как вы видите

[01:06:35] Joint lad можно использовать и ко многим

[01:06:38] и к одному но когда мы делаем ко многим

[01:06:40] нам приходится делать ещё и Unique и

[01:06:42] плюс мы получаем лишнее дублирование

[01:06:43] Поэтому лучше использовать Select in

[01:06:45] Load давайте сделаем ass Dev Get posts

[01:06:48] with a например Это же авторы постов и

[01:06:51] получаем сюда сессию Session - это

[01:06:53] Session Ну и сделаем Почти то же самое

[01:06:56] ра Select запрашиваем пост и обязательно

[01:06:59] Добавим сортировку Order bu пусть будет

[01:07:02] Post ID и сделаем тоже Joint lad мы

[01:07:05] запрашиваем к одному Поэтому в options я

[01:07:07] доки Joint Load и передаю сюда Post то

[01:07:11] User мы загружаем юзеров для постов всё

[01:07:14] выполняем запрос сделаем po равно AV

[01:07:19] Session и передаю сюда statement сделаю

[01:07:22] теперь for po in и тут мы получаем посты

[01:07:26] можно добавить для себя аннотацию для

[01:07:27] красоты просто Type двоеточия Post

[01:07:30] давайте сделаем Print Post - это Post а

[01:07:34] также его автор мы сделаем Print aor po

[01:07:38] User Ну можно было назвать и aor так как

[01:07:40] мы загрузили всё одним запросом мы

[01:07:43] увидим все эти данные сразу же давайте

[01:07:45] сделаем новый вызов Get Post with

[01:07:47] authors выполняем этот Script и мы видим

[01:07:50] вот пожалуйста вот Post ID 1 User ID 1

[01:07:54] Post ID 2 id1 Ну и так далее мы

[01:07:57] запросили все посты и тут не видно

[01:07:59] пользователя Эс потому что у Эс нет

[01:08:00] постов тут был выполнен один запрос мы

[01:08:03] запросили и посты и юзеров и так как

[01:08:05] связь у нас к одному то это вполне

[01:08:07] нормальный вариант когда мы делаем одним

[01:08:08] запросом запрос на и ту сущность которая

[01:08:12] нам нужна и на связанную сущность так

[01:08:13] как связка именно к одному если мы

[01:08:16] попробуем сделать этот SQL запрос тут то

[01:08:18] мы увидим вот каждый пост и вот у нас

[01:08:20] пользователи и да пользователи запросили

[01:08:22] повторно но нас это в данном случае

[01:08:24] устраивает И теперь давай дайте

[01:08:25] посмотрим ещё на загрузку разных

[01:08:27] связанных сущностей потому что в примере

[01:08:29] с Get users with posts мы можем сделать

[01:08:32] не только запрос постов но ещё и

[01:08:34] профилей я сделаю отдельный пример чтобы

[01:08:37] просто тот остался в истории Get users

[01:08:39] with posts and profiles и тут мы Запроси

[01:08:42] юзеров и с профилем и с постами И для

[01:08:45] этого я сделаю Joint Load на User

[01:08:47] Profile Потому что потому что нам нужно

[01:08:49] будет на каждого юзера потянуть профиль

[01:08:50] и на каждого юзера нужно будет потянуть

[01:08:52] ещё и посты и мы тут сделаем запрос на

[01:08:56] User Session scalers и потом их выведем

[01:08:58] Давайте посмотрим что у нас тут будет

[01:09:00] только выводим юзера потом мы выводим

[01:09:02] ещё и профиль юзера User Profile

[01:09:05] firstname выведем просто его имя и

[01:09:09] Давайте вызовем эту функцию я добавлю

[01:09:11] новый вызов и смотрим Что у нас тут

[01:09:14] получится мы видим что произошла ошибка

[01:09:16] на Type attribute First name потому что

[01:09:18] мы не всем создавали профиль поэтому

[01:09:20] давайте мы сделаем Такой формат записи

[01:09:23] мы выводим профиль и если профиль есть

[01:09:26] то его First name это такой однострочный

[01:09:28] когда мы проверяем что если профиль не

[01:09:30] пустой то вывез его свойства если он

[01:09:31] пустой то мы там просто ничего не

[01:09:33] выведем выполним заново и вот у нас есть

[01:09:36] р Эс у неё нет профиля поэтому тут NAN у

[01:09:39] юзера Сэм будет Сэм Ну и юзера Джон

[01:09:42] будет Джон Как вы видите Мы в одном

[01:09:44] запросе вытащили и профиль и посты и мы

[01:09:47] можем посмотреть на эти запросы и

[01:09:48] увидеть что от предыдущих они не сильно

[01:09:50] отличаются Я здесь выведу всё что у нас

[01:09:53] есть мы запрашиваем посты после того как

[01:09:56] мы вытащили пользователей давайте

[01:09:57] сделаем форматирование и выведем это

[01:10:00] красиво у нас будут айди ники здесь

[01:10:02] просто в в виде перечисления и мы

[01:10:05] запрашиваем пользователей и мы

[01:10:07] запрашиваем их профили в одном запросе

[01:10:10] вот мы запрашиваем каждого пользователя

[01:10:11] со своим профилем и мы запрашиваем посты

[01:10:13] для тех пользователей которых мы

[01:10:15] вытащили Ну и Давайте посмотрим на

[01:10:17] последний пример Мы ещё не делали

[01:10:19] фильтрацию Но это можно будет сделать

[01:10:21] отдельно сделаем запрос профиля с него

[01:10:23] потянем пользователя а с польз потянем

[01:10:26] посты это уже будет вложенные джоны и мы

[01:10:29] посмотрим как это вообще делается для

[01:10:31] этого я объявлю новую функцию Dev Get

[01:10:34] profiles with users and users with po и

[01:10:38] сюда мы получаем сессию Session Session

[01:10:41] и сделаем й я сразу открою здесь скобки

[01:10:43] потому что будет длинный запрос Select

[01:10:44] мы запрашиваем профили указываем Select

[01:10:47] прой или можно было наоборот да

[01:10:49] запросить посты с юзера и с профилями

[01:10:52] пользователей но тут неважно это будет

[01:10:53] работать в обе стороны делаем Order byy

[01:10:56] Profile по ID и так как у нас не у всех

[01:10:59] есть профили то мы Запроси получается не

[01:11:01] всех пользователей но зато мы увидим что

[01:11:04] у нас есть именно со стороны профиля и

[01:11:06] добавляем здесь options у нас будет

[01:11:09] точка options мы

[01:11:11] загружаем профиль и с него мы грузим

[01:11:14] юзера но как нам Получить этого юзера мы

[01:11:18] делаем через Joint lad Ведь мы загружаем

[01:11:20] к одному а дальше нам нужны посты этого

[01:11:22] пользователя но нам нужны посты

[01:11:23] пользователя а не посты профиля поэтому

[01:11:25] мы делаем точка И загружаем уже при

[01:11:28] помощи Select

[01:11:30] inad

[01:11:32] USPS потому что мы загрузили с профиля

[01:11:35] пользователя а с пользователя нужно уже

[01:11:37] взять посты вот и всё всё остальное у

[01:11:38] нас будет практически Так же как и до

[01:11:40] этого получаем profiles можно сделать

[01:11:43] равно AV Session SC и передать сюда

[01:11:46] statement и пойти в результате по

[01:11:49] профилю in profiles и мы выведем профиль

[01:11:53] для этого сделаем Profile firstname

[01:11:57] потом выведем Profile то User и выведем

[01:12:01] посты этого пользователя давайте сделаем

[01:12:02] Просто отдельный Print Profile User po

[01:12:06] вот и всё Мы увидим тут профиль с

[01:12:09] пользователем и с его постами сделаем

[01:12:11] новый запрос через эту функцию и я

[01:12:14] сделаю здесь новый вызов выполним этот

[01:12:17] код и мы видим вот пожалуйста

[01:12:19] пользователь joh сам User его имя в

[01:12:21] профиле и список его постов пользователи

[01:12:24] SM его р и список его постов Так мы

[01:12:28] сделали запросы насквозь с профиля на

[01:12:32] юзера с юзера на посты и дальше можем

[01:12:34] добавлять фильтрацию например Where и

[01:12:37] сказать нам нужны только те профили где

[01:12:38] у юзера урней равен такому-то Ну

[01:12:41] например Джон и соответственно мы

[01:12:42] вытащим только тех у кого пользователь

[01:12:45] Джон вот мы делаем новый запрос и нам

[01:12:47] кстати вернулся и Джон и Сэм всё Почему

[01:12:49] Потому что Алхимия не поняла где нам

[01:12:51] нужно сделать эту фильтрацию давайте

[01:12:53] сделаем более явную фильтрацию для этого

[01:12:55] я добавлю точка Join и скажу мы

[01:12:58] присоединяем юзера как мы его

[01:12:59] присоединяем мы его присоединяем через

[01:13:01] Профиль то User и тогда мы сможем уже

[01:13:04] фильтровать по этому юзеру потому что

[01:13:05] вот этот Joint Load он для подгрузки

[01:13:07] данных а вот этот Join он для фильтрации

[01:13:10] Давайте посмотрим ещё раз и в этот раз

[01:13:12] ошибки не было и мы вытащили только Джон

[01:13:13] Вот так мы можем добавлять фильтрацию

[01:13:15] Что произошло мы когда запрашивали

[01:13:17] пользователей с профилями мы

[01:13:19] отфильтровали по John и потом когда мы

[01:13:21] запрашивали все посты мы фильтровали

[01:13:23] только по найденным пользователям вот мы

[01:13:25] запрашивали по пользователю номер один

[01:13:27] которого мы вытащили предыдущим фильтром

[01:13:28] у меня сел основной телефон на который я

[01:13:30] записывал сейчас записываю на второй

[01:13:32] Давайте подведём итоги уже а то

[01:13:34] получилось довольно объёмное видео мы с

[01:13:35] вами посмотрели на то как мы можем

[01:13:37] создавать модели посмотрели на связи

[01:13:39] между этими моделями например в тот же

[01:13:41] профиль мы подгружать данные при помощи

[01:13:43] User relation mixin и в нём мы при

[01:13:46] помощи Class attributes закидываем

[01:13:47] дополнительные параметры это вычисляемые

[01:13:50] на ходу свойства поэтому для одного

[01:13:51] класса Unique и nullable могут быть True

[01:13:53] для другого fse и мы это всё можем

[01:13:55] указывать на классе для которого мы

[01:13:57] добавляем эту связь например профиль

[01:13:59] использует User relation mixin а также

[01:14:02] пост использует тоже User relation mixin

[01:14:04] мы здесь не указываем прямую связь на

[01:14:06] пользователя прямо на классе потому что

[01:14:08] мы можем это всё сделать на отдельном

[01:14:10] классе что нам позволяет оо и спасибо

[01:14:12] orm которые используют как раз таки

[01:14:14] классы для работы с базой данных мы

[01:14:16] посмотрели подробно на то как работать с

[01:14:18] этими объектами посмотрели на связи на

[01:14:21] то как мы их создаём И как мы

[01:14:22] запрашиваем все эти данные ещё

[01:14:24] посмотрели на новый формат запроса

[01:14:25] данных без промежуточного result мы

[01:14:28] можем сделать просто ait Session scaler

[01:14:30] для получения одного элемента или None

[01:14:32] или ait Session scalers для получения

[01:14:35] коллекции из элементов важно понимать

[01:14:37] что мы по этой коллекции если проходим

[01:14:39] то если нам нужно повторно будет

[01:14:40] выбирать пользователей то лучше сделать

[01:14:42] из этого список но тут если мы делаем

[01:14:44] один цикл то всё нормально ещё мы

[01:14:46] посмотрели Как делать Joint Load И зачем

[01:14:48] он вообще нужен увидели что при помощи

[01:14:50] Joint Load мы делаем в том же запросе

[01:14:53] подгрузка дополнительных данных и ещё мы

[01:14:55] с вами посмотрели на подгрузка через

[01:14:57] Select and Load Joint Load используют

[01:14:59] для подгрузки данных к одному хотя он

[01:15:01] может также подгружать и ко многим но

[01:15:03] если мы делаем его для ко многим то

[01:15:05] нужно будет ещё использовать Unique А

[01:15:07] если мы хотим подгружать ко многим и не

[01:15:08] использовать Unique то лучше

[01:15:10] использовать Select inad плюс Select and

[01:15:12] Load делает отдельный запрос и Да может

[01:15:13] показаться что отдельный запрос - Это

[01:15:15] какое-то лишнее действие Зачем нам

[01:15:16] лишний запрос но зато мы избавляемся от

[01:15:18] дублирования в этом запросе и поэтому

[01:15:21] Select and Load чаще используют для

[01:15:22] подгрузки ко многим а Joint load

[01:15:24] использу для подгрузки к одному мы с

[01:15:26] вами увидели что в одном запросе мы

[01:15:28] можем подтягивать и к одному через Joint

[01:15:30] Load и ко многим через Select and Load

[01:15:33] всё это мы перечисляем через запятую в

[01:15:34] options Но если нам нужно подгрузить

[01:15:36] несколько связей насквозь то Вот пример

[01:15:38] с профилем с профиля мы грузим юзеров с

[01:15:41] юзеров мы грузим посты и получается что

[01:15:44] мы делаем несколько уровней вложенности

[01:15:46] и мы можем с Joint Load сделать Select

[01:15:48] and Load спокойно Потому что тут мы

[01:15:49] подгрузить юзеров и к юзеров нам уже

[01:15:52] нужно подтягивать ко многим эти посты но

[01:15:55] если нам нужно делать фильтрацию как мы

[01:15:56] тут сделали по юзеру с юзернейм John то

[01:15:59] мы должны указывать Join вот этот Join

[01:16:02] уже нужен для работы с данными которые

[01:16:04] мы используем для фильтрации мы

[01:16:06] фильтруем юзера и чтобы по этому юзеру

[01:16:08] фильтровать нужно указать Join потому

[01:16:10] что вот эта подгрузка в options нужна

[01:16:12] только для orm чтобы подтянуть данные и

[01:16:14] отобразить их в моделях а для работы с

[01:16:17] этими данными для фильтрации нужно

[01:16:18] использовать отдельный Join Давайте

[01:16:20] посмотрим как это выглядит в запросе вот

[01:16:22] тут мы видим Select и получаем два

[01:16:25] селекта один на профиле с пользователями

[01:16:28] и один на посты Мы видим что мы

[01:16:29] запрашиваем Джона и по такому-то ID но

[01:16:32] Давайте посмотрим на это более подробно

[01:16:34] Я уже сюда Это скопировал и вот у нас

[01:16:36] есть профили и на эти профили мы Джони

[01:16:40] юзера мы делаем Left Joint чтобы

[01:16:42] потянуть профиль даже если там нет

[01:16:43] пользователей ведь база данных не знает

[01:16:45] что у нас нет такой возможности не

[01:16:46] сделать профиль без пользователя и также

[01:16:48] мы делаем ещё один Join users и вот этот

[01:16:51] users используется для фильтрации Таким

[01:16:53] образом мы получаем только юзера Джон мы

[01:16:56] его отфильтровали по юзернейм Джон и мы

[01:16:58] получаем всю информацию по профилю

[01:17:01] только для Джона и потом вытащив Джона с

[01:17:04] id1 мы уже можем запросить посты и все

[01:17:07] посты Мы запрашиваем тоже для id1 и мы

[01:17:10] увидим все посты которые написал Джон

[01:17:12] Так мы с вами подробно посмотрели на

[01:17:14] запросы в базу данных Да мы сделали мало

[01:17:16] фильтрации Но это всё Мы тоже Ещё успеем

[01:17:18] Мы работали сегодня внутри Fast ipi

[01:17:20] приложения но по сути всё время было

[01:17:22] посвящено SQL lch как вам вообще это

[01:17:24] информация Было ли Понятно может быть

[01:17:26] что-то непонятно я вот так долго

[01:17:28] рассказывал что у меня одна камера села

[01:17:30] Но если вам понравилось пожалуйста

[01:17:31] Напишите об этом в комментарии или хотя

[01:17:33] бы поставьте какую-нибудь реакцию чтобы

[01:17:34] дать мне понять Как вам это видео и мы

[01:17:37] ещё кстати сегодня познакомились с ОМК

[01:17:40] очень крутой инструмент для работы с

[01:17:41] миграция узнали как эти миграции

[01:17:43] генерировать Как сделать автогенерация

[01:17:44] миграций мы модифицировать npy для того

[01:17:47] чтобы здесь указать какие-то настройки и

[01:17:49] в настройках Мы ещё сделали вложенные

[01:17:52] значения и очень классно что мы можем

[01:17:54] делать вложенные значения ведь это

[01:17:55] отдель name Space а name Space - это

[01:17:57] круто И если вам это всё было полезно

[01:17:59] или может быть что-то было полезно

[01:18:01] Напишите об этом пожалуйста в прошлый

[01:18:02] раз вы меня очень сильно порадовали мы

[01:18:04] за полтора дня набрали 50 лайков которые

[01:18:07] я думал будем собирать 2 недели потому

[01:18:08] что на предыдущем видео Мы собирали 2

[01:18:10] недели 40 лайков Поэтому если поддержите

[01:18:11] будет очень классно мне очень приятно и

[01:18:13] Давайте 70 лайков вот так чтобы Я

[01:18:17] выпустил новый ролик пишите что вам

[01:18:18] интересно у меня ещё есть идеи что тут

[01:18:20] рассказывать и мы наконец-то именно с

[01:18:21] Fast API поработаем А то мы сегодня

[01:18:23] всё-таки больше с базой данных работаем

[01:18:25] поэтому пишите Я на все комментарии

[01:18:26] отвечаю Вот можете посмотреть и под этим

[01:18:27] роликом и предыдущим все комментарии с

[01:18:29] ответами поэтому задавайте свои вопросы

[01:18:31] пишите с удовольствием вам буду отвечать

[01:18:33] а на этом на сегодня всё с вами был

[01:18:35] Сурен и до новых встреч пока
