Django rest framework создать пользователя

Обновлено: 06.07.2024

я кодирую REST API с Django REST framework. API будет бэкендом социального мобильного приложения. После выполнения этого урока я могу сериализовать все свои модели, и я могу создавать новые ресурсы и обновлять их.

Я использую AuthToken для аутентификации.

у меня есть /users ресурс, я хочу, чтобы пользователь приложения мог зарегистрироваться. Так что, лучше иметь отдельный ресурс, как /register или разрешить анонимные пользователи для публикации в /users новый ресурс?

кроме того, некоторые рекомендации о разрешениях было бы здорово.

Я пошел вперед и сделал свой собственный пользовательский вид для обработки регистрации, так как мой сериализатор не ожидает, чтобы показать/получить пароль. Я сделал url-адрес отличным от ресурса /users.

мой url conf:

мое мнение:

Я могу ошибаться, но не похоже, что вам нужно будет ограничивать разрешения на это представление, так как вам нужны неавторизованные запросы .

Django REST Framework 3 разрешить переопределить create метод в сериализаторах:

также api.py:

самое простое решение, работающее в DRF 3.x:

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

write_only_fields будет убедиться, что пароли (на самом деле: их хэш мы храним) не отображаются, в то время как перезапись create метод гарантирует, что пароль хранится не в виде открытого текста, а в виде хэша.

я обновил ответ Cahlan для поддержки пользовательских моделей пользователей из Django 1.5 и вернул идентификатор пользователя в ответе.

Я обычно рассматриваю представление пользователя так же, как и любую другую конечную точку API, требующую авторизации, за исключением того, что я просто переопределяю набор разрешений класса представления своим собственным для POST (aka create). Я обычно использую этот шаблон:

для хорошей меры, вот сериализатор я обычно использую с ним:

djangorestframework 3.3.x / Django 1.8.x

@cpury выше предложил использовать . Это, однако, не работает для меня в DRF 3.3.3

на DRF 3.0 the write_only_fields опция на ModelSerializer была перемещена в PendingDeprecation и в DRF 3.2 заменен на более общий extra_kwargs:

extra_kwargs = >

все ответы до сих пор создают пользователя, а затем обновляют пароль пользователя. Это приводит к записи двух БД. Чтобы избежать дополнительной ненужной записи БД, установите пароль пользователя перед его сохранением:

немного опоздал на вечеринку, но может помочь кому-то, кто не хочет писать больше строк кода.

мы можем использовать super метод для достижения этой цели.

В первой части введения в Django Rest Framework мы создали проект и сделали обзор того, что представляет собой проект. Проверьте это, если вы еще не сделали.

Ообзор

В этом разделе мы пройдем регистрацию пользователей с помощью Django Rest Framework и будем использовать веб-токены JSON для авторизации. Мы также будем расширять модель User по умолчанию, которая поставляется с django, чтобы мы могли получить больше информации о пользователях нашей системы.

Проект доступен на github.

Что такое веб-токен JSON?

JSON Web Token (JWT) - это интернет-стандарт для создания токенов доступа на основе JSON, которые утверждают некоторое количество претензий. Например, сервер может сгенерировать токен с флагом «авторизованный как администратор» или «авторизованный как этот пользователь» и предоставить его клиенту. Затем клиент может использовать этот токен, чтобы доказать, что он вошел как администратор. Токены подписаны закрытым ключом одной стороны (обычно сервером), чтобы обе стороны могли проверить, является ли токен легитимным. Маркеры спроектированы так, чтобы быть компактными, безопасными для URL и использоваться, особенно в контексте единого входа (SSO) веб-браузера. Заявления JWT обычно могут использоваться для передачи идентификационных данных аутентифицированных пользователей между поставщиком идентификационных данных и поставщиком услуг.

В отличие от аутентификации на основе токенов, JWT не хранятся в базе данных приложения. Для более подробного объяснения того, как работают JWT, посмотрите это потрясающее видео.

Создание проекта

Прежде чем продолжить, давайте посмотрим на некоторые из конечных точек, которые мы будем использовать в этом разделе.

Это может показаться трудным, но хорошая новость в том, что djoser сделал для нас большую часть тяжелой работы. Все конечные точки, начинающиеся с auth, генерируются djoser.

Возвращаясь к первой части серии, мы установили несколько пакетов Python. Нам нужно добавить эти пакеты в файл settings.py проекта, чтобы использовать их в нашем проекте django.

