💡 Попробуй онлайн-тренажёр для подготовки к техническому собеседованию: clck.ru/3B5gwP 💡 Забирай роадмап изучения самого востребованного фреймворка на Python - FastAPI здесь: t.me/ArtemShumeikoBot
Здравствуйте, а вы можете отдельно сделать видео по созданию кастомного пользователя. Вы говорили в этом видео, что изначально была именно такая идея. Только со всеми мелочами и плюшками. Это очень важно. Если не Вам будет не очень сложно)
Здравствуйте! Начал изучать FastAPI по вашему курсу, столкнулся с проблемой: после изменения названия таблиц в модели БД и создания новой ревизии, не могу обновиться до этой ревизии т.к название таблицы не изменяется, а просто создается новая: sqlalchemy.exc.InternalError: удалить объект таблица roles нельзя, так как от него зависят другие объекты.
Я занимаюсь разработкой на python уже почти 5 лет и прекрасно понимаю всё, что ты показываешь в своих видео, но твоя подача всё равно заставляет смотреть до конца. Очень приятная картинка, превью и подача, просто кайф. Желаю тебе успехов и побольше подписчиков для такого годного контента!
Спасибо огромное за такое видео! Всё четко, по полочкам, ничего лишнего, уместные комментарии с объяснениями. Приятно вас слушать и смотреть - обстановка дома приятная и сами вы симпатичный. Надеюсь увидеть ещё больше ваших видео в будущем!
Спасибо за курс! Подача супер крутая, лучше туториала на русском я не встречал! Артем, ты молодец! Отличная работа, я восхищаюсь и параллельно продолжаю курс!
Артем, у вас отличная подача и умение хорошо объяснять сложный материал (что на самом деле, очень редкое качество). Большое вам спасибо за ваши уроки и удачи в работе и развитии канала!
Идентификация - определение пользователя. Аутентификация - проверка принадлежности идентификатора тому пользователю, который этот идентификатор предъявляет. Авторизация - проверка прав пользователя на использование конкретного ресурса.
Артём, ОГРОМНОЕ СПАСИБО ЗА ЭТО ВИДЕО! Ты создаешь очень годный контент и рассказываешь о том, что сейчас не найти на TH-cam. Расскажи пожалуйста про Fastapi-admin или Starlette-admin или про любую админку которую использую с Fastapi. СПАСИБО!
При создании хендлера для логина обычно рекомендуется использовать метод POST вместо метода GET. Это связано с тем, что метод GET передает данные формы через URL-адрес, который может быть легко просмотрен и перехвачен злоумышленником. Если пользователь вводит свои учетные данные в форму для входа, используя метод GET, то эти данные будут открыто передаваться в URL-адресе. Это может стать проблемой для безопасности, так как злоумышленник может перехватить эти данные с помощью простого сниффинга или посредника. С другой стороны, при использовании метода POST данные формы передаются в теле запроса, а не в URL-адресе. Это обеспечивает большую безопасность, так как данные не будут открыто передаваться и будут скрыты от посторонних глаз. Поэтому, чтобы обеспечить безопасность пользователей, рекомендуется использовать метод POST для передачи учетных данных при логине.
Автор красавчик так-то. Очень хорошо доносишь материал, но правда на сегодняшний день FastAPI Users изменили тот код который мы сначала скопировали не думая, а потом задумались, по этому в итоге вообще ничего не понятно касательно класса, приходится переписывать как было у автора. Теперь там не Column а Mapped...
Артем, большое спасибо за Ваши уроки. С удовольствием постигаю FastAPI. ) Надеюсь , с Вашей помощью , в ближайшее время создать какое-то всое приложение ).
6 лет на джанге сижу, хочу на фастапи перебираться. Вижу только плюсы пока. Из минусов наверно то, что нет админки встроенной и то, что от orm нужно отучаться и привыкать к алхимии. Буду своё приложение переписывать на фастапи. Короче, спасибо Артём. Лайкос.
а в фастапи есть что-то похожее на сессии фласка? чтобы пользователь не регался но при этом ммел какой-то идентификатор по которому мы можем его узнавать и хранить какуюто историютдействий, типа временой корзины или понравившийся товар
Сначала думал что автор ошибся с синтаксисом моделей БД алхимии. Но нет. Действительно, в последней версии алхимии поля таблицы описываются через Mapped а не Column И последняя версия FastApi-Users так же в классе через Mapped описывает. Имейте это в виду, и по чаще смотрите доки )
Отличный формат и подача! Респект автору огромный! однако хотелось бы чуть больше всяких подробностей насчет секьюрности, пусть где и что почитать - и то конкретика)) а то легкий сумбур в голове у меня как у новичка...
Для меня как новичка в программировании, прикольно что простым языком без разных замудростей)) особенно полезны вставки: "это всего лишь ........." тк за громкими названиями как правило прячутся простейшие вещи.
Очень интересно! Не смотрел есть ли у тебя на канале более подробно об регистрации, аутентификации и авторизации видео. Какие есть подходы, лучшие практики и т.д. Хотелось бы увидеть такое.
Переписал код полностью, запустил, вылезает ошибка "valueerror: invalid literal for int() with base 10: 'None'. Уже достаточно продолжительное время пытаюсь найти ошибку, не подскажешь, что делать?
Скажите а в чем смысл определять юзера два раза? Один раз в models.py через metadata а второй раз в database.py как бы кастомизируя класс User из FastAPI-Users ?
я бы не копипастил поля из базовых классов библиотеки в дочерние классы проекта, ведь тем самым вы сами же нарушаете своё правило с повторяемостью кода. А большая проблема повторяемости кода - отследить изменения во всех его частях. Если библиотека изменится, то очень легко упустить изменения и нарваться на непредвиденные ошибки. Дочерние классы в данном случае должны расширять функционал, а не подменять его.
Артем, спасибо тебе за урок. Но объясни пожалуйста, для чего ты делаешь две одинаковые модельки юзера? Можно ведь создать одну и использовать только ее, не плодя одинаковый код. Если я в чем-то не прав и чего-то не понимаю - ответьте :)
на счет того что при создании юзера поле role_id было user, а нельзя было бы в модели указать Column('role_id', Integer, ForeignKey(role.c.id), default=1)? Вместо того что бы ковырять библиотеку?
default сработает если при добавлении в базу значение не указанл, а так как в схеме UserCreate клиент может указать значение, то оно попадет в базу. Лучший вариант - исключить поля is_superuser, is_active, is_verified и role_id и использовать аргумент default для базы данных или переназначать эти переменные в обработчике эндпоинта
Артём, вас действительно интересно смотреть но многое в этом видео сделано "ну просто так надо", да с объясненими, но очень сложно если хочется понять всю структуру работы программы, а не на лету, в сумме очень сложно UPD: Читайте доки
подскажите пожалуйста 40:08 почему в поле username мы вбиваем почту? почему fastapi users по дефолту использует почту в качестве логина для входа? можно ли это как то исправить чтобы вместо почты пользователь вбивал свой username?
@@checkanon6908 да я почитал документацию и там разработчики написали что они решили использовать почту как username так как почта это всегда уникальное значение и поэтому точно не будет возникать никаких конфликтов. К сожалению я не понял каким образом можно использовать в качестве username настоящий username. Вроде как нужно что то изменить в коде самой библиотеки но из за этого начинают везде возникать ошибки и конфликты. По этой причине проще просто на фронтенде использовать форму email а в бд записывать данные в username. Звучит костыльно? Но как сделать по другому я не знаю.
Раньше на продакшене я пользовался кастомной аутентификацией, для этого курса буду использовать fastapi-users (надеюсь довести проект до прода). Не вижу причин не использовать данную библиотеку, тем более, что ее можно удобно настроить под себя ввиду хорошо задокументированного кода: удалить дефолтные роли active/verified/superuser и добавить свои (или через такие же переменные, или, как делаю я, через таблицу с ролями). Конечно, перед выкаткой в прод нужно почитать исходники библиотеки для поиска возможных уязвимостей.
c 10й попытки заработало и у меня. Все время после регистраици возвращало ошибку сервера крутил все что можно и так и этак пока в конце не снес всю базу и руками не прописал на чистом sql создание таблиц. Видимо рано мне еще алембик или что-то не так...
Артем, привет! Классная серия уроков, спасибо! Но некоторые вещи, честно говоря, расстраивают. Например, пароль ХЕШируется, а не шифруется. ХЕШ - не обратимая функция, никаким образом пароли не декодируются. На бэке сравниваются их хеши. То есть не пароль декодируется, а в БД хранится хеш и поступающий пароль тоже хешируется. И вот эти хеши сравниваются. И второе, у метода POST нет никакого другого "уровня защиты", он отличается от GET только тем, что пользователь не видит эти переменные в адресной строке и всё.
16:51 - нехорошо хардкодить id строки в БД. В БД совсем не обязательно роль "обычный пользователь" будет под id=1. Несколько раз инициируешь БД и сносишь - id всё время меняются. К ним нельзя привязываться. По-хорошему тут надо сделать запрос в БД с поиском id для нужной нам роли. И присвоить этот найденный id.
Всем привет! Оч нравится курс, все вроде как доходчиво, но не понимаю я одной штуки. Почему мы создаем модель юзера повторно? Или мы в принципе можем удалить модель, которую мы создали ранее и использовать ту, что в фастапи-юзерс?
Спасибо за видос. Странное решение позволить пользователям вводить поля типа is_admin. Вместо того чтобы убрать их с реквеста, вы сломали логику сохранения. Надеюсь исправите в будущем.
зачем на сущности и таблицы? разве это не усложнит разработку, когда их станет больше десяти? При каждой миграции я должен буду позаботиться обо всех изменениях?
Артем, насчет пересоздания миграции, вы просто удалили миграции и все у вас заработало. У меня получилось только и с удалением таблиц в БД, иначе требовало правило on_delete="CASCAD"
Большое спасибо за видео,очень полезно.Один момент: Возможно ли в Swagger doc где эндпоинт login поменять название поля с "username" на "email" Потому что,вводит в заблуждение разработчика,там по факту поле принимает email,но название username Спасибо заранее за ответ
Артём, хорошее дело делаешь! Молодец, продолжай! Вопрос по ходу дела. Я понимаю что Python язык не строгой типизации, но все же... Если заглянуть в класс SQLAlchemyBaseUserTable то можем там увидеть следующий странный код: hashed_password: str = Column(String(length=1024), nullable=False) is_active: bool = Column(Boolean, default=True, nullable=False) is_superuser: bool = Column(Boolean, default=False, nullable=False) is_verified: bool = Column(Boolean, default=False, nullable=False) Мы говорим что переменная hashed_password имеют тип str, is_active это bool и т.д. и тут же берем и просто назначаем объект с типом "Column" Или, мы говорим что у нас id имеет тип int и тут же тоже пихаем в него "Column": class User(SQLAlchemyBaseUserTable[int], Base): id = Column(Integer, primary_key=True) Можете объяснить, для полного понимания, в чем прикол и как это работает? Спасибо
Привет) Немного занудства сначала - питон имеет динамическую сильную типизацию. Динамическая - типы вычисляются в момент выполнения. Сильная - нельзя смешивать разные типы в выражении (нельзя вычесть строку из инта, привет, js) Надо понять два момента: 1. тип через двоеточие после имени переменной: hashed_password: str = Column(String(length=1024), nullable=False) Это не объявление типа, это подсказка типа. Если будете искать больше информации, то ищите type hinting. Подсказка не накладывает никаких ограничений, по факту в переменной может лежать любой тип. Это именно что подсказка для разработчика (подсказки синтаксические будут от IDE итд) 2. id имеет тип int и тут же тоже пихаем в него "Column" С чего бы начать. Если вкратце - это ORM. Задача ORM - абстрагировать разработчика от работы с БД. Мы используем один и тот же класс для определения таблицы в базе и для работы с объектами в нашей программе. То есть Column нужно для того чтобы библиотека делала корректные запросы при обращении к БД. Когда же мы будем работать с экземпляром класса User в коде, в поле id будет лежать int. Для понимания, обратите внимание, как в github.com/artemonsh/fastapi_course/blob/main/Lesson_05/main.py#L43 мы берем поле username экземпляра класса User. И хоть в классе бы объявили это поле как класс Column github.com/artemonsh/fastapi_course/blob/main/Lesson_05/auth/database.py#L21, при обращении к полю username мы получим строку (потому что в базе в колонке username лежит строковое значение).
Артем, подскажи как правильней сделать. Есть логин юзера в приложении через JWT и этому юзеру нужно предоставить дополнительно безлимитный по вреимени токен для некоторых операций с API. Как лучше хранить и проверять токен? Хранить в базе и кеше, чтоб каждый раз базу не дергать? Запросов с этим доп токеном может быть много.
Мне очень кажется странным что в реализации этой библиотеки нет модели с refresh_token , хотя копаясь в недрах самой библиотеки я нашел в классе BaseUserManager поле с рефреш токеном. То есть автор полагал что это поле нужное, но в документации эта тема совсем не тронута. И у вас вижу не реализован метод refresh и вы работаете с одним токеном. Может есть объективные причины на это, могли бы сказать почему ?
К моему комментарию выше: Фронтенд разработчик на работе погрузил меня в муки сомнений. Он уверенно утверждал что реализация в fastapi-users неправильная! Должно быть два токена refresh & access. Я не первый раз использую fastapi users, но после его слов у меня тревога и ворт в пастели )) Думаю надо написать свою аутентификацию а за одно понять все на молекулярном уровне. Написал ! Понял😊 FastAPI users отличная библиотека!
Идея с ролью для пользователя по умолчанию ясна, но мне кажется прописывать это в виде "1" в коде не очень читаемое и поддерживаемое решение, мало ли как потом базу данных поменяют, или кто будет этот код читать...
Артем, можно ли реализовать авторизацию и аутентификацию пользователя c помощью FastAPI Users, но без логина и пароля, а с ключом? Просто вместо логина и пароля передавать сгенерированный ключ, например, uuid.
@@artemshumeiko поищу, а по никак не могу связать формы регистрации и авторизации на фронте с беком. Если есть возможность - дайте ссылку на видео . спасибо
Артём, спасибо за урок. Сейчас у вас в проекте две ОРМ модели из разных библиотек (psycopg2, asyncpg)? Поясните пожалуйста зачем? Это ведь вылнуждает поддерживать и сихронизировать их вручную
Спасибо за комментарий! Действительно, psycopg2 устанавливался в уроке по Базам Данных, но по ходу развития курса стало ясно, что нет необходимости его использовать. В дальнейшем будет использоваться только asyncpg. В следующем уроке я еще обращусь к теме БД и, в частности, SQLAlchemy и особенностей подключения и работы с ней
@@artemshumeiko По 4 уроку переписал с использованием asyncpg. Все же тоже самое получается? Изменения по сути только в URL - "postgresql+asyncpg" и команде alembic init -t async migrations? Или еще какие-то есть нюансы?
@@artemshumeiko Я может тогда не так понял. Но разве не так должно быть: from sqlalchemy.ext.asyncio import create_async_engine engine = create_async_engine("postgresql+asyncpg://user:pass@hostname/dbname") (The asyncpg dialect is SQLAlchemy’s first Python asyncio dialect. Using a special asyncio mediation layer, the asyncpg dialect is usable as the backend for the SQLAlchemy asyncio extension package. This dialect should normally be used only with the create_async_engine() engine creation function:) а наоборот перевод в синхронку: # for testing purposes only; do not use in production! engine = create_engine("postgresql+asyncpg://user:pass@hostname/dbname?async_fallback=true") (The dialect can also be run as a “synchronous” dialect within the create_engine() function, which will pass “await” calls into an ad-hoc event loop. This mode of operation is of limited use and is for special testing scenarios only. The mode can be enabled by adding the SQLAlchemy-specific flag async_fallback to the URL in conjunction with create_engine():)
@@ЕвгенийЗемляной-д6ф имелось в виду добавить async_fallback к переменной sqlalchemy.url в файле alembic.ini. Адрес БД в функции create_async_engine менять не нужно
Артём, спасибо за полезную информацию! На 11 минуте, а именно в 10:20 ты говоришь "скопируем код" и у тебя в браузере есть значок скопировать код, а у меня ни в Firefox, ни в Chrome нет этой кнопки. Это какой-то плагин к браузеру?
А нельзя как-то скрыть параметры булевые при регистрации? Просто в модели дефолтные прописать и все, чтобы при инсерте не ругалась БД? Просто зачем выносить из класса отдельную функцию и переписывать ее, ощущение просто, что это костыль дикий прям и можно красивше)
💡 Попробуй онлайн-тренажёр для подготовки к техническому собеседованию: clck.ru/3B5gwP 💡
Забирай роадмап изучения самого востребованного фреймворка на Python - FastAPI здесь: t.me/ArtemShumeikoBot
Здравствуйте, а вы можете отдельно сделать видео по созданию кастомного пользователя. Вы говорили в этом видео, что изначально была именно такая идея. Только со всеми мелочами и плюшками. Это очень важно. Если не Вам будет не очень сложно)
Здравствуйте! Начал изучать FastAPI по вашему курсу, столкнулся с проблемой: после изменения названия таблиц в модели БД и создания новой ревизии, не могу обновиться до этой ревизии т.к название таблицы не изменяется, а просто создается новая: sqlalchemy.exc.InternalError: удалить объект таблица roles нельзя, так как от него зависят другие объекты.
@@__-fx5gd достаточно поменять в миграции код на ALTER TABLE table_name RENAME TO new_table_name, чтобы не удалялась и создавалась таблица
Я занимаюсь разработкой на python уже почти 5 лет и прекрасно понимаю всё, что ты показываешь в своих видео, но твоя подача всё равно заставляет смотреть до конца. Очень приятная картинка, превью и подача, просто кайф. Желаю тебе успехов и побольше подписчиков для такого годного контента!
зачем тогда смотреть когда знаешь?
@@fresh_wind87 а как понять, что ты это все знаешь, не посмотрев?
@@Gregory-vc2vs когда знаешь то знаешь что знаешь..хых
Прикол в том что кто понимает не очень смотреть не так уж легко
Спасибо огромное за такое видео! Всё четко, по полочкам, ничего лишнего, уместные комментарии с объяснениями. Приятно вас слушать и смотреть - обстановка дома приятная и сами вы симпатичный. Надеюсь увидеть ещё больше ваших видео в будущем!
Потратил пол дня на эту библиотеку, а тут за 40 мин. все по полочкам) Однозначно подписка👍
Спасибо за курс! Подача супер крутая, лучше туториала на русском я не встречал! Артем, ты молодец! Отличная работа, я восхищаюсь и параллельно продолжаю курс!
Артем, у вас отличная подача и умение хорошо объяснять сложный материал (что на самом деле, очень редкое качество). Большое вам спасибо за ваши уроки и удачи в работе и развитии канала!
Ура, новое видео! Классный новогодний фон😍
Идентификация - определение пользователя. Аутентификация - проверка принадлежности идентификатора тому пользователю, который этот идентификатор предъявляет. Авторизация - проверка прав пользователя на использование конкретного ресурса.
Артём, ОГРОМНОЕ СПАСИБО ЗА ЭТО ВИДЕО! Ты создаешь очень годный контент и рассказываешь о том, что сейчас не найти на TH-cam. Расскажи пожалуйста про Fastapi-admin или Starlette-admin или про любую админку которую использую с Fastapi. СПАСИБО!
Спасибо за комментарий! Наверное, через несколько видео будет материал про админку
@@artemshumeiko круто! я по ключевому слову fastapi admin попал на канал
При создании хендлера для логина обычно рекомендуется использовать метод POST вместо метода GET. Это связано с тем, что метод GET передает данные формы через URL-адрес, который может быть легко просмотрен и перехвачен злоумышленником.
Если пользователь вводит свои учетные данные в форму для входа, используя метод GET, то эти данные будут открыто передаваться в URL-адресе. Это может стать проблемой для безопасности, так как злоумышленник может перехватить эти данные с помощью простого сниффинга или посредника.
С другой стороны, при использовании метода POST данные формы передаются в теле запроса, а не в URL-адресе. Это обеспечивает большую безопасность, так как данные не будут открыто передаваться и будут скрыты от посторонних глаз.
Поэтому, чтобы обеспечить безопасность пользователей, рекомендуется использовать метод POST для передачи учетных данных при логине.
GET запрос зашифрован, кроме самого домена и порта
@@ЫГы-р2д ,
Шифрование не зависит от типа запроса это зависит от http или https
Ооо наконец, ждал этого именно прр юзерс!
Спасибо большое. Наверно самое понятное объяснение из всех видео, которые я пересмотрел
Невероятная подача материала. Спасибо большое!
Спасибо ;)
Честно признаться, я давно не был в таком щенячьем восторге от курсов. Помимо самого FastAPI он мне уже покрыл кучу пробелов моих
Подскажите пожалуйста, почему при входе требуется ввести username и password, но вместо username мы вводим email?
Cпасибо большое! этот урок очень выручил.
Отличный канал! Как раз решил попробовать FastAPI!
Успешного изучения!
Благодарю за урок, много полезной информации!
Спасибо большое за видео, все очень понятно, интересно и без воды!
На работе как раз FastAPI, но для пет-проекта в этой же компании не хватает знаний. Спасибо за твой урок, очень ценно! вернусь ещё на канал)
Спасибо за отзыв!
Автор красавчик так-то. Очень хорошо доносишь материал, но правда на сегодняшний день FastAPI Users изменили тот код который мы сначала скопировали не думая, а потом задумались, по этому в итоге вообще ничего не понятно касательно класса, приходится переписывать как было у автора. Теперь там не Column а Mapped...
Артем, большое спасибо за Ваши уроки. С удовольствием постигаю FastAPI. ) Надеюсь , с Вашей помощью , в ближайшее время создать какое-то всое приложение ).
Спасибо! Успехов вам!
Спасибо! Очень понятно, преподавательский талант вас не обошел стороной-:)))
спасибо :)
6 лет на джанге сижу, хочу на фастапи перебираться. Вижу только плюсы пока. Из минусов наверно то, что нет админки встроенной и то, что от orm нужно отучаться и привыкать к алхимии. Буду своё приложение переписывать на фастапи. Короче, спасибо Артём. Лайкос.
удачи вам!
Спасибо за ролики, хороший старт для изучения FastAPI
Большое спасибо за контент! В русскоязычном сегменте пока самый доступный вариант объяснения
спасибо за ваше старание. Очень полезный контент!
Курсы - логично, практично и фантастично :) СПСБ,!
Большое спасибо за ваш курс!
Спасибо за курс, очень помогает вкатиться в бэк =)
а в фастапи есть что-то похожее на сессии фласка? чтобы пользователь не регался но при этом ммел какой-то идентификатор по которому мы можем его узнавать и хранить какуюто историютдействий, типа временой корзины или понравившийся товар
кайф) давно не было видео и думал, что пропал) спасибо!
Спасибо за такой полезный урок!
Рад помочь :) Спасибо
Спасибо большое за курс, очень информативно
Спасибо тебе большое, Артём! Всё чётко разъяснил за авторизацию 😂 пожалуйста, продолжай пилить видосы дальше🥵 хотел бы увидеть интеграцию с AWS S3
После джанго так непривычно, что начал понимать тему после третьего просмотра с параллельной практикой, но материал отличный
супер! спасибо!! мне понравилось!
сердечно благодарю за уроки)
Очень крутые видео, спасибо за курс
А такой вопрос почему при аутентификации мы в поле username вводим email, а при введении зареганного username выходит ошибка?
привет! удалось найти ответ?
Огромное спасибо за урок!
Сначала думал что автор ошибся с синтаксисом моделей БД алхимии. Но нет. Действительно, в последней версии алхимии поля таблицы описываются через Mapped а не Column
И последняя версия FastApi-Users так же в классе через Mapped описывает.
Имейте это в виду, и по чаще смотрите доки )
как всегда, спасибо большое!! Все вместе с тобой проделала, все поняла ))
Мощно! Спасибо! С меня лайк и подписка!
Спасибо ;)
40:10 Мы же вход осуществляем по email, верно? А поле называется "username". А где это исправить?
Тоже очень волнует этот вопрос. Если вы уже нашли ответ, поделитесь им, пожалуйста.
удалось найти ответ?
@@checkanon6908 в моделях поменяй и сделай миграции, делов то
Отличный формат и подача! Респект автору огромный! однако хотелось бы чуть больше всяких подробностей насчет секьюрности, пусть где и что почитать - и то конкретика)) а то легкий сумбур в голове у меня как у новичка...
Для меня как новичка в программировании, прикольно что простым языком без разных замудростей)) особенно полезны вставки: "это всего лишь ........." тк за громкими названиями как правило прячутся простейшие вещи.
А что на счет refresh tokena
Очень интересно! Не смотрел есть ли у тебя на канале более подробно об регистрации, аутентификации и авторизации видео. Какие есть подходы, лучшие практики и т.д. Хотелось бы увидеть такое.
отличное видео, ждем продолжении авторизацию!
Переписал код полностью, запустил, вылезает ошибка "valueerror: invalid literal for int() with base 10: 'None'. Уже достаточно продолжительное время пытаюсь найти ошибку, не подскажешь, что делать?
Скажите а в чем смысл определять юзера два раза? Один раз в models.py через metadata а второй раз в database.py как бы кастомизируя класс User из FastAPI-Users ?
Действительно, смысла в этом нет. Это была моя ошибка. Достаточно оставить класс User с наследованием от Base
я бы не копипастил поля из базовых классов библиотеки в дочерние классы проекта, ведь тем самым вы сами же нарушаете своё правило с повторяемостью кода. А большая проблема повторяемости кода - отследить изменения во всех его частях. Если библиотека изменится, то очень легко упустить изменения и нарваться на непредвиденные ошибки. Дочерние классы в данном случае должны расширять функционал, а не подменять его.
Ты имеешь ввиду не копипастить код , а, например, пользовться методом super()?
Когда создаёшь отдельную директорию/сервис с авторизацией все волки делают ауф 😂
Не смог удержаться))
Красавчик, классный урок 👍
Видео просто огонь!!!!!
Артём, ты так и не рассказал, что делать, если истекло время жизни cookie!
Артем, а как данную авторизацию подключить к моему html файлу на бекенде с авторизацией. Есть ли у Вас такой курс?
Артем, спасибо тебе за урок. Но объясни пожалуйста, для чего ты делаешь две одинаковые модельки юзера? Можно ведь создать одну и использовать только ее, не плодя одинаковый код.
Если я в чем-то не прав и чего-то не понимаю - ответьте :)
Ошибся. Достаточно одной модели
Артём добра тебе и всех благ! Очень крутое видео!
Спасибо!
Будьте внимательны: за username в Сваггере считается электронная почта, а не тот username, который мы ввели в модель. Я долго тупил :)
на счет того что при создании юзера поле role_id было user, а нельзя было бы в модели указать Column('role_id', Integer, ForeignKey(role.c.id), default=1)? Вместо того что бы ковырять библиотеку?
default сработает если при добавлении в базу значение не указанл, а так как в схеме UserCreate клиент может указать значение, то оно попадет в базу. Лучший вариант - исключить поля is_superuser, is_active, is_verified и role_id и использовать аргумент default для базы данных или переназначать эти переменные в обработчике эндпоинта
Артём, вас действительно интересно смотреть но многое в этом видео сделано "ну просто так надо", да с объясненими, но очень сложно если хочется понять всю структуру работы программы, а не на лету, в сумме очень сложно
UPD: Читайте доки
подскажите пожалуйста
40:08 почему в поле username мы вбиваем почту?
почему fastapi users по дефолту использует почту в качестве логина для входа?
можно ли это как то исправить чтобы вместо почты пользователь вбивал свой username?
удалось найти решение?
@@checkanon6908 да я почитал документацию и там разработчики написали что они решили использовать почту как username так как почта это всегда уникальное значение и поэтому точно не будет возникать никаких конфликтов. К сожалению я не понял каким образом можно использовать в качестве username настоящий username. Вроде как нужно что то изменить в коде самой библиотеки но из за этого начинают везде возникать ошибки и конфликты. По этой причине проще просто на фронтенде использовать форму email а в бд записывать данные в username. Звучит костыльно? Но как сделать по другому я не знаю.
давай давай. продолжай в тои же духе. Больше видео
Спасибо за урок. А чем вы пользуетесь в продакшене? Разве похожей библиотекой авторизации? Или пишете кастомные доступы по ролям к данным на бекенде?
Раньше на продакшене я пользовался кастомной аутентификацией, для этого курса буду использовать fastapi-users (надеюсь довести проект до прода). Не вижу причин не использовать данную библиотеку, тем более, что ее можно удобно настроить под себя ввиду хорошо задокументированного кода: удалить дефолтные роли active/verified/superuser и добавить свои (или через такие же переменные, или, как делаю я, через таблицу с ролями).
Конечно, перед выкаткой в прод нужно почитать исходники библиотеки для поиска возможных уязвимостей.
Боооольшое спасибо за уроки.
Однако сейчас в 'fastapi_users' вместо "Column" используется "mapped_column". Но пока ничего не крякнуло =)
c 10й попытки заработало и у меня. Все время после регистраици возвращало ошибку сервера крутил все что можно и так и этак пока в конце не снес всю базу и руками не прописал на чистом sql создание таблиц. Видимо рано мне еще алембик или что-то не так...
Артем, привет! Классная серия уроков, спасибо! Но некоторые вещи, честно говоря, расстраивают. Например, пароль ХЕШируется, а не шифруется. ХЕШ - не обратимая функция, никаким образом пароли не декодируются. На бэке сравниваются их хеши. То есть не пароль декодируется, а в БД хранится хеш и поступающий пароль тоже хешируется. И вот эти хеши сравниваются. И второе, у метода POST нет никакого другого "уровня защиты", он отличается от GET только тем, что пользователь не видит эти переменные в адресной строке и всё.
спасибо за урок больше четырех
А кто-то может подсказть почему при аутентификации поле называется username, а вводить надо email?
Тоже интересно. Вы узнали ответ?
А где можно подробнее познакомится с сессиями? Не совсем понятно для чего то и зачем
16:51 - нехорошо хардкодить id строки в БД. В БД совсем не обязательно роль "обычный пользователь" будет под id=1.
Несколько раз инициируешь БД и сносишь - id всё время меняются. К ним нельзя привязываться.
По-хорошему тут надо сделать запрос в БД с поиском id для нужной нам роли. И присвоить этот найденный id.
Спасибо большое!
Спасибо большое за контент. Продолжай в том же ритме. Желаю многократного увеличения просмотров и подписчиков..
Всем привет! Оч нравится курс, все вроде как доходчиво, но не понимаю я одной штуки.
Почему мы создаем модель юзера повторно? Или мы в принципе можем удалить модель, которую мы создали ранее и использовать ту, что в фастапи-юзерс?
Все верно, можно использовать модель из fastapi-users. В уроке была допущена ошибка DRY
Желательно вообще все модели переписать с Table() на классы
Как всегда - красаучыг
хотелось бы больше видео где идёт фулстек разработка, чтобы параллельно всю работу бэкенда одевать в красивый фронтенд
запишешь подробнее про jwt мб даже с подтверждением почты очередями и чтоб с докой сходилось что то очень все туго зашло но интересно
Привет, спасибо за видео! Мб снимешь сравнение fast, rest, soap API, сходства различия и для чего используются?
Привет! Спасибо за предложение, я подумаю
Спасибо за видос. Странное решение позволить пользователям вводить поля типа is_admin. Вместо того чтобы убрать их с реквеста, вы сломали логику сохранения. Надеюсь исправите в будущем.
Согласен, плохая реализация
так тут один токен, а jwt вроде как refresh token предполагает. Где объяснения как refresh работает?)
"detail": "JWTError" в dependencies хотя токены совпадают. В чем может быть дело?
зачем на сущности и таблицы? разве это не усложнит разработку, когда их станет больше десяти? При каждой миграции я должен буду позаботиться обо всех изменениях?
Для продвижения. Но подача и правда супер
Спасибо
@@artemshumeiko скоро на ваш курс на степике запишусь. 😉
Артем, насчет пересоздания миграции, вы просто удалили миграции и все у вас заработало. У меня получилось только и с удалением таблиц в БД, иначе требовало правило on_delete="CASCAD"
Спасибо. Буду знать
Здравствуйте, подскажите, пожалуйста, серия из скольки роликов примерно планируется и когда выйдет последний? Спасибо за контент!
Планируется ещё около 10 видео. Надеюсь к концу марта все снять
Большое спасибо за видео,очень полезно.Один момент:
Возможно ли в Swagger doc где эндпоинт login поменять название поля с "username" на "email"
Потому что,вводит в заблуждение разработчика,там по факту поле принимает email,но название username
Спасибо заранее за ответ
очень интересно спасибо
Артём, хорошее дело делаешь! Молодец, продолжай!
Вопрос по ходу дела. Я понимаю что Python язык не строгой типизации, но все же...
Если заглянуть в класс SQLAlchemyBaseUserTable
то можем там увидеть следующий странный код:
hashed_password: str = Column(String(length=1024), nullable=False)
is_active: bool = Column(Boolean, default=True, nullable=False)
is_superuser: bool = Column(Boolean, default=False, nullable=False)
is_verified: bool = Column(Boolean, default=False, nullable=False)
Мы говорим что переменная hashed_password имеют тип str, is_active это bool и т.д. и тут же берем и просто назначаем объект с типом "Column"
Или, мы говорим что у нас id имеет тип int и тут же тоже пихаем в него "Column":
class User(SQLAlchemyBaseUserTable[int], Base):
id = Column(Integer, primary_key=True)
Можете объяснить, для полного понимания, в чем прикол и как это работает?
Спасибо
Привет)
Немного занудства сначала - питон имеет динамическую сильную типизацию. Динамическая - типы вычисляются в момент выполнения. Сильная - нельзя смешивать разные типы в выражении (нельзя вычесть строку из инта, привет, js)
Надо понять два момента:
1. тип через двоеточие после имени переменной:
hashed_password: str = Column(String(length=1024), nullable=False)
Это не объявление типа, это подсказка типа. Если будете искать больше информации, то ищите type hinting. Подсказка не накладывает никаких ограничений, по факту в переменной может лежать любой тип. Это именно что подсказка для разработчика (подсказки синтаксические будут от IDE итд)
2. id имеет тип int и тут же тоже пихаем в него "Column"
С чего бы начать. Если вкратце - это ORM. Задача ORM - абстрагировать разработчика от работы с БД. Мы используем один и тот же класс для определения таблицы в базе и для работы с объектами в нашей программе. То есть Column нужно для того чтобы библиотека делала корректные запросы при обращении к БД. Когда же мы будем работать с экземпляром класса User в коде, в поле id будет лежать int.
Для понимания, обратите внимание, как в github.com/artemonsh/fastapi_course/blob/main/Lesson_05/main.py#L43 мы берем поле username экземпляра класса User. И хоть в классе бы объявили это поле как класс Column github.com/artemonsh/fastapi_course/blob/main/Lesson_05/auth/database.py#L21, при обращении к полю username мы получим строку (потому что в базе в колонке username лежит строковое значение).
@@vsevolodtetervak257
Привет!)
Да, вправил мозги, теперь стало гораздо понятнее. Благодарю!
Артем, подскажи как правильней сделать. Есть логин юзера в приложении через JWT и этому юзеру нужно предоставить дополнительно безлимитный по вреимени токен для некоторых операций с API. Как лучше хранить и проверять токен? Хранить в базе и кеше, чтоб каждый раз базу не дергать? Запросов с этим доп токеном может быть много.
Мне очень кажется странным что в реализации этой библиотеки нет модели с refresh_token , хотя копаясь в недрах самой библиотеки я нашел в классе BaseUserManager поле с рефреш токеном. То есть автор полагал что это поле нужное, но в документации эта тема совсем не тронута. И у вас вижу не реализован метод refresh и вы работаете с одним токеном. Может есть объективные причины на это, могли бы сказать почему ?
К моему комментарию выше:
Фронтенд разработчик на работе погрузил меня в муки сомнений. Он уверенно утверждал что реализация в fastapi-users неправильная! Должно быть два токена refresh & access. Я не первый раз использую fastapi users, но после его слов у меня тревога и ворт в пастели )) Думаю надо написать свою аутентификацию а за одно понять все на молекулярном уровне. Написал ! Понял😊 FastAPI users отличная библиотека!
Идея с ролью для пользователя по умолчанию ясна, но мне кажется прописывать это в виде "1" в коде не очень читаемое и поддерживаемое решение, мало ли как потом базу данных поменяют, или кто будет этот код читать...
Артем, можно ли реализовать авторизацию и аутентификацию пользователя c помощью FastAPI Users, но без логина и пароля, а с ключом? Просто вместо логина и пароля передавать сгенерированный ключ, например, uuid.
а роль то почему не меняется? Шлешь 2 получаешь в бд 2, шлешь 1 - в бд тоже 1. Что я пропустил? user_dict['role_id'] = 1 добавлял
кстати очень много с докой не сходиться это такая фича? меня аж немного подгорать начало хотя курс свежий
А можете выпустить видео, где будет интеграция с фротендом, а то никак не получается интегрировать. А так спасибо за курс по Fastapi.
на канале уже есть видео fastapi + frontend, называется "Fullstack - это просто". Выходило в начале года, обязательно посмотрите)
@@artemshumeiko поищу, а по никак не могу связать формы регистрации и авторизации на фронте с беком. Если есть возможность - дайте ссылку на видео . спасибо
@@artemshumeiko Это видео Как Связать Бэкенд и Фронтенд? React + FastAPI Full Stack приложение ?
@@Edvardmoskovka да
Артём, спасибо за урок. Сейчас у вас в проекте две ОРМ модели из разных библиотек (psycopg2, asyncpg)? Поясните пожалуйста зачем? Это ведь вылнуждает поддерживать и сихронизировать их вручную
Спасибо за комментарий! Действительно, psycopg2 устанавливался в уроке по Базам Данных, но по ходу развития курса стало ясно, что нет необходимости его использовать. В дальнейшем будет использоваться только asyncpg.
В следующем уроке я еще обращусь к теме БД и, в частности, SQLAlchemy и особенностей подключения и работы с ней
@@artemshumeiko По 4 уроку переписал с использованием asyncpg. Все же тоже самое получается? Изменения по сути только в URL - "postgresql+asyncpg" и команде alembic init -t async migrations? Или еще какие-то есть нюансы?
возможно, к URL в конце стоит дописать "?async_fallback=True", как упомянуто в 6 видео
@@artemshumeiko Я может тогда не так понял. Но разве не так должно быть:
from sqlalchemy.ext.asyncio import create_async_engine
engine = create_async_engine("postgresql+asyncpg://user:pass@hostname/dbname")
(The asyncpg dialect is SQLAlchemy’s first Python asyncio dialect.
Using a special asyncio mediation layer, the asyncpg dialect is usable as the backend for the SQLAlchemy asyncio extension package.
This dialect should normally be used only with the create_async_engine() engine creation function:)
а наоборот перевод в синхронку:
# for testing purposes only; do not use in production!
engine = create_engine("postgresql+asyncpg://user:pass@hostname/dbname?async_fallback=true")
(The dialect can also be run as a “synchronous” dialect within the create_engine() function, which will pass “await” calls into an ad-hoc event loop. This mode of operation is of limited use and is for special testing scenarios only. The mode can be enabled by adding the SQLAlchemy-specific flag async_fallback to the URL in conjunction with create_engine():)
@@ЕвгенийЗемляной-д6ф имелось в виду добавить async_fallback к переменной sqlalchemy.url в файле alembic.ini. Адрес БД в функции create_async_engine менять не нужно
Артём, спасибо за полезную информацию!
На 11 минуте, а именно в 10:20 ты говоришь "скопируем код" и у тебя в браузере есть значок скопировать код, а у меня ни в Firefox, ни в Chrome нет этой кнопки. Это какой-то плагин к браузеру?
Это кнопка внутри документации позволяет скопировать весь код
А нельзя как-то скрыть параметры булевые при регистрации? Просто в модели дефолтные прописать и все, чтобы при инсерте не ругалась БД? Просто зачем выносить из класса отдельную функцию и переписывать ее, ощущение просто, что это костыль дикий прям и можно красивше)