Профиль пользователя состоит из настроек и информации, связанной с пользователем. Рассмотрим, как разрешить пользователям обновлять свои профили в приложениях Django в Python.
Установка пакета Pillow
Поскольку мы будем работать с изображениями, нам необходимо установить пакет Pillow с помощью следующей команды pip:
pip install Pillow
Настройка каталога для хранения загруженных изображений
Сначала создайте в проекте каталог мультимедиа:
mkdir media
Во-вторых, добавьте MEDIA_ROOT и MEDIA_URL в settings.py проекта:
MEDIA_ROOT = BASE_DIR / 'media' MEDIA_URL = '/media/'
MEDIA_ROOT указывает каталог, в котором хранится загруженное изображение. MEDIA_URL указывает URL, который обслуживает файлы изображений из каталога MEDIA_ROOT.
В-третьих, добавьте URL-адрес, обслуживающий медиа-файлы, в urls.py проекта следующим образом:
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('',include('todo.urls')),
path('',include('users.urls'))
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.MEDIA_ROOT)
Если в файле settings.py параметр DEBUG имеет значение True, приложение Django будет обслуживать медиафайлы с MEDIA_URL.
Создание модели профиля
Измените models.py приложения пользователя и определите модель профиля следующим образом:
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(
default="avatar.jpg", # default avatar
upload_to='profile_avatars' # dir to store the image
)
def __str__(self):
return f'{self.user.username} Profile'
def save(self, *args, **kwargs):
# save the profile first
super().save(*args, **kwargs)
# resize the image
img = Image.open(self.avatar.path)
if img.height > 300 or img.width > 300:
output_size =(300, 300)
# create a thumbnail
img.thumbnail(output_size)
# overwrite the larger image
img.save(self.avatar.path)
Как это работает.
- Сначала определим модель Profile, унаследованную от класса Model:
class Profile(models.Model):
- Во-вторых, у каждого пользователя есть профиль, а каждый профиль принадлежит пользователю. Таким образом, связь между моделью User и моделью Profile является один-к-одному.
Для определения отношения «один к одному» используется OneToOneField:
user = models.OneToOneField(User, on_delete=models.CASCADE)
Если пользователь удаляется, профиль, связанный с пользователем, также удаляется. Это указано в параметре on_delete=models.CASCADE OneToOneField().
- В-третьих, определите поле аватара, которое содержит аватар пользователя:
avatar = models.ImageField(
default="avatar.jpg", # default avatar
upload_to='profile_avatars' # dir to store the image
)
Если пользователи не загрузили аватары, то по умолчанию используется файл avatar.jpg. Также мы указываем каталог(profile_avatars), в котором будут храниться загруженные аватары.
Обратите внимание, что при необходимости вы можете добавить в модель профиля дополнительные поля, такие как адреса, интересы и т. д.
- В-четвертых, скачайте файл avatar.jpg и скопируйте его в папку media проекта:
![]()
- В-пятых, определите метод __str__(), который возвращает строковое представление модели Profile:
def __str__(self):
return f'{self.user.username} Profile'
- В-шестых, определите метод save(), который сохраняет профиль в базе данных, создает миниатюру аватара и сохраняет ее в указанном каталоге:
def save(self, *args, **kwargs):
# save the profile first
super().save(*args, **kwargs)
# resize the image
img = Image.open(self.avatar.path)
if img.height > 150 or img.width > 150:
output_size =(150, 150)
# create a thumbnail
img.thumbnail(output_size)
# overwrite the large image
img.save(self.avatar.path)
- В-седьмых, зарегистрируйте профиль в admin.py, чтобы мы могли управлять профилем на странице администратора:
from django.contrib import admin from .models import Profile admin.site.register(Profile)
Применение миграций
Сначала выполните миграцию, применив команду makemigrations:
python manage.py makemigrations
Выход:
Migrations for 'users':
users\migrations\0001_initial.py
- Create model Profile
Затем примените миграции:
python manage.py migrate
Выход:
Operations to perform: Apply all migrations: admin, auth, contenttypes, sessions, todo, users Running migrations: Applying users.0001_initial... OK
Создание представления MyProfile
Определите представление на основе класса MyProfile в файле views.py:
from django.views import View
# ...
class MyProfile(LoginRequiredMixin, View):
def get(self, request):
user_form = UserUpdateForm(instance=request.user)
profile_form = ProfileUpdateForm(instance=request.user.profile)
context = {
'user_form': user_form,
'profile_form': profile_form
}
return render(request, 'users/profile.html', context)
def post(self,request):
user_form = UserUpdateForm(
request.POST,
instance=request.user
)
profile_form = ProfileUpdateForm(
request.POST,
request.FILES,
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 has been updated successfully')
return redirect('profile')
else:
context = {
'user_form': user_form,
'profile_form': profile_form
}
messages.error(request,'Error updating you profile')
return render(request, 'users/profile.html', context)
Сначала импортируем класс View из django.views:
from django.views import View
Во-вторых, определите класс MyView, который наследует класс View. Класс MyView имеет методы get() и post(), которые соответствуют HTTP GET и POST. Используя класс View, вам не нужно иметь ветвление if-else внутри функции представления, чтобы определить, является ли метод HTTP GET или POST.
В методе get() класса MyProfile мы создаем объекты UserUpdateForm и ProfileUpdateForm и передаем их в шаблон profile.html.
В методе post() мы также создаем объекты UserUpdateForm и ProfileUpdateForm, но передаем дополнительные данные из request.POST и request.FILES.
Если обе формы действительны, мы сохраняем их в базе данных, создаем флэш-сообщение и перенаправляем пользователя обратно на страницу профиля. Если одна из форм недействительна, мы создаем сообщение об ошибке, перенаправляем пользователя обратно на страницу профиля и повторно отображаем шаблон.
Создание шаблона profile.html
Создайте profile.html в каталоге templates/users, который расширяет шаблон base.html:
{% extends 'base.html' %}
{% block content %}
<div class="center">
<form method="POST" enctype="multipart/form-data" class="card">
{% csrf_token %}
{% if user.profile %}
<img src="https://copython.ru/{{user.profile.avatar.url}}" alt="{{ user.username }}" class="avatar" accept=".jpg,.jpeg,.png"/>
{% endif %}
<h2 class="text-center">{{ user.username | title }}</h2>
<p class="text-center"><a href="mailto:{{user.email}}">{{user.email}}</a></p>
<hr>
<label for="email">Email Address:</label>
<input type="email" id="email" name="email" value="{{user.email}}" />
<label for="avatar">Avatar:</label>
<input type="file" name="avatar" id="avatar">
<button type="submit" class="btn btn-primary full-width">Update Profile</button>
</form>
</div>
{% endblock content %}
Создание профиля вручную
Сначала войдите на сайт администратора, используя учетную запись суперпользователя. Вы увидите профили в приложении «Пользователи»:

Во-вторых, нажмите кнопку «Добавить профиль», чтобы создать новый профиль для существующего пользователя:

В-третьих, добавьте новый профиль для пользователя John и нажмите кнопку «Сохранить»:

Django покажет, что профиль пользователя John был успешно добавлен.

Если вы войдете в систему как John и откроете страницу профиля http://127.0.0.1:8000/profile/, вы увидите следующую страницу:

В этой форме вы можете обновить профиль, изменив адрес электронной почты и загрузив новый аватар.
Включение URL-адрес профиля в заголовок
Измените шаблон base.html, чтобы добавить URL-адрес профиля в заголовок:
{%load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://copython.ru/{% static"css/style.css' %}" />
<title>Todo List</title>
</head>
<body>
<header class="header">
<div class="container">
<a href="{%url 'home'%}" class="logo">Todo</a>
<nav class="nav">
<a href="{%url 'home'%}"><i class="bi bi-house-fill"></i> Home</a>
{% if request.user.is_authenticated %}
<a href="{% url 'tasks' %}"><i class="bi bi-list-task"></i> My Tasks</a>
<a href="{% url 'task-create' %}"><i class="bi bi-plus-circle"></i> Create Task</a>
<a href="{% url 'profile' %}" title="Update my profile">Hi {{request.user | title}}</a>
<a href="{% url 'logout' %}" class="btn btn-outline">Logout</a>
{% else %}
<a href="{% url 'login' %}" class="btn btn-outline">Login</a>
<a href="{% url 'register' %}" class="btn btn-primary">Join Now</a>
{% endif %}
</nav>
</div>
</header>
<main>
<div class="container">
{% if messages %}
{% for message in messages %}
<div class="alert alert-{{message.tags}}">
{{message}}
</div>
{% endfor %}
{% endif %}
{%block content %}
{%endblock content%}
</div>
</main>
<footer class="footer">
<div class="container">
<p>© Copyright {% now "Y" %} by <a href="https://www.pythontutorial.net">Python Tutorial</a></p>
</div>
</footer>
</body>
</html>
Создание профиля автоматически
Если вы войдете в систему как Jane и откроете страницу профиля, вы получите следующую ошибку:

Причина в том, что мы не создали профиль для пользователя Jane. Чтобы исправить эту проблему, мы должны создать профиль после успешной регистрации пользователя. Чтобы реализовать это, мы будем использовать нечто, называемое сигналами в Django.
Сначала создайте файл signals.py в приложении пользователя со следующим кодом:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
@receiver(post_save, sender=User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
В этом файле signals.py:
- Функция create_profile() создает новый профиль после создания объекта User.
- Функция save_profile() обновляет профиль после сохранения объекта User.
Декоратор @receiver подключает событие post_save модели User к каждой функции.
Во-вторых, импортируйте сигналы в файл apps.py пользовательского приложения:
from django.apps import AppConfig
class UsersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name="users"
def ready(self):
import users.signals
В apps.py приложения пользователя мы импортируем signals.py в метод ready класса UsersConfig.
В-третьих, зарегистрируйте нового пользователя и проверьте профиль.