Не забудьте изменить настройки аутентификации для DRF, чтобы отразить использование JWTS.

После настройки этой системы важно зарегистрировать маршруты для конечных точек, которые будут использоваться в проекте. Регистрируя пути к главному файлу проекта urls.py , мы можем получить доступ к различным конечным точкам, которые нам понадобятся позже.

Модель профиля пользователя

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

Мы также создадим сигнал post_save для автоматического создания профиля пользователя для новых пользователей, которые регистрируются на платформе.

Для этого создайте файл signal.py и напишите приведенный ниже код.

Для подробного объяснения того, как работают сигналы, это хорошая отправная точка. Не забудьте зарегистрировать сигнал в вашем файле app.py следующим образом:

Сериализаторы

С базовыми настройками давайте перейдем к реализации API. Если вы новичок в django, сериализаторы позволяют преобразовывать сложные данные, такие как наборы запросов и экземпляры модели, в собственные типы данных Python, которые можно легко преобразовать в форматы, такие как JSON. Это называется сериализацией. Они также позволяют десериализацию после первой проверки данных входящего запроса.

В каталоге приложения мы запустим файл serializers.py и введем следующий код:

Далее мы постарались импортировать класс сериализаторов из rest_framework , а также модель, которую мы хотим сериализовать. В данном случае это модель userProfile .

Наш первый сериализатор - userProfileSerializer . Он будет наследоваться от класса ModelSerializer в django. Как вы заметили ранее, модель userProfile была связана с моделью пользователя по умолчанию в django. Мы будем указывать это поле как read_only . Это означает, что поле будет включено в выходные данные API, но не будет включено во время операций создания или обновления на конечной точке. Чтобы заполнить это поле, мы создадим метод для автоматического заполнения поля пользователем запроса.

В rest_framework есть другие типы сериализатора, такие как ListSerializer и HyperlinkedModelSerializer . Для всестороннего руководства по сериализаторам лучше всего начать с документации по остальным фреймворкам.

Представления API

Для доступа к данным в API мы используем конечные точки. Это в основном URL-маршруты. Как работает django, так это то, что каждый URL связан с контроллером, называемым представлением. Контроллеры могут быть на основе классов или функций.

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

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

Некоторыми из этих представлений являются CreateAPIView , ListAPIView , ListCreateAPIView , RetrieveUpdateDestroyAPIView , и этот список можно продолжить.

Мы реализуем ListCreateAPIView и RetrieveUpdateDestroyAPIView .

Каждое представление API связано с классом сериализатора, который мы создали ранее. Одна вещь, на которую мы обратим внимание, это perform_create метод в классе UserProfileListCreateView . Вот как мы указываем, как мы хотим создать сериализатор. В этом случае мы хотели заполнить поле пользователя read_only запрашивающим пользователем, а затем заполнить сериализатор этим значением.

Права доступа

Разрешения определяют, должен ли запросу быть предоставлен или запрещен доступ. Django rest framework поставляется с несколькими. Я не буду вдаваться в подробности, поскольку их документация достаточно обширна. Однако давайте обратим наше внимание на класс разрешений IsOwnerProfileOrReadOnly .

Это реализация пользовательских разрешений. Мы инициализируем файл license.py и наполняем его следующим кодом:

Переопределив класс BasePermission , мы можем создать собственное разрешение. Этот класс имеет два метода, которые мы можем переопределить: .has_permission() и .has_object_permission() .

Оба должны возвращать True , если запрос должен быть удовлетворен, и False , если запрос отклонен. SAFE_METHODS - это GET, OPTIONS и HEAD.

В нашем пользовательском классе разрешений мы проверяем, похож ли запрашивающий пользователь на пользовательское поле объекта. Это гарантирует, что владелец профиля - единственный, кто может изменить свою информацию.

API тесты

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

Чтобы запустить тесты, запустите команду

python manage.py test

в вашем терминале.

Если вы чувствуете себя немного смущенным, вот структура проекта до этого момента.


В этой статье мы рассмотрим как делается регистрация пользователя Django через rest-framework, это очень просто.

Но перед тем как прочитать эту статью, посмотрите «Быстрый старт Django», если вы не знаете как создать проект на Django.

Подключение библиотек:

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

В начале мы скачиваем rest-framework для Django, который добавляет в него логику RestAPI, следующие скачивание, это библиотека Djoser, которая сделана просто для обычной авторизации.

Дальше подключаем в «settings.py», в список INSTALLED_APPS всё что мы скачали.

Настройка библиотек:

