Профиль пользователя в Django в Python — примеры создания

Профиль пользователя состоит из настроек и информации, связанной с пользователем. Рассмотрим, как разрешить пользователям обновлять свои профили в приложениях 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="{{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 и нажмите кнопку «Сохранить»:

Добавление нового профиля для пользователя John

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

Профиль пользователя John был успешно добавлен

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

Пример профиля пользователя John

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

Включение 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.

В-третьих, зарегистрируйте нового пользователя и проверьте профиль.

Похожие посты
Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *