Django 5 для начинающих

Прогресс по курсу:  9/1004

7.4 Профили пользователей и пользовательские поля модели User
5 из 8 шагов пройдено
0 из 15 баллов  получено

Пользовательские поля модели User

Модель Django по умолчанию User(то есть класс) использует django.contrib.auth.models.User минимальный набор полей данных которые мы рассмотрели в прошлых разделах.

Хотя этих последних полей достаточно для встроенной пользовательской функциональности Django, их может не хватить, если вы ожидаете хранить дополнительные пользовательские данные (например, возраст, телефон, адрес).

Существует два подхода к поддержке дополнительных пользовательских данных: создать отдельную модель для хранения дополнительных данных и создать к ней отношение пользователя (т. е. User с OneToOneField) или переопределить django.contrib.auth.models.User класс по умолчанию для создания пользовательского класса.

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

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

 

Создание профиля

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

Прежде всего, давайте создадим представление профиля внутри accounts/views.py.:

from django.shortcuts import render
from django.contrib.auth.decorators import login_required


@login_required
def profile(request):
    return render(request, 'registration/profile.html')

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

  • Декоратор login_required ограничивает доступ для зарегистрированных пользователей.

  • Пользователь, не вошедший в систему, не может получить доступ к странице профиля. Если пользователь попытается это сделать, login_required() он будет перенаправлен на settings.LOGIN_URL(который мы добавим в файл настройки проекта), передав текущий абсолютный путь в строке запроса.
    Пример: /login/?next=/profile/.

  • Как видно из примера пути, функция отслеживает, к какой странице пытается получить доступ пользователь. Следовательно, он перенаправит пользователя на страницу профиля, которую он запросил в первую очередь после успешной аутентификации.

Откройте пользовательское приложение accounts и в файл urls.py и добавьте маршрут для просмотра профиля:

from django.urls import path
from .views import SignUpView, CustomLoginView, profile
from django.contrib.auth import views as auth_views


urlpatterns = [
    path("signup/", SignUpView.as_view(), name="signup"),
    path('login/', CustomLoginView.as_view(redirect_authenticated_user=True, template_name='registration/login.html'), name='login'),
    path('logout/', auth_views.LogoutView.as_view(template_name='registration/logout.html'), name='logout'),
    path('profile/', profile, name='users-profile'),

]

 Создайте шаблон для представления в каталоге шаблонов приложений пользователей - registration/profile.html:

{% extends "blog/base.html" %}
{% block title %}Profile Page{% endblock title %}
{% block content %}
    <div>
        <h1>This is the profile page for {{user.username}}</h1>
    </div>

{% endblock content %}

Мы изменим этот шаблон позже, чтобы отобразить профиль пользователя, но сначала нам нужно сделать пару вещей.

Расширение пользовательской модели с использованием связи «один-к-одному»

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

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

В Django мы можем создавать отношения один к одному между моделями, используя OneToOneField поле модели. Подробнее мы изучали это в разделе 3.4 "Организация связей между таблицами" данного курса.

В отношениях «один-к-одному» одна запись в таблице связана с одной и только одной записью в другой таблице с использованием внешнего ключа. Пример — экземпляр модели пользователя связан с одним и только одним экземпляром профиля.

Хорошо, давайте создадим модель профиля с двумя полями: аватар (изображение профиля) и биографию. Вы можете добавить больше, если хотите.

Добавим в наши модели файла accounts/models.py следующий код:

from django.db import models
from django.contrib.auth.models import User


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)

    avatar = models.ImageField(default='default.jpg', upload_to='profile_images')
    bio = models.TextField()

    def __str__(self):
        return self.user.username

Первый аргумент OneToOneField указывает, к какой модели будет относиться текущая модель, в нашем случае это модель User.

Второй аргумент on_delete=models.CASCADE означает, что при удалении пользователя удаляется и его/ее профиль.

Далее мы указываем что у пользователя будет свой аватар аргументом ImageFielddefault='default.jpg' — это изображение по умолчанию, которое пользователь может использовать, если он не загружает его самостоятельно.

Второй аргумент upload_to='profile_images' - это каталог, в который загружаются изображения. bio — это просто текстовое поле, в котором хранится некоторая информация о пользователях.

Django требует от нас установки pillow библиотеки всякий раз, когда мы работаем с ImageField, поэтому перейдите в свой терминал и введите следующее:

pip install pillow==9.2.0

Чтобы изменения вступили в силу внутри нашей базы данных, давайте запустим миграции:

python manage.py makemigrations
python manage.py migrate

Еще один важный шаг — зарегистрировать модель профиля в пользовательском приложении accounts/admin.py:

from accounts.models import Profile
from django.contrib import admin

admin.site.register(Profile)

Приведенный выше код импортирует модель профиля, а затем вызывает admin.site.register ее для регистрации.

Теперь вы можете войти в панель администратора и увидеть созданную нами модель:


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

Еще один важный шаг — зарегистрировать модель профиля в пользовательском приложении accounts/admin.py:

from accounts.models import Profile


admin.site.register(Profile)

Забыли добавить:

from django.contrib import admin
Изменен Александр Павлов

@Александр_Павлов, спасибо, добавил.

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

Ошибка в тексте

@Дмитрий_Харламов, спасибо, исправил.

Может быть, Вы имели в виду зарегистрировать Profile в приложении accounts? Судя по скриншоту и следуя логике)

@Кирилл_Семенихин, Исправили.

Здравствуйте, только сейчас увидел через админку, что не сохраняются email  адреса, хотя код точно такой же как у вас, может это нормально, я не знаю просто 

@Шамбер_Егор

@Шамбер_Егор,  почему то при добавлении этой функции в форму перестает работать сохранение email адреса 

def clean_email(self):
email = self.cleaned_data['email']
users = get_user_model() # передаем модель User
if users.objects.filter(email=email).exists():
raise ValidationError(f"Entered email {email} already used, please use another one")
else:
self.cleaned_data['email'] = email

@Шамбер_Егор, функция clean_email должна же возвращать email

@Илья_Перминов,  спасибо

Смотрите у ваших лекция уже отсутствуют пути куда что нужно добавлять это вводит в ступор, пожалуйста найдите время и подправьте это!


 

Хорошо, давайте создадим модель профиля с двумя полями: аватар (изображение профиля) и биографию. Вы можете добавить больше, если хотите.

Добавим в наши модели следующий код:

from django.db import models
from django.contrib.auth.models import User


class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)

    avatar = models.ImageField(default='default.jpg', upload_to='profile_images')
    bio = models.TextField()

    def __str__(self):
        return self.user.username
Изменен No Name

@No_Name, Спасибо, поправил.