Теперь настраиваем библиотеки, в начале добавляем список REST_FRAMEWORK .

Также добавляем список DJOSER .

Тут вы скорее всего заметили название параметр SEND_ACTIVATION_EMAIL с параметром False, это нужно что бы при регистрации не отправлялась почта для подтверждение EMAIL, но так нужно делать только если вы разрабатываете на локальном сервере.

Последние добавляем в «urls.py», новые пути для работы регистрации и авторизации, которые мы будем использовать.

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

Создание пользователя и регистрации:

Перейдём к созданию пользователя, для этого создайте приложение используя эту команду.

У вас должна появится папка «users», там переходим во файл «models.py» и в нём создаём модель пользователя.

models.py:

from django . contrib . auth . models import AbstractBaseUser , BaseUserManager , PermissionsMixin def _create_user ( self , email , username , password , * * extra_fields ) : return self . _create_user ( email , username , password ) def create_superuser ( self , email , username , password ) : return self . _create_user ( email , username , password , is_staff = True , is_superuser = True )

Дальше создаём пользователя, передаём туда в качестве параметров Email и логин, также есть **extra_fields , это нужно если надо добавит дополнительные параметры, которые мы будем делать при создание администратора, сохраняем пароль и пользователя, возвращаем его.

Остальные два метода, это создание обычного пользователя и создание администратора, вот и всё.

Теперь когда с первым классом разобрались, делаем второй, который для пользователя.

Тут мы создали класс пользователя наследуем его от двух других классов, AbstractBaseUser , базовый абстрактный класс пользователя и PermissionsMixin , это класс для прав доступа.

Внутри него пишем параметры:

В этом коде самое интересное то, что для поля активации мы принимаем параметр default=True , это значит то, что по умолчанию пользователь будет активирован.

Свойства USERNAME_FIELD , это идентификатор для обращения, а REQUIRED_FIELDS хранит список имён при регистрации администратор или суперюзера.

Также создаём objects , и в него добавляем класс MyUserManager , что бы могли использовать его методы.

Теперь нужно сделать миграции, для этого вводим эти две команды.

На этом с моделями всё, тут больше не чего сказать.

serializers.py:

Теперь создаём файл «serializers.py», в папке «users» и пишем в нём такой код.

class UserRegistrSerializer ( serializers . ModelSerializer ) :

В начале как всегда подключаем нужные нам компоненты, потом создаём класс UserRegistrSerializer , наследуем его от класса ModelSerializer , в нём первым делом создаём поле password2 , для повторного пароля.

Потом идёт класс Meta , в котором идёт настройка полей, которые будет принимать сервер, первое свойство, это откуда взять поля, второе список полей.

После класса создаём метод для создания нового пользователя, в нём делаем новый объект класса User , проверяем совпадают ли пароли и сохраняем, возвращаем нового пользователя, тут файлам.

views.py:

Последние что осталось рассмотреть, это файл «views.py», вот он.

from rest_framework . generics import CreateAPIView serializer = UserRegistrSerializer ( data = request . data )

В начале как обычно подключаем все нужные нам зависимости, для чего какая нужна посмотрите к комментариях кода, потом создаём класс RegistrUserView , он у нас будет отвечать за всё регистрацию, самым первым там идут свойства, опять же про них подробнее прочитаете в комментариях.

Потом идёт метод post , и как можно понять из названия, он будет работать только если получает POST запросы от клиента, внутри его мы первым делом создаём объект serializer , класса UserRegistrSerializer , там в качестве параметра data передаём request (запрос), который получаем от клиента.

Потом проверяем на валидность, если всё правильно, то сохраняем и выводим что ошибок нет, если не правильно, то показываем ошибки.

я кодирую REST API с помощью Django Rest framework. API будет бэкэндом социального мобильного приложения. После выполнения руководства я могу сериализовать все свои модели, и я могу создавать новые ресурсы и обновлять их.

Я использую AuthToken для аутентификации.

как только у меня будет /users ресурс, я хочу, чтобы пользователь приложения мог зарегистрироваться. Итак, лучше ли иметь отдельный ресурс, такой как /register или разрешить анонимные пользователи для публикации в /users новый ресурс?

кроме того, некоторые рекомендации о разрешениях было бы здорово.

Я пошел вперед и сделал свой собственный пользовательский вид для обработки регистрации, так как мой сериализатор не ожидает показать/получить пароль. Я сделал url-адрес отличным от ресурса / users.

