Профиль пользователя в Django в Python — примеры создания
Профиль пользователя состоит из настроек и информации, связанной с пользователем. Рассмотрим, как разрешить пользователям обновлять свои профили в приложениях Django в Python.
- Установка пакета Pillow
- Настройка каталога для хранения загруженных изображений
- Создание модели профиля
- Применение миграций
- Создание представления MyProfile
- Создание шаблона profile.html
- Создание профиля вручную
- Включение URL-адрес профиля в заголовок
- Создание профиля автоматически
Установка пакета 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="{{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="{% 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.
В-третьих, зарегистрируйте нового пользователя и проверьте профиль.