Стратегии расширения Django User Model
В Django встроена прекрасная система аутентификации пользователей. В большинстве случаев мы можем использовать ее «из коробки», что экономит много времени разработчиков и тестировщиков. Но иногда нам необходимо расширить ее, чтобы удовлетворять потребностям нашего сайта.
Как правило возникает потребность хранить дополнительные данные о пользователях, например, краткую биографию (about), дату рождения, местоположение и другие подобные данные.
В этой статье пойдет речь о стратегиях, с помощью которых вы можете расширить пользовательскую модель Django, а не писать ее с нуля.
Стратегии расширения
Опишем кратко стратегии расширения пользовательской модели Django и потребности в их применении. А потом раскроем детали конфигурирование по каждой стратегии.
Простое расширение модели (proxy)
Эта стратегия без создания новых таблиц в базе данных. Используется, чтобы изменить поведение существующей модели (например, упорядочение по умолчанию, добавление новых методов и т.д.), не затрагивая существующую схему базы данных.
Вы можете использовать эту стратегию, когда вам не нужно хранить дополнительную информацию в базе данных, а просто необходимо добавить дополнительные методы или изменить диспетчер запросов модели. →
Использование связи один-к-одному с пользовательской моделью (user profiles)
Это стратегия с использованием дополнительной обычный модели Django со своей таблицей в базе данных, которая связана пользователем стандартной модели через связь OneToOneField .
Вы можете использовать эту стратегию, чтобы хранить дополнительную информацию, которая не связана с процессом аутентификации (например, дата рождения). Обычно это называется пользовательский профиль. →
Расширение AbstractBaseUser
Это стратегия использования совершенно новой модели пользователя, которая отнаследована от AbstractBaseUser . Требует особой осторожности и изменения настроек в settings.py . В идеале должно быть сделано в начале проекта, так как будет существенно влиять на схему базы данных.
Вы можете использовать эту стратегию, когда ваш сайт имеет специфические требования в отношении процесса аутентификации. Например, в некоторых случаях имеет смысл использовать адрес электронной почты в качестве идентификации маркера вместо имени пользователя. →
Расширение AbstractUser
Это стратегия использования новой модели пользователя, которая отнаследована от AbstractUser . Требует особой осторожности и изменения настроек в settings.py . В идеале должно быть сделано в начале проекта, так как будет существенно влиять на схему базы данных.
Простое расширение модели (proxy)
Это наименее трудоемкий способ расширить пользовательскую модель. Полностью ограничен в недостатках, но и не имеет никаких широких возможностей.
from django.contrib.auth.models import User from .managers import PersonManager class Person(User): objects = PersonManager() class Meta: proxy = True ordering = ('first_name', ) def do_something(self): .
В приведенном выше примере мы определили расширение модели User моделью Person . Мы говорим Django это прокси-модель, добавив следующее свойство внутри class Meta :
Proxy = True
Также в примере назначен пользовательский диспетчер модели, изменен порядок по умолчанию, а также определен новый метод do_something() .
Стоит отметить, что User.objects.all() и Person.objects.all() будет запрашивать ту же таблицу базы данных. Единственное отличие состоит в поведении, которое мы определяем для прокси-модели.
Использование связи один-к-одному с пользовательской моделью (user profiles)
Скорее всего, это то, что вам нужно. Лично я использую этот метод в большинстве случаев. Мы будем создавать новую модель Django для хранения дополнительной информации, которая связана с моделью пользователя.
Имейте в виду, что использование этой стратегии порождает дополнительные запросы или соединения внутри запроса. В основном все время, когда вы будете запрашивать данные, будет срабатывать дополнительный запрос. Но этого можно избежать для большинства случаев. Я скажу пару слов о том, как это сделать, ниже.
from django.db import models from django.contrib.auth.models import User class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) bio = models.TextField(max_length=500, blank=True) location = models.CharField(max_length=30, blank=True) birth_date = models.DateField(null=True, blank=True)
Теперь добавим немножко магии: определим сигналы, чтобы наша модель Profile автоматически обновлялась при создании/изменении данных модели User .
from django.db import models from django.contrib.auth.models import User from django.db.models.signals import post_save from django.dispatch import receiver class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) bio = models.TextField(max_length=500, blank=True) location = models.CharField(max_length=30, blank=True) birth_date = models.DateField(null=True, blank=True) @receiver(post_save, sender=User) def create_user_profile(sender, instance, created, **kwargs): if created: Profile.objects.create(user=instance) @receiver(post_save, sender=User) def save_user_profile(sender, instance, **kwargs): instance.profile.save()
Мы «зацепили» create_user_profile() и save_user_profile() к событию сохранения модели User . Такой сигнал называется post_save .
А теперь пример шаблона Django с использованием данных Profile :
А еще можно вот так:
def update_profile(request, user_id): user = User.objects.get(pk=user_id) user.profile.bio = 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. ' user.save()
Вообще говоря, вы никогда не должны вызывать методы сохранения Profile . Все это делается с помощью модели User .
Если вам необходимо работать с формами, то ниже приведены примеры кода для этого. Помните, что вы можете за один раз (из одной формы) обрабатывать данные более одной модели (класса).
class UserForm(forms.ModelForm): class Meta: model = User fields = ('first_name', 'last_name', 'email') class ProfileForm(forms.ModelForm): class Meta: model = Profile fields = ('url', 'location', 'company')
@login_required @transaction.atomic def update_profile(request): if request.method == 'POST': user_form = UserForm(request.POST, instance=request.user) profile_form = ProfileForm(request.POST, instance=request.user.profile) if user_form.is_valid() and profile_form.is_valid(): user_form.save() profile_form.save() messages.success(request, _('Your profile was successfully updated!')) return redirect('settings:profile') else: messages.error(request, _('Please correct the error below.')) else: user_form = UserForm(instance=request.user) profile_form = ProfileForm(instance=request.user.profile) return render(request, 'profiles/profile.html', < 'user_form': user_form, 'profile_form': profile_form >)
profile.html
И об обещанной оптимизации запросов. В полном объеме вопрос рассмотрен в другой моей статье.
Но, если коротко, то Django отношения ленивы. Django формирует запрос к таблице базы данных, если необходимо прочитать одно из ее полей. Относительно нашего примера, эффективным будет использование метода select_related() .
Зная заранее, что вам необходимо получить доступ к связанным данным, вы можете c упреждением сделать это одним запросом:
users = User.objects.all().select_related('Profile')
Расширение AbstractBaseUser
Если честно, я стараюсь избегать этот метод любой ценой. Но иногда это не возможно. И это прекрасно. Едва ли существует такая вещь, как лучшее или худшее решение. По большей части, существует более или менее подходящее решение. Если это является наиболее подходящим решением для вас, что ж — идите вперед.
Я должен был сделать это один раз. Честно говоря, я не знаю, существует ли более чистый способ сделать это, но не нашел ничего другого.
Мне нужно было использовать адрес электронной почты в качестве auth token , а username абсолютно был не нужен. Кроме того, не было никакой необходимости флага is_staff , так как я не использовал Django Admin.
Вот как я определил свою собственную модель пользователя:
from __future__ import unicode_literals from django.db import models from django.contrib.auth.models import PermissionsMixin from django.contrib.auth.base_user import AbstractBaseUser from django.utils.translation import ugettext_lazy as _ from .managers import UserManager class User(AbstractBaseUser, PermissionsMixin): email = models.EmailField(_('email address'), unique=True) first_name = models.CharField(_('first name'), max_length=30, blank=True) last_name = models.CharField(_('last name'), max_length=30, blank=True) date_joined = models.DateTimeField(_('date joined'), auto_now_add=True) is_active = models.BooleanField(_('active'), default=True) avatar = models.ImageField(upload_to='avatars/', null=True, blank=True) objects = UserManager() USERNAME_FIELD = 'email' REQUIRED_FIELDS = [] class Meta: verbose_name = _('user') verbose_name_plural = _('users') def get_full_name(self): ''' Returns the first_name plus the last_name, with a space in between. ''' full_name = '%s %s' % (self.first_name, self.last_name) return full_name.strip() def get_short_name(self): ''' Returns the short name for the user. ''' return self.first_name def email_user(self, subject, message, from_email=None, **kwargs): ''' Sends an email to this User. ''' send_mail(subject, message, from_email, [self.email], **kwargs)
Я хотел сохранить ее как можно ближе к «стандартной» модели пользователя. Отнаследовав от AbstractBaseUser мы должны следовать некоторым правилам:
-
USERNAME_FIELD — строка с именем поля модели, которая используется в качестве уникального идентификатора ( unique=True в определении);
Мой UserManager выглядел следующим образом:
from django.contrib.auth.base_user import BaseUserManager class UserManager(BaseUserManager): use_in_migrations = True def _create_user(self, email, password, **extra_fields): """ Creates and saves a User with the given email and password. """ if not email: raise ValueError('The given email must be set') email = self.normalize_email(email) user = self.model(email=email, **extra_fields) user.set_password(password) user.save(using=self._db) return user def create_user(self, email, password=None, **extra_fields): extra_fields.setdefault('is_superuser', False) return self._create_user(email, password, **extra_fields) def create_superuser(self, email, password, **extra_fields): extra_fields.setdefault('is_superuser', True) if extra_fields.get('is_superuser') is not True: raise ValueError('Superuser must have is_superuser=True.') return self._create_user(email, password, **extra_fields)
По сути, я очистил существующий UserManager от полей username и is_staff .
Последний штрих. Необходимо изменить settings.py :
AUTH_USER_MODEL = 'core.User'
Таким образом, мы говорим Django использовать нашу пользовательскую модель вместо поставляемой «в коробке». В примере выше, я создал пользовательскую модель внутри приложения с именем core .
Как ссылаться на эту модель?
Есть два способа. Рассмотрим модель под названием Course :
from django.db import models from testapp.core.models import User class Course(models.Model): slug = models.SlugField(max_length=100) name = models.CharField(max_length=100) tutor = models.ForeignKey(User, on_delete=models.CASCADE)
В целом нормально. Но, если вы планируете использовать приложение в других проектах или распространять, то рекомендуется использовать следующий подход:
from django.db import models from django.conf import settings class Course(models.Model): slug = models.SlugField(max_length=100) name = models.CharField(max_length=100) tutor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
Расширение AbstractUser
Это довольно просто, поскольку класс django.contrib.auth.models.AbstractUser обеспечивает полную реализацию пользовательской модели по-умолчанию в качестве абстрактной модели.
from django.db import models from django.contrib.auth.models import AbstractUser class User(AbstractUser): bio = models.TextField(max_length=500, blank=True) location = models.CharField(max_length=30, blank=True) birth_date = models.DateField(null=True, blank=True)
После этого необходимо изменить settings.py :
AUTH_USER_MODEL = 'core.User'
Как и в предыдущей стратегии, в идеале это должно быть сделано в начале проекта и с особой осторожностью, посколько изменит всю схему базы данных. Также хорошим правилом будет создавать ключи к пользовательской модели через импорт настроек from django.conf import settings и использования settings.AUTH_USER_MODEL вместо непосредственной ссылки на класс User .
Резюме
Отлично! Мы рассмотрели четыре различных стратегии расширения «стандартной» пользовательской модели. Я попытался сделать это как можно более подробно. Но, как я уже говорил, лучшего решения не существует. Все будет зависеть от того, что вы хотите получить.
- Простое расширение модели (proxy) — вас устраивает процесс аутентификации и хранение данных пользователя, вам просто хотелось бы изменить некоторое поведение.
- Использование связи один-к-одному с пользовательской моделью (user profiles) — вас устраивает процесс аутентификации, но хотелось бы добавить дополнительные данные пользователя (данные будут хранится в специальной модели).
- Расширение AbstractBaseUser — процесс аутентификации «из коробки» вам не подходит.
- Расширение AbstractUser — вас устраивает процесс аутентификации, но хотелось бы добавить дополнительные данные пользователя (данные будут хранится непосредственно в пользовательской модели, а не в специальной модели).
Оригинал
Не стесняйте задавать вопросы и высказывать мнения об этом посте!
Руководство Django Часть 8: Аутентификация и авторизация пользователя
В данном руководстве мы продемонстрируем вам систему входа пользователя на ваш сайт используя его собственный аккаунт. Кроме того, мы покажем как реализовать контроль того, что может видеть и делать пользователь, в зависимости от того, залогинен он, или нет, а также имеет ли он соответствующий уровень прав доступа (permissions). Для того чтобы продемонстрировать все это, мы расширим LocalLibrary, добавив страницы для входа/выхода, а также страницы просмотра/редактирования книг, специфические для пользователя и персонала.
| Требования: | Завершить изучение предыдущих тем руководства, включая Руководство Django Часть 7: Работа с сессиями. |
|---|---|
| Цель: | Понимать как настроить и использовать механизм аутентификации пользователя и разграничений прав доступа. |
Обзор
Django предоставляет систему аутентификации и авторизации («permission») пользователя, реализованную на основе фреймворка работы с сессиями, который мы рассматривали в предыдущей части. Система аутентификации и авторизации позволяет вам проверять учётные данные пользователей и определять какие действия какой пользователь может выполнять. Данный фреймворк включает в себя встроенные модели для Пользователей и Групп (основной способ применения прав доступа для более чем одного пользователя), непосредственно саму систему прав доступа (permissions)/флаги, которые определяют может ли пользователь выполнить задачу, с какой формой и отображением для авторизованных пользователей, а так же получить доступ к контенту с ограниченным доступом.
Примечание: В соответствии с идеологией Django система аутентификации является очень общей и, таким образом, не предоставляет некоторые возможности, которые присутствуют в других системах веб-аутентификации. Решениями некоторых общих задач занимаются пакеты сторонних разработчиков, например, защита от подбора пароля (через стороннюю библиотеку OAuth).
В данном разделе руководства мы покажем вам реализацию аутентификации пользователя на сайте LocalLibrary, создание страниц входа/выхода, добавления разграничения доступа (permissions) к вашим моделям, а также продемонстрируем контроль за доступом к некоторым страницам. Мы будем использовать аутентификацию/авторизацию для показа пользователям и сотрудникам библиотеки, списков книг, которые были взяты на прокат.
Система аутентификации является очень гибкой и позволяет вам формировать свои собственные URL-адреса, формы, отображения, а также шаблоны страниц, если вы пожелаете, с нуля, через простой вызов функций соответствующего API для авторизации пользователя. Тем не менее, в данной статье мы будем использовать «встроенные» в Django методы отображений и форм аутентификации, а также методы построения страниц входа и выхода. Нам все ещё необходимо создавать шаблоны страниц, но это будет достаточно несложно.
Мы покажем вам как реализовать разграничение доступа (permissions), а также выполнять соответствующую проверку статусов авторизации и прав доступа, в отображениях, и в шаблонах страниц.
Подключение аутентификации
Аутентификация была подключена автоматически когда мы создали скелет сайта (в части 2), таким образом на данный момент вам ничего не надо делать.
Примечание: Необходимые настройки были выполнены для нас, когда мы создали приложение при помощи команды django-admin startproject . Таблицы базы данных для пользователей и модели авторизации были созданы, когда в первый раз выполнили команду python manage.py migrate .
Соответствующие настройки сделаны в параметрах INSTALLED_APPS и MIDDLEWARE файла проекта (locallibrary/locallibrary/settings.py), как показано ниже:
= [ ... 'django.contrib.auth', # Фреймворк аутентификации и моделей по умолчанию. 'django.contrib.contenttypes', # Django контент-типовая система (даёт разрешения, связанные с моделями). .... MIDDLEWARE = [ ... 'django.contrib.sessions.middleware.SessionMiddleware', # Управление сессиями между запросами ... 'django.contrib.auth.middleware.AuthenticationMiddleware', # Связывает пользователей, использующих сессии, запросами. ....
Создание пользователей и групп
Вы уже создали своего первого пользователя когда мы рассматривали Административная панель сайта Django в части 4 (это был суперпользователь, созданный при помощи команды python manage.py createsuperuser ). Наш суперпользователь уже авторизован и имеет все необходимые уровни доступа к данным и функциям, таким образом нам необходимо создать тестового пользователя для отработки соответствующей работы сайта. В качестве наиболее быстрого способа, мы будем использовать административную панель сайта для создания соответствующих групп и аккаунтов locallibrary.
Примечание: вы можете создавать пользователей программно, как показано ниже. Например, вам мог бы подойти данный способ в том случае, если вы разрабатываете интерфейс, который позволяет пользователям создавать их собственные аккаунты (вы не должны предоставлять доступ пользователям к административной панели вашего сайта).
from django.contrib.auth.models import User # Создайте пользователя и сохраните его в базе данных user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword') # Обновите поля и сохраните их снова user.first_name = 'John' user.last_name = 'Citizen' user.save()
Ниже мы создадим группу, а затем пользователя. Несмотря на то, что у нас пока нет никаких разрешений для добавления к нашей библиотеке каких-либо членов, если мы захотим это сделать в будущем, то будет намного проще добавлять их к уже созданной группе, с заданной аутентификацией.
Запустите сервер разработки и перейдите к административной панели вашего сайта ( http://127.0.0.1:8000/admin/ ). Залогиньтесь на сайте при помощи параметров (имя пользователя и пароля) аккаунта суперпользователя. Самая «верхняя» страница панели Администратора показывает все наши модели. Для того, чтобы увидеть записи в разделе Authentication and Authorisation вы можете нажать на ссылку Users, или Groups.

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

- Нажмите на кнопку Add(Добавить) (рядом с Group) и создайте новую группу; для данной группы введите Name (Имя) «Library Members».
- Для данной группы не нужны какие-либо разрешения, поэтому мы просто нажимаем кнопку SAVE (Сохранить) (вы перейдёте к списку групп).
Теперь давайте создадим пользователя:
- Перейдите обратно на домашнюю страницу административной панели
- Для перехода к диалогу добавления пользователя нажмите на кнопку Add, соответствующую строке Users (Пользователи).

- Введите соответствующие Username (имя пользователя) и Password/Password confirmation (пароль/подтверждение пароля) для вашего тестового пользователя
- Нажмите SAVE для завершения процесса создания пользователя. Административная часть сайта создаст нового пользователя и немедленно перенаправит вас на страницу Change user (Изменение параметров пользователя) где вы можете, соответственно, изменить ваш username, а кроме того добавить информацию для дополнительных полей модели User. Эти поля включают в себя имя пользователя, фамилию, адрес электронной почты, статус пользователя, а также соответствующие параметры доступа (может быть установлен только флаг Active). Ниже вы можете определить группу для пользователя и необходимые параметры доступа, а кроме того, вы можете увидеть важные даты, относящиеся к пользователю (дату подключения к сайту и дату последнего входа).

- В разделе Groups, из списка Доступные группы выберите группу Library Member, а затем переместите её в блок «Выбранные группы» (нажмите стрелку-«направо», находящуюся между блоками).

- Больше нам не нужно здесь нечего делать, просто нажмите «Save»(Сохранить), и вы вернётесь к списку созданных пользователей.
Вот и все! Теперь у вас есть учётная запись «обычного члена библиотеки», которую вы сможете использовать для тестирования (как только добавим страницы, чтобы пользователи могли войти в систему).
Примечание: Попробуйте создать другого пользователя, например «Библиотекаря». Так же создайте группу «Библиотекарей» и добавьте туда своего только что созданного библиотекаря
Настройка представлений проверки
Django предоставляет почти все, что нужно для создания страниц аутентификации входа, выхода из системы и управления паролями из коробки. Это включает в себя url-адреса, представления (views) и формы,но не включает шаблоны — мы должны создать свой собственный шаблон!
В этом разделе мы покажем, как интегрировать систему по умолчанию в Сайт LocalLibrary и создать шаблоны. Мы поместим их в основные URL проекта.
Примечание: вы не должны использовать этот код, но вполне вероятно, что вы хотите, потому что это делает вещи намного проще. Вам почти наверняка потребуется изменить код обработки формы, если вы измените свою модель пользователя (сложная тема!) но даже в этом случае вы всё равно сможете использовать функции просмотра запасов.
**Примечание:**В этом случае мы могли бы разумно поместить страницы аутентификации, включая URL-адреса и шаблоны, в наше приложение каталога. Однако, если бы у нас было несколько приложений, было бы лучше отделить это общее поведение входа в систему и иметь его доступным на всем сайте, так что это то, что мы показали здесь!
Проектирование URLs
Добавьте следующее в нижней части проекта urls.py файл (locallibrary/locallibrary/urls.py) файл:
#Add Django site authentication urls (for login, logout, password management) urlpatterns += [ path('accounts/', include('django.contrib.auth.urls')), ]
Перейдите по http://127.0.0.1:8000/accounts/ URL (обратите внимание на косую черту!), Django покажет ошибку, что он не смог найти этот URL, и перечислить все URL, которые он пытался открыть. Из этого вы можете увидеть URL-адреса, которые будут работать, например:
Примечание: Примечание. Использование вышеуказанного метода добавляет следующие URL-адреса с именами в квадратных скобках, которые могут использоваться для изменения сопоставлений URL-адресов. Вам не нужно реализовывать что-либо ещё — приведённое выше сопоставление URL-адресов автоматически отображает указанные ниже URL-адреса.
Примечание:
/ login/ [name='login'] accounts/ logout/ [name='logout'] accounts/ password_change/ [name='password_change'] accounts/ password_change/done/ [name='password_change_done'] accounts/ password_reset/ [name='password_reset'] accounts/ password_reset/done/ [name='password_reset_done'] accounts/ reset/uidb64>/token>/ [name='password_reset_confirm'] accounts/ reset/done/ [name='password_reset_complete']
Теперь попробуйте перейти к URL-адресу входа ( http://127.0.0.1:8000/accounts/login/ ). Это приведёт к сбою снова, но с ошибкой, сообщающей вам, что нам не хватает требуемого шаблона (registration / login.html) в пути поиска шаблона. Вы увидите следующие строки, перечисленные в жёлтом разделе вверху:
: TemplateDoesNotExist Exception Value: registration/login.html
Следующий шаг — создать каталог регистрации в пути поиска, а затем добавить файл login.html.
Каталог шаблонов
URL-адреса (и неявные представления), которые мы только что добавили, ожидают найти связанные с ними шаблоны в каталоге / регистрации / где-то в пути поиска шаблонов.
Для этого сайта мы разместим наши HTML-страницы в каталоге templates / registration /. Этот каталог должен находиться в корневом каталоге проекта, то есть в том же каталоге, что и в каталоге и папках locallibrary). Создайте эти папки сейчас.
Примечание: ваша структура папок теперь должна выглядеть как показано внизу: locallibrary (django project folder) |_catalog |_locallibrary |_templates (new) |_registration
Чтобы сделать эти директории видимыми для загрузчика шаблонов (т. е. помещать этот каталог в путь поиска шаблона) откройте настройки проекта (/locallibrary/locallibrary/settings.py), и обновите в секции TEMPLATES строку ‘DIRS’ как показано.
= [ ... 'DIRS': [os.path.join(BASE_DIR, 'templates')], 'APP_DIRS': True, ...
Шаблон аутентификации
Предупреждение: Важно: Шаблоны аутентификации, представленные в этой статье, являются очень простой / слегка изменённой версией шаблонов логина демонстрации Django. Возможно, вам придётся настроить их для собственного использования!
Создайте новый HTML файл, названный /locallibrary/templates/registration/login.html. дайте ему следующее содержание:
extends "base_generic.html" %> block content %> if form.errors %> p>Your username and password didn't match. Please try again.p> endif %> if next %> if user.is_authenticated %> p>Your account doesn't have access to this page. To proceed, please login with an account that has access.p> else %> p>Please login to see this page.p> endif %> endif %> form method="post" action=" url 'login' %>"> csrf_token %> table> tr> td> <form.username.label_tag >>td> td> <form.username >>td> tr> tr> td> <form.password.label_tag >>td> td> <form.password >>td> tr> table> input type="submit" value="login" /> input type="hidden" name="next" value=" <next >>" /> form> p>a href=" url 'password_reset' %>">Lost password?a>p> endblock %>
Этот шаблон имеет сходство с тем, что мы видели раньше — он расширяет наш базовый шаблон и переопределяет блок контента. Остальная часть кода — это довольно стандартный код обработки формы, о котором мы поговорим в следующем учебном пособии. Все, что вам нужно знать, это показ формы, в которой вы можете ввести своё имя пользователя и пароль, а если вы введёте недопустимые значения, вам будет предложено ввести правильные значения, когда страница обновится.
Перейдите на страницу входа ( http://127.0.0.1:8000/accounts/login/ ) когда вы сохраните свой шаблон, и вы должны увидеть что-то наподобие этого:

Если ваша попытка войти в систему будет успешной, вы будете перенаправлены на другую страницу (по умолчанию это будет http://127.0.0.1:8000/accounts/profile/ ). Проблема здесь в том, что по умолчанию Django ожидает, что после входа в систему вы захотите перейти на страницу профиля, что может быть или не быть. Поскольку вы ещё не определили эту страницу, вы получите ещё одну ошибку!
Откройте настройки проекта (/locallibrary/locallibrary/settings.py) и добавьте текст ниже. Теперь, когда вы входите в систему, вы по умолчанию должны перенаправляться на домашнюю страницу сайта.
# Redirect to home URL after login (Default redirects to /accounts/profile/) LOGIN_REDIRECT_URL = '/'
Шаблон выхода
Если вы перейдёте по URL-адресу выхода ( http://127.0.0.1:8000/accounts/logout/ ), то увидите странное поведение — ваш пользователь наверняка выйдет из системы, но вы попадёте на страницу выхода администратора. Это не то, что вам нужно, хотя бы потому, что ссылка для входа на этой странице приведёт вас к экрану входа в систему администратора. (и это доступно только для пользователей, у которых есть разрешение is_staff ).
Создайте и откройте /locallibrary/templates/registration/logged_out.html. Скопируйте текст ниже:
extends "base_generic.html" %> block content %> p>Logged out!p> a href=" url 'login'%>">Click here to login again.a> endblock %>
Этот шаблон очень прост. Он просто отображает сообщение, информирующее вас о том, что вы вышли из системы, и предоставляет ссылку, которую вы можете нажать, чтобы вернуться на экран входа в систему. Если вы снова перейдёте на страницу выхода из системы, вы увидите эту страницу:
Шаблон сброса пароля
Система сброса пароля по умолчанию использует электронную почту, чтобы отправить пользователю ссылку на сброс. Вам необходимо создать формы, чтобы получить адрес электронной почты пользователя, отправить электронное письмо, разрешить им вводить новый пароль и отметить, когда весь процесс будет завершён.
В качестве отправной точки можно использовать следующие шаблоны.
Форма сброса пароля
Это форма, используемая для получения адреса электронной почты пользователя (для отправки пароля для сброса пароля). Создайте /locallibrary/templates/registration/password_reset_form.html и дайте ему следующее содержание:
extends "base_generic.html" %> block content %> form action="" method="post"> csrf_token %> if form.email.errors %> <form.email.errors >> endif %> p> <form.email >>p> input type="submit" class="btn btn-default btn-lg" value="Reset password" /> form> endblock %>
Сброс пароля
Эта форма отображается после того, как ваш адрес электронной почты будет собран. Создайте /locallibrary/templates/registration/password_reset_done.html, и дайте ему следующее содержание:
extends "base_generic.html" %> block content %> p> We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder. p> endblock %>
Сброс пароля по email
Этот шаблон предоставляет текст электронной почты HTML, содержащий ссылку на сброс, которую мы отправим пользователям. Создайте /locallibrary/templates/registration/password_reset_email.html и дайте ему следующее содержание:
email >>. Follow the link below: protocol>>:// domain >> url 'password_reset_confirm' uidb64=uid token=token %>
Подтверждение на сброс пароля
На этой странице вы вводите новый пароль после нажатия ссылки в электронном письме с возвратом пароля. Создайте /locallibrary/templates/registration/password_reset_confirm.html и дайте ему следующее содержание:
extends "base_generic.html" %> block content %> if validlink %> p>Please enter (and confirm) your new password.p> form action="" method="post"> csrf_token %> table> tr> td> <form.new_password1.errors >> label for="id_new_password1">New password:label> td> td> <form.new_password1 >>td> tr> tr> td> <form.new_password2.errors >> label for="id_new_password2">Confirm password:label> td> td> <form.new_password2 >>td> tr> tr> td>td> td>input type="submit" value="Change my password" />td> tr> table> form> else %> h1>Password reset failedh1> p> The password reset link was invalid, possibly because it has already been used. Please request a new password reset. p> endif %> endblock %>
Сброс пароля завершён
Это последний шаблон сброса пароля, который отображается, чтобы уведомить вас о завершении сброса пароля. Создайте /locallibrary/templates/registration/password_reset_complete.html и дайте ему следующее содержание:
extends "base_generic.html" %> block content %> h1>The password has been changed!h1> p>a href=" url 'login' %>">log in again?a>p> endblock %>
Тестирование новых страниц аутентификации
Теперь, когда вы добавили конфигурацию URL и создали все эти шаблоны, теперь страницы аутентификации должны работать! Вы можете протестировать новые страницы аутентификации, попытавшись войти в систему, а затем выйдите из учётной записи суперпользователя, используя эти URL-адреса:
- http://127.0.0.1:8000/accounts/login/
- http://127.0.0.1:8000/accounts/logout/
Вы сможете проверить функцию сброса пароля по ссылке на странице входа. Имейте в виду, что Django отправляет только сбросные электронные письма на адреса (пользователи), которые уже хранятся в его базе данных!
Примечание: Система сброса пароля требует, чтобы ваш сайт поддерживал электронную почту, что выходит за рамки этой статьи, поэтому эта часть ещё не будет работать. Чтобы разрешить тестирование, поместите следующую строку в конец файла settings.py. Это регистрирует любые письма, отправленные на консоль (чтобы вы могли скопировать ссылку на сброс пароля с консоли).
= 'django.core.mail.backends.console.EmailBackend'
Для получения дополнительной информации см. Отправка email (Django docs).
Тестирование проверки подлинности пользователей
В этом разделе мы рассмотрим, что мы можем сделать, чтобы выборочно контролировать контент, который видят пользователи, на основе того, вошли ли они в систему или нет.
Тестирование в шаблонах
Вы можете получить информацию о текущем зарегистрированном пользователе в шаблонах с переменной шаблона > (это добавляется в контекст шаблона по умолчанию при настройке проекта, как и в нашем скелете).
Обычно вы сначала проверяете переменную шаблона >, чтобы определить, имеет ли пользователь право видеть конкретный контент. Чтобы продемонстрировать это, мы обновим нашу боковую панель, чтобы отобразить ссылку «Вход», если пользователь вышел из системы, и ссылку «Выход», если он вошёл в систему.
Откройте базовый шаблон (/locallibrary/catalog/templates/base_generic.html) и скопируйте следующий текст в sidebar блок непосредственно перед тегом шаблона endblock.
ul class="sidebar-nav"> ... % if user.is_authenticated %> li>User: user.get_username >>/li> li>a href="?next=>">Logout/a>/li> % else %> li>a href="?next=>">Login/a>/li> % endif %> /ul>
Как вы можете видеть, мы используем теги шаблона if-else-endif для условного отображения текста на основе того, является ли > истинным. Если пользователь аутентифицирован, мы знаем, что у нас есть действительный пользователь, поэтому мы вызываем >, чтобы отобразить их имя.
Мы создаём URL-адрес для входа и выхода из системы, используя тег шаблона URL-адреса и имена соответствующих конфигураций URLs. Также обратите внимание на то, как мы добавили ?next=> в конец URLs. Это означает, что следующий URL-адрес содержит адрес (URL) текущей страницы, в конце связанного URL-адреса. После того, как пользователь успешно выполнил вход в систему, представления будут использовать значение » next » чтобы перенаправить пользователя обратно на страницу, где они сначала нажали ссылку входа / выхода из системы.
Примечание: Попробуйте! Если вы находитесь на главной странице и вы нажимаете «Вход / Выход» на боковой панели, то после завершения операции вы должны вернуться на ту же страницу.
Тестирование в представлениях
Если вы используете функциональные представления, самым простым способом ограничить доступ к вашим функциям является применение login_required декоратор к вашей функции просмотра, как показано ниже. Если пользователь вошёл в систему, ваш код просмотра будет выполняться как обычно. Если пользователь не вошёл в систему, это перенаправит URL-адрес входа, определённый в настройках проекта. ( settings.LOGIN_URL ), передав текущий абсолютный путь в качестве next параметра URL. Если пользователю удастся войти в систему, они будут возвращены на эту страницу, но на этот раз аутентифицированы.
from django.contrib.auth.decorators import login_required @login_required def my_view(request): ...
Примечание: Вы можете сделать то же самое вручную, путём тестирования request.user.is_authenticated , но декоратор намного удобнее!
Аналогичным образом, самый простой способ ограничить доступ к зарегистрированным пользователям в ваших представлениях на основе классов — это производные от LoginRequiredMixin . Вы должны объявить этот mixin сначала в списке суперкласса, перед классом основного представления.
from django.contrib.auth.mixins import LoginRequiredMixin class MyView(LoginRequiredMixin, View): ...
Это имеет такое же поведение при переадресации, что и login_required декоратор. Вы также можете указать альтернативное местоположение для перенаправления пользователя, если он не аутентифицирован ( login_url ), и имя параметра URL вместо » next » , чтобы вставить текущий абсолютный путь ( redirect_field_name ).
class MyView(LoginRequiredMixin, View): login_url = '/login/' redirect_field_name = 'redirect_to'
Для получения дополнительной информации ознакомьтесь с Django docs here.
Пример — перечисление книг текущего пользователя
Теперь, когда мы знаем, как ограничить страницу определённому пользователю, создайте представление о книгах, которые заимствовал текущий пользователь.
К сожалению, у нас пока нет возможности пользователям использовать книги! Поэтому, прежде чем мы сможем создать список книг, мы сначала расширим BookInstance модель для поддержки концепции заимствования и использования приложения Django Admin для заимствования ряда книг нашему тестовому пользователю.
Модели
Прежде всего, мы должны предоставить пользователям возможность кредита на BookInstance (у нас уже есть status и due_back дата, но у нас пока нет связи между этой моделью и пользователем. Мы создадим его с помощью поля ForeignKey (один ко многим). Нам также нужен простой механизм для проверки того, просрочена ли заёмная книга.
Откройте catalog/models.py, и импортируйте модель User из django.contrib.auth.models (добавьте это чуть ниже предыдущей строки импорта в верхней части файла, так User доступен для последующего кода, что позволяет использовать его):
from django.contrib.auth.models import User
Затем добавьте поле borrower в модель BookInstance :
= models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
Пока мы здесь, давайте добавим свойство, которое мы можем вызвать из наших шаблонов, чтобы указать, просрочен ли конкретный экземпляр книги. Хотя мы могли бы рассчитать это в самом шаблоне, использование свойства, как показано ниже, будет намного более эффективным. Добавьте это где-нибудь в верхней части файла:
from datetime import date
Теперь добавьте следующее определение свойства внутри класса BookInstance:
@property def is_overdue(self): if self.due_back and date.today() > self.due_back: return True return False
Примечание: Сначала мы проверим, является ли due_back пустым, прежде чем проводить сравнение. Пустое поле due_back заставило Django выкидывать ошибку, а не показывать страницу: пустые значения не сопоставимы. Это не то, что мы хотели бы, чтобы наши пользователи испытывали!
Теперь, когда мы обновили наши модели, нам нужно будет внести новые изменения в проект, а затем применить эти миграции:
Admin
Теперь откройте каталог catalog/admin.py, и добавьте поле
borrowerв классBookInstanceAdmin, как вlist_display, так и в поляхfieldsets, как показано ниже. Это сделает поле видимым в разделе Admin, так что мы можем при необходимости назначитьUserвBookInstance.python
@admin.register(BookInstance) class BookInstanceAdmin(admin.ModelAdmin): list_display = ('book', 'status', 'borrower', 'due_back', 'id') list_filter = ('status', 'due_back') fieldsets = ( (None, 'fields': ('book','imprint', 'id') >), ('Availability', 'fields': ('status', 'due_back','borrower') >), )Займите несколько книг
Теперь, когда возможно кредитовать книги конкретному пользователю, зайдите и заработайте на нескольких записей в BookInstance . Установите borrowed поле вашему тестовому пользователю, сделайте status «В займе» и установите сроки оплаты как в будущем, так и в прошлом.
Примечание: Мы не будем описывать процесс, так как вы уже знаете, как использовать Admin сайт!
Займ в представлении
Теперь мы добавим представление для получения списка всех книг, которые были предоставлены текущему пользователю. Мы будем использовать один и тот же общий класс, с которым мы знакомы, но на этот раз мы также будем импортировать и выводить из LoginRequiredMixin , так что только вошедший пользователь сможет вызвать это представление. Мы также решили объявить template_name , вместо того, чтобы использовать значение по умолчанию, потому что у нас может быть несколько разных списков записей BookInstance, с разными представлениями и шаблонами.
Добавьте следующее в catalog/views.py:
from django.contrib.auth.mixins import LoginRequiredMixin class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView): """ Generic class-based view listing books on loan to current user. """ model = BookInstance template_name ='catalog/bookinstance_list_borrowed_user.html' paginate_by = 10 def get_queryset(self): return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')Чтобы ограничить наш запрос только объектами BookInstance для текущего пользователя, мы повторно реализуем get_queryset() , как показано выше. Обратите внимание, что "o" это сохранённый код для "on loan" и мы сортируем по дате due_back , чтобы сначала отображались самые старые элементы.
URL-адрес для заёмных книг
Теперь откройте /catalog/urls.py и добавьте url() , указывая на приведённое выше представление (вы можете просто скопировать текст ниже в конец файла).
+= [ url(r'^mybooks/$', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'), ]Шаблон для заёмных книг
Теперь все, что нам нужно сделать для этой страницы, - это добавить шаблон. Сначала создайте файл шаблона /catalog/templates/catalog/bookinstance_list_borrowed_user.html и дайте ему следующее содержание:
% extends "base_generic.html" %> % block content %> h1>Borrowed books/h1> % if bookinstance_list %> ul> % for bookinst in bookinstance_list %> li class="text-danger"> a href="">bookinst.book.title>>/a> ( bookinst.due_back >>) /li> % endfor %> /ul> % else %> p>There are no books borrowed./p> % endif %> % endblock %>Этот шаблон очень похож на тот, который мы создали ранее для объектов Book и Author . Единственное, что «новое» здесь, это то, что мы проверяем метод, который мы добавили в модель (bookinst.is_overdue ) с целью использовать его для изменения цвета просроченных предметов.
Когда сервер разработки запущен, вы должны теперь иметь возможность просматривать список для зарегистрированного пользователя в своём браузере по адресу http://127.0.0.1:8000/catalog/mybooks/ . Попробуйте это, когда ваш пользователь войдёт в систему и выйдет из системы (во втором случае вы должны быть перенаправлены на страницу входа в систему).
Добавить список на боковую панель
Последний шаг - добавить ссылку на эту новую страницу в sidebar. Мы поместим это в тот же раздел, где мы покажем другую информацию для зарегистрированного пользователя.
Откройте базовый шаблон (/locallibrary/catalog/templates/base_generic.html) и добавьте выделенную строку из sidebar, как показано на рисунке.
ul class="sidebar-nav"> % if user.is_authenticated %> li>User: user.get_username >>/li> li>a href="">My Borrowed/a>/li> li>a href="?next=>">Logout/a>/li> % else %> li>a href="?next=>">Login/a>/li> % endif %> /ul>На что это похоже?
Когда любой пользователь войдёт в систему, он будет видеть ссылку «Мной позаимствовано (My Borrowed)» в боковой колонке, и список книг, показанных ниже (первая книга не имеет установленной даты, что является ошибкой, которую мы надеемся исправить в более позднем уроке!).
Права доступа
Права доступа связаны с моделями и определяют операции, которые могут выполняться на экземпляре модели самим пользователем, у которого есть разрешение. По умолчанию Django автоматически даёт добавить, изменить, и удалить разрешения у всех моделей, которые позволяют пользователям с правом доступа выполнять связанные действия через администратора сайта. Вы можете определить свои собственные разрешения для моделей и предоставить их конкретным пользователям. Вы также можете изменить разрешения, связанные с разными экземплярами одной и той же модели. Тестирование разрешений в представлениях и шаблонах очень похоже на тестирование по статусу аутентификации (фактически, тестирование прав доступа также проверяет аутентификацию).
Модели
Определение разрешений выполняется в разделе моделей " class Meta " , используется permissions поле. Вы можете указать столько разрешений, сколько необходимо в кортеже, причём каждое разрешение определяется во вложенном кортеже, содержащем имя разрешения и отображаемое значение разрешения. Например, мы можем определить разрешение, позволяющее пользователю отметить, что книга была возвращена, как показано здесь:
class BookInstance(models.Model): ... class Meta: ... permissions = (("can_mark_returned", "Set book as returned"),)Затем мы могли бы назначить разрешение группе «Библиотекарь» (Librarian) на сайте администратора.
Откройте catalog/models.py, и добавьте разрешение, как показано выше. Вам нужно будет повторно выполнить миграцию (вызвав python3 manage.py makemigrations и python3 manage.py migrate ) для надлежащего обновления базы данных.
Шаблоны
Разрешения текущего пользователя хранятся в переменной шаблона, называемой > . Вы можете проверить, имеет ли текущий пользователь определённое разрешение, используя конкретное имя переменной в соответствующем приложении «Django» - например, > будет True если у пользователя есть это разрешение, а False - в противном случае. Обычно мы проверяем разрешение с использованием шаблона , как показано в:
% if perms.catalog.can_mark_returned %> !-- We can mark a BookInstance as returned. --> !-- Perhaps add code to link to a "book return" view here. --> % endif %>Представления
Разрешения можно проверить в представлении функции, используя permission_required декоратор или в представлении на основе классов, используя PermissionRequiredMixin . шаблон и поведение такие же, как для аутентификации входа в систему, хотя, конечно, вы можете разумно добавить несколько разрешений.
Функция в представлении с декоратором:
from django.contrib.auth.decorators import permission_required @permission_required('catalog.can_mark_returned') @permission_required('catalog.can_edit') def my_view(request): ...Требуется разрешение mixin для представлений на основе классов.
from django.contrib.auth.mixins import PermissionRequiredMixin class MyView(PermissionRequiredMixin, View): permission_required = 'catalog.can_mark_returned' # Or multiple permissions permission_required = ('catalog.can_mark_returned', 'catalog.can_edit') # Note that 'catalog.can_edit' is just an example # the catalog application doesn't have such permission!Пример
Мы не будем обновлять LocalLibrary здесь; возможно, в следующем уроке!
Испытайте себя
Ранее в этой статье мы показали вам, как создать страницу для текущего пользователя, в которой перечислены книги, которые они заимствовали. Теперь задача состоит в том, чтобы создать аналогичную страницу, которая видна только для библиотекарей, которая отображает все книги, которые были заимствованы, и которая показывает имя каждого заёмщика.
Вы должны следовать той же схеме, что и для другого представления. Главное отличие состоит в том, что вам нужно ограничить представление только библиотекарями. Вы можете сделать это на основе того, является ли пользователь сотрудником (декоратор функции: staff_member_required , переменная шаблона: user.is_staff ) но мы рекомендуем вам вместо этого использовать can_mark_returned разрешения и PermissionRequiredMixin , как описано в предыдущем разделе.
Предупреждение: Важно: Не забудьте использовать вашего суперпользователя для тестирования на основе разрешений (проверки разрешений всегда возвращают true для суперпользователей, даже если разрешение ещё не определено!). Вместо этого создайте пользователя-библиотекаря и добавьте необходимые возможности.
Когда вы закончите, ваша страница должна выглядеть примерно, как на скриншоте ниже.
Подводим итоги
Отличная работа - теперь вы создали веб-сайт, на котором участники библиотеки могут входить в систему и просматривать собственный контент, и библиотекари (с правом доступа) могут просматривать все заёмные книги с их читателями. На данный момент мы все ещё просто просматриваем контент, но те же принципы и методы используются, когда вы хотите начать изменять и добавлять данные.
В следующей статье мы рассмотрим, как вы можете использовать формы Django для сбора пользовательского ввода, а затем начнём изменять некоторые из наших сохранённых данных.
Смотрите также
- User authentication in Django (Django docs)
- Using the (default) Django authentication system (Django docs)
- Introduction to class-based views > Decorating class-based views (Django docs)
- Назад
- Обзор: Django
- Далее
Found a content problem with this page?
- Edit the page on GitHub.
- Report the content issue.
- View the source on GitHub.
This page was last modified on 3 авг. 2023 г. by MDN contributors.
Your blueprint for a better internet.
Пользовательская модель User
Каждый новый проект Django должен использовать пользовательскую модель User. Официальная документация Django гласит, что это «настоятельно рекомендуется», но я сделаю еще один шаг и без колебаний скажу: вы просто с ума сошли, если не использовали пользовательскую модель раньше.
Зачем? Потому что вам придется внести изменения в пользователя в какой-то момент в жизни вашего проекта - добавить поле даты рождения, возраст, что угодно - и если вы не начали с пользовательской модели User до самой первой выполненной вами команды переноса, тогда вы попадете в мир боли.
Однако, если вы используете пользовательскую модель, вы можете легко добавлять и изменять ее.
Можно ли переключиться на пользовательскую модель в середине проекта? Да. Хочешь ли ты это сделать? Лучше не делать.
Вот самый простой способ, чтобы начать каждый новый проект с правильного пути.
Шаг 1. Создание нового проекта
В командной строке перейдите в новый каталог для своих проектов, используйте Pipenv для установки Django, активируйте виртуальную среду и создайте новый проект с именем new_project . Давайте предположим, что мы хотим использовать папку code в Desktop , так пример на Mac.
$ cd ~/Desktop $ mkdir code && cd code $ pipenv install django $ pipenv shell (code) $ django-admin startproject new_project .
Теперь нам нужно создать приложение пользователя, а затем обновить 4 файла. Готовы?
Шаг 2. Создание приложения пользователя
(code) $ python manage.py startapp users
Теперь давайте расскажем Django о новом приложении и обновим AUTH_USER_MODEL , чтобы Django знал, что нужно использовать нашу новую модель CustomUser вместо модели User по умолчанию.
Откройте new_project/settings.py в текстовом редакторе и внесите следующие два изменения:
# new_project/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', # Local 'users.apps.UsersConfig', # новое ] . AUTH_USER_MODEL = 'users.CustomUser' # новое
Шаг 3. Модель CustomUser
Мы хотим расширить (или скопировать) существующую модель User и назвать ее как-то иначе, в нашем случае CustomUser . Это все, что нам нужно сделать. Просто сделайте копию, и тогда мы сможем настроить ее так, как нам нравится, но при этом использовать все преимущества встроенного User .
Нам даже не нужно добавлять поле на этом этапе!
# users/models.py from django.contrib.auth.models import AbstractUser from django.db import models class CustomUser(AbstractUser): pass # add additional fields in here
Шаг 4: Обновление форм
Django использует модель User - теперь нашу модель CustomUser , поскольку мы указали ее в AUTH_USER_MODEL повсюду. Два основных места - это когда создается новый пользователь и когда мы что-то меняем у пользователя. Поэтому мы должны снова расширить встроенные формы для этого и указать их для нашей новой модели CustomUser .
Создайте новый файл users/forms.py и заполните его следующим текстом:
# users/forms.py from django import forms from django.contrib.auth.forms import UserCreationForm, UserChangeForm from .models import CustomUser class CustomUserCreationForm(UserCreationForm): class Meta(UserCreationForm): model = CustomUser fields = ('username', 'email') class CustomUserChangeForm(UserChangeForm): class Meta: model = CustomUser fields = ('username', 'email')
Шаг 5: Обновление admin.py
Модель Django User тесно связана с превосходным встроенным приложением администратора admin , поэтому мы должны указать Django использовать вместо этого CustomUser . Вот как:
# users/admin.py from django.contrib import admin from django.contrib.auth import get_user_model from django.contrib.auth.admin import UserAdmin from .forms import CustomUserCreationForm, CustomUserChangeForm from .models import CustomUser class CustomUserAdmin(UserAdmin): add_form = CustomUserCreationForm form = CustomUserChangeForm model = CustomUser list_display = ['email', 'username',] admin.site.register(CustomUser, CustomUserAdmin)
Всё.
И это все. Создайте файл миграции для наших изменений, а затем впервые запустите миграцию, чтобы инициализировать нашу базу данных с помощью CustomUser вместо User .
(code) $ python manage.py makemigrations users (code) $ python manage.py migrate
Поздравляем! Ваш проект Django рассчитан на будущее и вы можете продолжить работу без проблем.
Расширение модели User
При работе с учетными записями пользователей вы узнаете, что модель User механизма аутентификации с помощью Джанго подходит для распространенных случаев. Однако модель User поставляется с довольно базовыми возможностями. Пользователь может расширить модель User, включив в нее дополнительные данные. Лучшим способом для этого является создание модели профиля, которая содержит все дополнительные поля и связь «один к одному» с моделью User.
Откройте файл models.py приложения account и внесите в него следующий код:
from django.db import models from django.conf import settings class Profile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL) date_of_birth = models.DateField(blank=True, null=True) photo = models.ImageField(upload_to='users/%Y/%m/%d', blank=True) def __str__(self): return 'Profile for user <>'.format(self.user.username)
In order to keep your code generic, use the get_user_model() method to retrieve the user model and the AUTH_USER_MODEL setting to refer to it when defining model's relations to the user model, instead of referring to the auth User model directly.
Связь «один к одному» позволяет связывать профили с пользователями. Поле photo является полем ImageField . Вам потребуется установить один из пакетов Python для управления изображениями. Установите Pillow, запустив в терминале следующую команду:
pip install Pillow==2.9.0
Для обслуживания файлов мультимедиа, загруженных пользователями с сервероа разработки, добавьте следующие параметры в файл settings.py проекта:
MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media/')
MEDIA_URL — это базовый URL-адрес для обслуживания файлов мультимедиа, отправляемых пользователями, а MEDIA_ROOT — локальный путь, в котором они находятся. Мы динамически строим путь относительно нашего пути проекта, чтобы сделать код более универсальным.
Отредактируйте основной файл urls.py проекта bookmarks и добавьте в него следующий код:
from django.conf.urls import include, url from django.contrib import admin from django.conf import settings from django.conf.urls.static import static urlpatterns = [ url(r'^admin/', include(admin.site.urls)), url(r'^account/', include('account.urls')), ] if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Таким образом, сервер разработки Джанго будет отвечать за службу мультимедийных файлов во время разработки.
Вспомогательная функция static() подходит для разработки, но не для использования в продакшн версии.Никогда не обслуживайте статические файлы с Джанго в продакшн версии.
Откройте оболочку и выполните следующую команду, чтобы создать миграцию базы данных для новой модели:
python manage.py makemigrations
Вы увидите следующее:
Migrations for 'account': 0001_initial.py: - Create model Profile
Затем синхронизируйте базу данных следующей командой:
python manage.py migrate
Вы увидите следующее:
Applying account.0001_initial. OK
Измените файл admin.py приложения account и зарегистрируйте модель Profile на сайте администрирования:
from django.contrib import admin from .models import Profile class ProfileAdmin(admin.ModelAdmin): list_display = ['user', 'date_of_birth', 'photo'] admin.site.register(Profile, ProfileAdmin)
Запустите сервер разработки снова с помощью команды python manage.py runserver . Теперь вы можете видеть модель Profile в административной части сайта вашего проекта:

Теперь мы позволим пользователям редактировать свой профиль на веб-сайте. Добавьте следующие модели формы в файл forms.py приложения account:
from .models import Profile class UserEditForm(forms.ModelForm): class Meta: model = User fields = ('first_name', 'last_name', 'email') class ProfileEditForm(forms.ModelForm): class Meta: model = Profile fields = ('date_of_birth', 'photo')
Немного о коде выше:
- UserEditForm : Позволит пользователям изменять свое имя, фамилию и электронную почту, хранящиеся во встроенной пользовательской модели.
- ProfileEditForm : Позволит пользователям редактировать дополнительные данные, сохраняемые в пользовательской модели Profile. Пользователи смогут изменить дату рождения и отправить фотографию для своего профиля.
Отредактируйте файл views.py приложения account и сделайте импорт модели Profile:
from .models import Profile
И добавьте следующие строки в представление register под new_user.save():
# Create the user profile profile = Profile.objects.create(user=new_user)
Когда пользователи регистрируются на нашем сайте, мы создаем пустой профиль, связанный с ними. Необходимо создать объект Profile вручную с помощью административной части сайта для созданных ранее пользователей.
Теперь мы позволим пользователям редактировать их профиль. Добавьте следующий код в тот же файл:
from .forms import LoginForm, UserRegistrationForm, UserEditForm, ProfileEditForm @login_required def edit(request): if request.method == 'POST': user_form = UserEditForm(instance=request.user, data=request.POST) profile_form = ProfileEditForm(instance=request.user.profile, data=request.POST, files=request.FILES) if user_form.is_valid() and profile_form.is_valid(): user_form.save() profile_form.save() else: user_form = UserEditForm(instance=request.user) profile_form = ProfileEditForm(instance=request.user.profile) return render(request, 'account/edit.html', 'user_form': user_form, 'profile_form': profile_form>)
Мы используем декоратор login_required, так как пользователи должны авторизоваться для редактирования своего профиля. В этом случае используются две модели форм: UserEditForm для хранения данных встроенной модели User и ProfileEditForm для хранения дополнительных данных профиля. Чтобы проверить представленные данные, мы проверяем, что метод is_valid() обеих форм возвращает значение true. В этом случае мы сохраняем обе формы для обновления соответствующего объекта в базе данных.
Добавьте новый URL шаблон в файл urls.py приложения account:
url(r'^edit/$', views.edit, name='edit'),
Наконец, создайте шаблон для этого представления в templates/account/ и назовите его edit.html. Добавьте в него следующий код:
Edit your account
Edit your account
You can edit your account using the following form:
> >
We include enctype="multipart/form-data" in our form to enable file uploads. We use one HTML form to submit both the user_form and the profile_form forms.
Зарегистрируйте нового пользователя и пройдите по адресу http://127.0.0.1:8000/account/edit/ . Вы увидите следующую страницу:

Теперь можно также отредактировать страницу панели мониторинга и включить ссылки для редактирования страниц профиля и смены пароля. Откройте шаблон account/dashboard.html и замените эту строку:
Welcome to your dashboard.
Welcome to your dashboard. You can ">edit your profile or ">change your password.
Теперь пользователи могут получить доступ к форме для редактирования профиля в панели управления.