Я могу ошибаться, но не похоже, что вам нужно будет ограничивать разрешения на это представление, так как вы хотите неавторизованные запросы .

Django REST Framework 3 разрешить переопределить create метод в сериализаторах:

также api.py:

самое простое решение, работающее в DRF 3.x:

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

write_only_fields убедитесь, что пароли (на самом деле: их хэш мы храним) не отображаются, в то время как перезаписанный create метод гарантирует, что пароль хранится не в виде открытого текста, а в виде хэша.

я обновил ответ Cahlan для поддержки пользовательских моделей пользователей из Django 1.5 и вернул идентификатор пользователя в ответе.

обычно я рассматриваю представление пользователя так же, как и любую другую конечную точку API, требующую авторизации, за исключением того, что я просто переопределяю набор разрешений класса представления своим собственным для POST (aka create). Я обычно использую этот шаблон:

для хорошей меры, вот сериализатор, который я обычно использую с ним:

djangorestframework 3.3.x / Django 1.8.x

@cpury выше предложил использовать . Однако это не сработало для меня в DRF 3.3.3

на DRF 3.0 на write_only_fields опция на ModelSerializer была перемещена в PendingDeprecation и в DRF 3.2 заменен более общим extra_kwargs:

все ответы до сих пор создают пользователя, а затем обновляют пароль пользователя. Это приводит к записи двух БД. Чтобы избежать дополнительной ненужной записи БД, установите пароль пользователя перед его сохранением:

немного опоздал на вечеринку, но может помочь кому-то, кто не хочет писать больше строк кода.

Всем привет. При разработке API для очередного веб-портала я взял свой привычный стек:

Но в этот раз стояла довольно непривычная задача — сделать одну User модель, которая может иметь несколько разных профилей (Исполнитель, Заказчик). И наличие каждого из профилей дает разные полномочия на работу с одними и теми же ресурсами.

Такой подход позволяет пользователям не заводить несколько учетных записей для каждой роли, что зачастую было бы невозможно, ввиду ограничений на модель: уникальный email или номер телефона.

Итак, опишем возникшие перед нами проблемы:

  1. Один пользователь – несколько профилей.
  2. Как организовать права каждого из профилей.
  3. Доступ к одним тем же ресурсам от разных профилей.

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

Таким образом каждый пользователь может иметь от 0 до 2-х профилей (профиль Исполнителя, профиль Заказчика).

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

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

Для действий, которые доступны пользователям с любым из профилей, можно сделать общий permission

У такого подхода есть минус: если пермишнов по профилям будет больше 2-х, то множество таких сочетаний будет сильно расти. Но если вы можете с достаточной уверенностью утверждать, что пермишны не будут расширяться, то код останется довольно лаконичным.

Почему необходимость в таких составных пермишнах вообще возникает

В django-rest-framework пермишны, которые применяются к конкретной вью, указываются в атрибуте permissions_class, которые накладывается по принципу AND.

В этом примере доступ ко вью получат только пользователи, имеющие оба профиля.

Именно в таком случае нам приходится придумывать фокусы с составными пермишнами EmployeeAndCompanyManagerOnly и использовать их в качестве одного общего пермишн класса.

С версии 3.9 в drf появилась возможность конструировать различные условия из пермишнов, используя синтаксис битовых операций

Синтаксис не самый очевидный и симпатичный, но может быть удобнее, чем городить кучу составных пермишн классов.

В текущей версии проекта я использовал версию drf 3.11, поэтому решил использовать эту новую возможность. Это добавляет некоторой гибкости в масштабировании проекта, не так уж сильно усложняя чтение и понимание кода.

P.S. В дальнейшем у меня добавились еще пермишны для CompanyOwnerOnly и CompanyMemberOnly, и мне не пришлось ничего дописывать помимо этих классов, что хорошо.

Мы дошли до самого интересного и неочевидного места.

Немного о том, как я организую апи

Когда-то давно, потратив несколько дней на изучение вопросов (Как же все-таки правильно писать REST API? Обязательно ли апи должно быть RESTful? Да и вообще как делать правильно? Должны же быть какие-то best practice?), я понял, что мнений много, а четких правил нет. Но все мнения сходятся в одном: не бойтесь делать то, что удобно в вашем случае.

И для себя я вывел следующие тезисы:

  • Не усложняй. В попытке удержать гордое звание RESTful, апи может стать довольно сложным, а количество производных ресурсов будет неизбежно расти. Так как действий, выраженных глаголами GET POST PUT DELETE, будет всегда не хватать. Особенно если вы делаете что-то сложнее, чем приложение AuthorBook.
  • Не бойся использовать action endpoint'ы. Добавив немного RPC в наш REST, мы поймем, что оно ничуть не потеряло в удобстве. Зато жизнь разработчика упрощается многократно. Например, это очень удобно для переключения каких-то флагов у ресурсов.
  • Не злоупотребляй action endopoint'ами. Если их стало слишком много, это значит, что скорее всего твой ресурс слишком сложный, и его надо декомпозировать на несколько производных объектов.

В своих проектах я использую viewsets от drf, которые из коробки генерят необходимые нам REST окончания для наших моделей. И в случае необходимости разбавляю его некоторыми экшнами.


Вернемся к нашей проблеме

Итак, опишем ресурс, с которым взаимодействуют различные пользователи:

Cодержание экшнов не имеет значения ("create", "update", "partial_update" — название дефолтных экшнов drf), поэтому не буду приводить их описания.

Вот как будет выглядеть апи от имени Исполнителя (для Заказчика аналогично, только со своими методами):


И все бы было хорошо, если бы не тот факт, что один и тот же пользователь, может иметь сразу оба профиля, а значит сваггер нарисует нам следующую картинку:


Тут и становится понятно, что у нас есть некоторые проблемы:

  1. Как определить, от имени какого профиля я хочу запросить список задач, если у меня их два.
  2. Имея доступ к задаче (могу получить ее по GET /tasks/), я могу делать с ней только те действия, которые определены моей ролью в этой задаче, а не наличием у меня того или иного профиля.

И решить их навскидку можно 4-мя способами:

Написать разные TaskViewSet для Исполнителя и Заказчика.

Плюсы Минусы
Код получается прямолинейный, без лишних if Спецификация сильно растет
- Несколько вьюх вместо одной (труднее поддерживать)
- Employee и Сompany это все-таки не путь к ресурсу, а роль, с которой я работаю в этом ресурсе, как-то не "по-рестовски" пихать ее в url

Использовать кастомный хэдер в реквесте для определения, в качестве кого пользователь хочет запросить ресурс.

Плюсы Минусы
Предположительная красота спецификации (ничего лишнего в урлах) В логах ничего не понятно: если что-то где-то упадет, сложно понять, от имени кого пользователь запрашивал данные
- Автоматический генератор спецификации (drf_yasg) не поддерживает добавления кастомных хэдеров, поэтому разработка превратилась бы в ад

Использовать query параметры в урле.

Плюсы Минусы
Вью будет одна Сразу понятно, что вью усложнится: будут постоянные if else
Кажется, что спецификация будет симпатичная (вкусовщина) -

HATEOAS (расскажу подробнее в следующем посте!)

По этому решению я не могу описать плюсы-минусы, так как никогда не пытался внедрять в свои проекты. Читал, что это не всегда удобно и бывает не просто поддерживать.
Но достоверность этой информации подтвердить не могу.
Так же есть подозрение, что подход не решает проблему №1.

Я выбрал третье решение, так как в нем меньше всего минусов.

Написал специальный сериалайзер и подключаю его к спецификации тех экшнов, которые должны содержать этот query параметр.


Получилось довольно симпатично и последним штрихом осталось определить queryset во вью в зависимости от выбранного mode.

Итак, мы решили проблему №1, теперь мы точно знаем, от какой роли запрашиваем задачи.

Следующим этапом надо было придумать, как ограничить действия на объекты, которые мы можем получить, например, как Исполнитель, но не можем редактировать как Заказчик (так как мы не ее автор, хоть у нас и есть профиль Заказчика).

И тут мне помогло то, как организован метод self.get_object() в drf view.

Он ищет объект в queryset = self.filter_queryset(self.get_queryset()) , который мы определили до этого, что в общем-то логично, так как другой связи с моделью у вью нет.

Соответственно небольшой модификацией кода мы решили и вторую проблему:

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

После небольшого рефакторинга стало лучше:

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

В первую очередь я набирал этот текст, чтобы попытаться логически выстроить свое решение и объяснить каждый следующую шаг.

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

На хабр я решил запостить эту статью, т.к. пока решал данную задачу, долго искал что-то похожее в интернете, но нашел довольно мало материалов на тему "один пользователь — много ролей".

Хочется узнать не изобретал ли я велосипед в стеке Django, drf. А если это действительно нужный кейс, то можно даже обернуть это в небольшой плагинчик для джанго.

Читайте также: