А достаточно ли ты хорош чтобы иметь синдром самозванца?
Anonymous Poll
25%
Я - Топ!
16%
Да
59%
Нет, но да
Скинули тут занятную статейку переложения программистов на классы в D&D.
https://habr.com/ru/companies/domclick/articles/517736/
Не могу определиться, я Варвар или Воин или мультикласс))
https://habr.com/ru/companies/domclick/articles/517736/
Не могу определиться, я Варвар или Воин или мультикласс))
Django 34.2. Простой профиль пользователя - страница настроек
В предыдущем посте, мы сделали страницу профиля, теперь надо сделать страницу настроек пользователя.
На этой странице пользователь сможет изменить свои данные и поменять пароль.
Также сделаем страницу со всеми постами пользователя.
В процессе напишем две формы, два представления и два шаблона.
Работать будем с файлами в директории приложения
Формы для страницы настроек.
Откроем файл
У нас будет две формы:
- Форма изменения данных пользователя - это имя пользователя (username), email, имя и фамилия.
- Форма смены пароля.
Форма изменения данных.
Это типовая форма модели.
Создадим класс
Описываем четыре поля, добавляя названия полей и стили:
В подклассе
В предыдущем посте, мы сделали страницу профиля, теперь надо сделать страницу настроек пользователя.
На этой странице пользователь сможет изменить свои данные и поменять пароль.
Также сделаем страницу со всеми постами пользователя.
В процессе напишем две формы, два представления и два шаблона.
Работать будем с файлами в директории приложения
user_app. Приступим.Формы для страницы настроек.
Откроем файл
forms.py в директории приложения user_app.У нас будет две формы:
- Форма изменения данных пользователя - это имя пользователя (username), email, имя и фамилия.
- Форма смены пароля.
Форма изменения данных.
Это типовая форма модели.
Создадим класс
UserInfoForm, унаследованный от forms.ModelForm.Описываем четыре поля, добавляя названия полей и стили:
username, email, first_name, last_name.В подклассе
Meta указываем модель User и вышеупомянутые поля.Код формы:
Форма изменения пароля.
Форму смены пароля писать с нуля не будем, т.к. Django предоставляет встроенную форму
Мы всего лишь переопределим поля, добавив стили форме.
Создадим класс
Код формы:
Представление страницы настроек.
Достаточно сложное и объёмно представление.
Нам надо передать на страницу две формы, а затем обрабатывать их независимо друг от друга.
Помимо того, что страница должна быть доступна только авторизованному пользователю, она также должна быть доступна только тому пользователю, чья страница настроек открыта.
Например, у нас есть маршрут
Откроем файл
Создадим класс
- От класса
- От уже знакомого нам класса
Прописываем единственное поле
Далее у нас будет переопределено три метода:
Первым мы переопределим метод
Метод `dispatch()` - это один из ключевых методов в классовых представлениях Django. Он является частью жизненного цикла обработки запросов и играет важную роль в определении того, какой метод (GET, POST, PUT, DELETE и т. д.) должен обрабатывать входящий HTTP-запрос.
class UserInfoForm(forms.ModelForm):
username = forms.CharField(
max_length=150,
label='Имя пользователя (username)',
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Введите имя пользователя'
})
)
email = forms.EmailField(
widget=forms.EmailInput(attrs={
'class': 'form-control',
'placeholder': 'Введите email'
})
)
first_name = forms.CharField(
max_length=150,
label='Имя',
required=False,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Введите ваше имя'
})
)
last_name = forms.CharField(
max_length=150,
label='Фамилия',
required=False,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Введите вашу фамилию'
})
)
class Meta:
model = User
fields = ['username', 'email', 'first_name', 'last_name']
Форма изменения пароля.
Форму смены пароля писать с нуля не будем, т.к. Django предоставляет встроенную форму
PasswordChangeForm.Мы всего лишь переопределим поля, добавив стили форме.
Создадим класс
UserPasswordForm, унаследованный от PasswordChangeForm и пропишем три поля: old_password, new_password1, new_password2.Код формы:
class UserPasswordForm(PasswordChangeForm):
old_password = forms.CharField(
max_length=128,
label='Старый пароль',
widget=forms.PasswordInput(attrs={
'class': 'form-control',
'placeholder': 'Введите старый пароль'
})
)
new_password1 = forms.CharField(
max_length=128,
label='Новый пароль',
help_text=password_validation.password_validators_help_text_html(),
widget=forms.PasswordInput(attrs={
'class': 'form-control',
'placeholder': 'Введите новый пароль'
})
)
new_password2 = forms.CharField(
max_length=128,
label='Подтверждение нового пароля',
widget=forms.PasswordInput(attrs={
'class': 'form-control',
'placeholder': 'Повторите новый пароль'
})
)
Представление страницы настроек.
Достаточно сложное и объёмно представление.
Нам надо передать на страницу две формы, а затем обрабатывать их независимо друг от друга.
Помимо того, что страница должна быть доступна только авторизованному пользователю, она также должна быть доступна только тому пользователю, чья страница настроек открыта.
Например, у нас есть маршрут
/user/testuser/settings, где testuser это имя пользователя. И если по этому адресу перейдёт testuser, то он увидит настройки, но если другой пользователь откроет эту страницу, то должна быть ошибка 403 Forbidden.Откроем файл
views.py.Создадим класс
UserSettingsView, в этот раз у нас будет два наследования:- От класса
LoginRequiredMixin, проверяющего авторизован пользователь или нет.- От уже знакомого нам класса
TemplateView.Прописываем единственное поле
template_name с указанием файла шаблона.Далее у нас будет переопределено три метода:
Первым мы переопределим метод
dispatch(). С ним мы ещё не сталкивались. Метод `dispatch()` - это один из ключевых методов в классовых представлениях Django. Он является частью жизненного цикла обработки запросов и играет важную роль в определении того, какой метод (GET, POST, PUT, DELETE и т. д.) должен обрабатывать входящий HTTP-запрос.
`dispatch()` работает следующим образом:
1. Когда клиентский запрос поступает на представление, Django вызывает метод `dispatch()` этого представления.
2. `dispatch()` анализирует метод HTTP запроса (GET, POST, PUT, DELETE и т. д.), который пришел от клиента.
3. В зависимости от метода запроса, `dispatch()
4. После обработки запроса соответствующим методом, `dispatch()` возвращает HTTP-ответ.
В нашем методе, мы проверяем, является ли пользователь переданный в адресной строке текущим авторизованным пользователем.
Если является - вызываем метод
Вторым переопределённым методом будет
В этом методе мы передаём две формы и т.к. у нас формы моделей, нам при их сохранении в переменную, в качестве аргумента необходимо передать объект модели, с которым будет работать форма. Если этого не сделать, при сохранении данных будет создаваться новый объект модели, а не обновляться необходимый.
В качестве аргумента для формы
А для формы
Третьим мы переопределим метод
В теле метода у нас находится
-
-
-
Структура внутри
В переменную
Напомню, что для
В случае с формой
Затем проверяем валидность формы.
Если форма валидна и данные корректны:
Сохраняем форму, тем самым внеся изменения в связанный с ней объект пользователя.
Записываем сообщение об успешном изменении, используя функцию
Возвращаем результат.
В этом моменте происходят различия кода.
При обработке формы изменения данных, для возврата результата мы используем функцию
При обработке формы изменения пароля, для возврата результата мы используем стандартный
Если форма не валидна:
Получаем контекст представления и при помощи метода
1. Когда клиентский запрос поступает на представление, Django вызывает метод `dispatch()` этого представления.
2. `dispatch()` анализирует метод HTTP запроса (GET, POST, PUT, DELETE и т. д.), который пришел от клиента.
3. В зависимости от метода запроса, `dispatch()
вызывает соответствующий метод класса представления. Например, если это GET-запрос, `dispatch()` вызовет метод `get(), если это POST-запрос - метод `post()`, и так далее.4. После обработки запроса соответствующим методом, `dispatch()` возвращает HTTP-ответ.
В нашем методе, мы проверяем, является ли пользователь переданный в адресной строке текущим авторизованным пользователем.
Если является - вызываем метод
dispatch() из родительского класса, в противном случае возвращаем 403 Forbidden.Вторым переопределённым методом будет
get_context_data. С ним мы уже сталкивались ранее и он вполне должен быть знаком, но и тут есть нюансы.В этом методе мы передаём две формы и т.к. у нас формы моделей, нам при их сохранении в переменную, в качестве аргумента необходимо передать объект модели, с которым будет работать форма. Если этого не сделать, при сохранении данных будет создаваться новый объект модели, а не обновляться необходимый.
В качестве аргумента для формы
UserInfoForm мы передаём ключевой аргумент instance с объектом пользователя.А для формы
UserPasswordForm, мы передаём объект пользователя в качестве позиционного аргумента.Третьим мы переопределим метод
post. Он достаточно большой и с первого взгляда можно запутаться, но всё достаточно тривиально.В теле метода у нас находится
if-elif-else конструкция. -
if проверяет отправку формы с изменением данных.-
elif проверяет отправку формы изменения пароля.-
else возвращает эту же страницу без изменений.Структура внутри
if и elif в целом одинаковая, различается только действие в случае успеха.В переменную
form помещаем нашу форму, передав в неё объект пользователя и данные отправленные с формы на сайте. Напомню, что для
UserInfoForm, объект пользователя передаётся как ключевой аргумент instance, т.е. он будет вторым аргументом, а данные формы как позиционный, т.е. первым.В случае с формой
UserPasswordForm, оба аргумента передаются как позиционные и первым идёт объект пользователя, а вторым данные формы.Затем проверяем валидность формы.
Если форма валидна и данные корректны:
Сохраняем форму, тем самым внеся изменения в связанный с ней объект пользователя.
Записываем сообщение об успешном изменении, используя функцию
messages.Возвращаем результат.
В этом моменте происходят различия кода.
При обработке формы изменения данных, для возврата результата мы используем функцию
redirect, перенаправляющую пользователя на новую страницу. Она нужна, поскольку в адресной строке прописывается имя пользователя и при изменении имени пользователя и вызове стандартного метода get, происходит перенаправление, но путь в адресной строке не меняется, что влечёт за собой ошибки, а при использовании redirect, пользователь переходит на новый URL-адрес, включающий в себя новое имя пользователя.При обработке формы изменения пароля, для возврата результата мы используем стандартный
get.Если форма не валидна:
Получаем контекст представления и при помощи метода
render обновляем страницу, включающую в себя введённые ранее пользователем данные.Код представления:
**Шаблон страницы настроек профиля.**
В директории с шаблонами приложения
В этом файле прописываем две формы: отображение сообщения об успешном изменении и кнопку возврата в профиль.
Обратите внимание на код кнопок отправки формы. В них мы указываем атрибут
class UserSettingsView(LoginRequiredMixin, TemplateView):
template_name = 'user_app/profile_settings_page.html'
def dispatch(self, request, *args, **kwargs):
if request.user == get_object_or_404(User, username=self.kwargs.get('username')):
return super().dispatch(request, *args, **kwargs)
else:
raise HttpResponseForbidden("Вы не имеете доступа к этой странице.")
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['user_info_form'] = forms.UserInfoForm(instance=self.request.user)
context['user_password_form'] = forms.UserPasswordForm(self.request.user)
context['title'] = f'Настройки профиля {self.request.user}'
return context
def post(self, request, *args, **kwargs):
if 'user_info_form' in request.POST:
form = forms.UserInfoForm(request.POST, instance=request.user)
if form.is_valid():
form.save()
messages.success(request, 'Данные успешно изменены.')
return redirect('user_app:user_profile_settings', form.cleaned_data.get('username'))
else:
context = self.get_context_data(**kwargs)
context['user_info_form'] = form
return render(request, self.template_name, context)
elif 'user_password_form' in request.POST:
form = forms.UserPasswordForm(request.user, request.POST)
if form.is_valid():
form.save()
messages.success(request, 'Пароль успешно изменён.')
return self.get(request, *args, **kwargs)
else:
context = self.get_context_data(**kwargs)
context['user_password_form'] = form
return render(request, self.template_name, context)
else:
return self.get(request, *args, **kwargs)
**Шаблон страницы настроек профиля.**
В директории с шаблонами приложения
user_app создадим файл profile_settings_page.html.В этом файле прописываем две формы: отображение сообщения об успешном изменении и кнопку возврата в профиль.
Обратите внимание на код кнопок отправки формы. В них мы указываем атрибут
name. Именно по этому атрибуту мы отслеживаем в представлении то, какая форма была отправлена.Код шаблона:
Страница с постами пользователя.
Представление.
В файле
Пропишем три поля:
-
-
-
Переопределим метод
В переопределённом методе
Код представления:
**Шаблон.**
В директории с шаблонами приложения
В качестве шаблона я использовал код из файла
URL-паттерны страницы настроек и всех постов пользователя.
Откроем файл
Завершение.
Осталось изменить шаблон страницы профиля, описанный в прошлом посте, а именно, исправить код кнопок.
Кнопка все посты:
Кнопка настроек профиля:
{% extends 'blog/base.html' %}
{% block title %}{{ title }}{% endblock %}
{% block content %}
<div class="container mt-3">
<div class="row d-flex justify-content-between align-items-center">
<div class="col-lg-10 col-sm-12">
<h2>Настройки профиля {{ user }}</h2>
</div>
<div class="col-lg-2 col-sm-12 text-right">
<a class="btn btn-primary my-btn h-100"
href="{% url 'user_app:user_profile' username=user.username %}">Вернуться в профиль</a>
</div>
</div>
<hr>
<div class="row d-flex justify-content-evenly">
<div class="row text-center">
{% if messages %}
<p class="alert alert-success">
{% for message in messages %}
{{ message }}<br>
{% endfor %}
</p>
{% endif %}
</div>
<div class="col-lg-4 col-sm-12">
<h3 class="mb-3 mt-3">Изменить данные:</h3>
<form method="post">
{% csrf_token %}
{{ user_info_form.as_p }}
<button class="btn btn-primary my-btn mt-2" type="submit" name="user_info_form">Отправить</button>
</form>
</div>
<div class="col-lg-4 col-sm-12">
<h3 class="mb-3 mt-3">Изменить пароль:</h3>
<form method="post">
{% csrf_token %}
{{ user_password_form.as_p }}
<button class="btn btn-primary my-btn mt-2" type="submit" name="user_password_form">Отправить
</button>
</form>
</div>
</div>
</div>
{% endblock %}Страница с постами пользователя.
Представление.
В файле
views.py создадим класс UserPostsView, унаследованный от ListView.Пропишем три поля:
-
template_name - файл шаблона.-
context_object_name - имя переменной в шаблоне-
paginate_by - количество элементов на страницеПереопределим метод
get_queryset. В нём вернём список постов, отфильтрованных по переданному в URL-адресе пользователю.В переопределённом методе
get_context_data, в блоке try-except получим объект пользователя по имени пользователя из URL-адреса и запишем его в контекст.Код представления:
class UserPostsView(ListView):
template_name = 'user_app/user_posts_page.html'
context_object_name = 'posts'
paginate_by = 10
def get_queryset(self):
return PostModel.post_manager.filter(author__username=self.kwargs.get('username'))
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
try:
author = get_object_or_404(User, username=self.kwargs.get("username"))
except User.DoesNotExist:
raise Http404("Пользователь не найден")
context['author'] = author
context['title'] = f'Посты пользователя {author}'
return context
**Шаблон.**
В директории с шаблонами приложения
user_app создадим файл user_posts_page.html.В качестве шаблона я использовал код из файла
tag_page.html.URL-паттерны страницы настроек и всех постов пользователя.
Откроем файл
urls.py в директории приложения user_app и добавим следующие строки в список urlpatterns:path('<str:username>/settings/', views.UserSettingsView.as_view(), name='user_profile_settings'),
path('<str:username>/posts/', views.UserPostsView.as_view(), name='user_posts'),Завершение.
Осталось изменить шаблон страницы профиля, описанный в прошлом посте, а именно, исправить код кнопок.
Кнопка все посты:
<a class="btn btn-primary my-btn mb-3"
href="{% url 'user_app:user_posts' username=user_profile.username %}">Все посты {{ user_profile }}
</a>
Кнопка настроек профиля:
<a class="btn btn-primary my-btn me-1"
href="{% url 'user_app:user_profile_settings' username=user_profile.username %}">Настройки профиля
</a>
Готово. За эти два поста, мы реализовали публичный профиль пользователя, страницу настроек и страницу всех постов, используя стандартную модель пользователя Django.
Файлы к посту, можно получить в боте по коду: 828730
Пост на сайте.
Поддержать канал.
Файлы к посту, можно получить в боте по коду: 828730
Пост на сайте.
Поддержать канал.
🔥2👏1
Позавчера было ровно 15 месяцев как началась учёба в GB.
Как же блин быстро летит время.
Очередной пост на Пикабу: Обучение: пятнадцатый месяц
😉Расчехляйте лайкомёты)
Как же блин быстро летит время.
Очередной пост на Пикабу: Обучение: пятнадцатый месяц
😉Расчехляйте лайкомёты)
Пикабу
Обучение: пятнадцатый месяц
Автор: proDream
🔥3
Приветствую.
У меня почему-то Хэллоуин ассоциируется не то с комедией, не то с трэш-хоррорами. И вот в преддверии этого события, у меня для вас забавный фильм.
Фильм на сегодня: Смерть ей к лицу (1992).
Краткий синопсис: Эликсир вечной молодости! Сколько женщин мечтают о нем! О нем мечтали и бродвейская звезда Мэдлин Эштон, и Хелен Шарп, у которой эта коварная Мэдлин отбила жениха Эрнеста Мэнвилла, гениального врача-специалиста по пластическим операциям.
Прошли годы, и изрядно полинявшие и уставшие друг от друга дамочки, обращаются за чудотворным снадобьем к некоей колдунье. Итак, эликсир выпит, кожа посвежела, груди подтянулись, но скоро качество лекарства будет проверено... смертью.
Посмотреть можно тут: https://www.sspoisk.ru/film/1889/
А какие ассоциации у вас вызывает Хэллоуин?
У меня почему-то Хэллоуин ассоциируется не то с комедией, не то с трэш-хоррорами. И вот в преддверии этого события, у меня для вас забавный фильм.
Фильм на сегодня: Смерть ей к лицу (1992).
Краткий синопсис: Эликсир вечной молодости! Сколько женщин мечтают о нем! О нем мечтали и бродвейская звезда Мэдлин Эштон, и Хелен Шарп, у которой эта коварная Мэдлин отбила жениха Эрнеста Мэнвилла, гениального врача-специалиста по пластическим операциям.
Прошли годы, и изрядно полинявшие и уставшие друг от друга дамочки, обращаются за чудотворным снадобьем к некоей колдунье. Итак, эликсир выпит, кожа посвежела, груди подтянулись, но скоро качество лекарства будет проверено... смертью.
Посмотреть можно тут: https://www.sspoisk.ru/film/1889/
А какие ассоциации у вас вызывает Хэллоуин?
👍2
Django 35.1. Расширенный профиль пользователя - модель и сигналы
Продолжаем тему профиля пользователя, начатую в прошлом посте.
В этом и следующем посте мы расширим его дополнительными полями, создав модель профиля, форму, написав сигнал для создания профиля при регистрации и изменим наши шаблоны.
Я решил расширить профиль следующими полями:
- Пол
- Дата рождения
- Личный сайт - ссылка на сайт пользователя.
- Профиль в Telegram - ссылка на Telegram-профиль.
- Аватарка - изображения по умолчанию у меня не будет, да и скучно это, когда много пользователей с одинаковыми изображениями. Вместо этого, для каждого пользователя по умолчанию будет генерироваться аватар в сервисе https://robohash.org/.
- Три переключателя, определяющих отображать в профиле или нет следующие поля: Фамилия, Email, Telegram-профиль.
Продолжаем тему профиля пользователя, начатую в прошлом посте.
В этом и следующем посте мы расширим его дополнительными полями, создав модель профиля, форму, написав сигнал для создания профиля при регистрации и изменим наши шаблоны.
Я решил расширить профиль следующими полями:
- Пол
- Дата рождения
- Личный сайт - ссылка на сайт пользователя.
- Профиль в Telegram - ссылка на Telegram-профиль.
- Аватарка - изображения по умолчанию у меня не будет, да и скучно это, когда много пользователей с одинаковыми изображениями. Вместо этого, для каждого пользователя по умолчанию будет генерироваться аватар в сервисе https://robohash.org/.
- Три переключателя, определяющих отображать в профиле или нет следующие поля: Фамилия, Email, Telegram-профиль.
В профиле это будет отображаться несколько иначе:
- Вместо даты рождения, будет отображаться возраст пользователя, если указана дата.
- Ссылка на профиль в Telegram, будет отображать только ник.
- Также будет поле для отображения информации о том, как давно зарегистрировался пользователь.
Библиотека Pillow.
Для работы с изображениями необходима библиотека
Откроем файл
В самом начале пропишем внутренний класс
Далее будет девять полей:
-
-
-
-
-
-
Прописываем класс
Затем у нас будет несколько методов:
Переопределённый метод
В этом методе, сперва проверяем, установлена ли у пользователя аватарка.
Если не установлена, то делаем запрос на сайт и сохраняем полученное изображение.
В противном случаем, мы проверяем, что загруженное пользователем изображение не больше 300х300 и если оно больше, сжимаем до нужного размера.
Метод
Метод
Метод
Dunder-метод
Код модели:
Откроем файл
Я не вижу смысла тут прописывать поля для отображения, по крайней мере пока, по этому просто зарегистрирую модель:
Когда пользователь регистрируется на сайте, необходимо, что бы создавалась модель профиля, с этим нам помогут сигналы (signals) в Django.
Сигналы (signals) - это механизм, который позволяет отправлять сообщения о событиях в приложении. Сигналы используются для оповещения других частей приложения о том, что произошло определенное событие, например, создание или обновление объекта модели.
В директории приложения
- Вместо даты рождения, будет отображаться возраст пользователя, если указана дата.
- Ссылка на профиль в Telegram, будет отображать только ник.
- Также будет поле для отображения информации о том, как давно зарегистрировался пользователь.
Библиотека Pillow.
Для работы с изображениями необходима библиотека
Pillow, если она у вас не установлена, то установить её можно командой:pip install PillowНе забудьте добавить библиотеку в файл
requirements.txt:Pillow~=10.1.0Модель профиля.
Откроем файл
models.py в директории user_app и создадим класс ProfileModel, унаследованный от models.Model.В самом начале пропишем внутренний класс
Genders, это будет перечисление с вариантами выбора пола пользователя. Подобный класс перечисления мы писали в посте "Django 20. Модель поста".Далее будет девять полей:
-
user - поле для связи с пользователем через связь "Один к Одному" (OneToOne). В аргументах передаём модель, название, а так же имя связи, по которому мы сможем обратиться к объекту модели из объекта пользователя.-
gender - текстовое поле для хранения выбранного в перечислении значения пола пользователя. В аргументах указываем максимальную длину поля, указываем класс с перечислениями, указываем стандартное значение, а также имя поля.-
dob - поле с датой рождения пользователя. В аргументах указываем null и blank равное True, что делает поле необязательным к вводу, а также имя поля.-
site_link, telegram_link - поля ссылок (URLField) . Стандартные аргументы: имя поля, null и blank, максимальная длина. Для telegram_link добавляем атрибут unuque=True, что бы ссылки на профили не повторялись.-
user_avatar - поле изображения (ImageField). В аргументах передаём путь в директории media, куда будут загружаться изображения, также имя поля и null и blank. Также, можно указать изображение по умолчанию.-
show_email, show_telegram, show_last_name - логические поля (BooleanField). В аргументах передаём имя поля и стандартное значение False.Прописываем класс
Meta, указывая имя модели.Затем у нас будет несколько методов:
Переопределённый метод
save. В этом методе, сперва проверяем, установлена ли у пользователя аватарка.
Если не установлена, то делаем запрос на сайт и сохраняем полученное изображение.
В противном случаем, мы проверяем, что загруженное пользователем изображение не больше 300х300 и если оно больше, сжимаем до нужного размера.
Метод
get_on_site, высчитывающий из текущей даты и даты регистрации то, сколько дней/месяцев/лет назад зарегистрировался пользователь.Метод
get_telegram_username, отделяющий от ссылки на профиль имя пользователя в Telegram.Метод
get_age, высчитывающий возраст пользователя.Dunder-метод
__str__, возвращающий имя пользователя при обращении к объекту.Код модели:
Код доступен на сайте или в файлах к постуРегистрация в панели администратора.
Откроем файл
admin.py в директории user_app.Я не вижу смысла тут прописывать поля для отображения, по крайней мере пока, по этому просто зарегистрирую модель:
from django.contrib import adminСигнал о регистрации пользователя.
from user_app import models
admin.site.register(models.ProfileModel)
Когда пользователь регистрируется на сайте, необходимо, что бы создавалась модель профиля, с этим нам помогут сигналы (signals) в Django.
Сигналы (signals) - это механизм, который позволяет отправлять сообщения о событиях в приложении. Сигналы используются для оповещения других частей приложения о том, что произошло определенное событие, например, создание или обновление объекта модели.
В директории приложения
user_app создадим новый файл signals.py и напишем следующий код:from django.contrib.auth.models import User
from .models import ProfileModel
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
if created:
ProfileModel.objects.create(user=instance)
create_profile - это функция-обработчик сигнала `post_save`, который вызывается каждый раз, когда сохраняется экземпляр модели `User`. В нашем случае он будет отрабатывать только при создании нового объекта, т.е. регистрации пользователя. Для этого в теле функции есть условие
if created.Если условие верное, то будет создан экземпляр модели `ProfileModel` и связан с экземпляром модели `User`, который был передан в функцию обработчиком сигнала.
**Подключение сигнала.**
Откроем файл
apps.py и внутри класса добавим метод ready, который будет срабатывать при запуске приложения:def ready(self):
import user_app.signals
Внимание! Если у вас уже есть зарегистрированные пользователи, а как минимум один (суперпользователь) у вас есть, вам необходимо для них в админке создать профили самостоятельно!
Файлы к посту, можно получить в боте по коду: 585887
Пост на сайте.
Поддержать канал.
🔥1
Django 35.2. Расширенный профиль пользователя - форма и шаблон
Мы написали модель и сделали сигнал о регистрации.
Теперь займёмся расширенной формой и доработкой шаблона.
Форма модели профиля.
В форме пропишем следующие поля:
В целом класс формы не отличается от других ранее созданных нами форм.
Описываем поле, указываем его тип, прописываем название поля и прописываем CSS-класс, также прописываем, что все поля необязательны к вводу.
Мы написали модель и сделали сигнал о регистрации.
Теперь займёмся расширенной формой и доработкой шаблона.
Форма модели профиля.
В форме пропишем следующие поля:
gender, dob, site_link, telegram_link, user_avatar, show_last_name, show_email, show_telegram.В целом класс формы не отличается от других ранее созданных нами форм.
Описываем поле, указываем его тип, прописываем название поля и прописываем CSS-класс, также прописываем, что все поля необязательны к вводу.
Опишу только новые или отличающиеся поля:
-
-
-
-
Ниже класс
Код формы:
Изменение представления страницы настроек профиля.
Для добавления новой формы нам надо добавить несколько строк.
В метод
В методе
Далее в проверку на валидность, добавляем проверку и второй формы:
После чего, если обе формы валидны, сохраняем объекты с новыми данными:
Если одна или обе формы не валидны, возвращаем формы с введёнными данными:
Код изменённых методов:
Шаблон страницы настроек:
Тут мы объединяем обе формы в одном теге
Далее, можно по стандарту вывести обе формы:
Но я для лучшего отображения применил классы Bootstrap. Для этого пришлось каждое поле выводить по отдельности.
Код шаблона:
Шаблон страницы профиля.
Тут почти стандартно, отображаем нужные поля профиля с проверкой на наличие данных в них:
На этом всё. У нас теперь есть расширенный профиль пользователя с необходимыми полями. Вероятно, в будущем он будет изменяться или расширяться. Следующим шагом будет создание своего расширенного пользователя, но этим мы займёмся в одном из следующих постов.
Файлы к посту, можно получить в боте по коду: 206476
Пост на сайте.
Поддержать канал.
-
gender - поле выбора ChoiceField. В аргументах указываем название поля, доступные выборы параметром choices и виджет Select.-
dob - поле даты DateField. Указываем название поля и виджет DateInput. В аргументах к виджету передаём параметр format. С этим связана забавная особенность. В БД дата хранится в виде ГГГГ-ММ-ДД, однако в нашей локали принята запись ДД.ММ.ГГГГ. В шаблон оно передаётся в нашем виде, но HTML-форма даты принимает только в формате ГГГГ-ММ-ДД, при этом отображает в формате пользовательской локали. Сложно и не понятно. Для решения этой ситуации указываем параметр format='%Y-%m-%d'. Также в параметр attrs, помимо класса стиля, передаём тип формы 'type': 'date', т.к. по умолчанию DateInput это просто текстовое поле.-
user_avatar - поле загрузки файлов FileField. В атрибутах название поля и виджет FileInput. В параметре attrs виджета, кроме класса, указываем тип поля 'type': 'file'.-
show_last_name, show_email, show_telegram - логические поля BooleanField. Виджет поля CheckboxInput.Ниже класс
Meta с указанием модели ProfileModel и перечислением полей.Код формы:
Много текста. Код доступен на сайте или в материалах к посту.
Изменение представления страницы настроек профиля.
Для добавления новой формы нам надо добавить несколько строк.
В метод
get_context_data добавляем строку с передачей новой формы в шаблон, передавая в качестве аргумента объект профиля:context['user_profile_form'] = forms.ProfileForm(instance=self.request.user.profile)
В методе
post, в первом условии if 'user_info_form' in request.POST:, добавляем новую переменную формы, передавая в неё данные из POST-запроса, файл из POST-запроса и объект профиля.user_profile_form = forms.ProfileForm(request.POST, request.FILES, instance=self.request.user.profile)
Далее в проверку на валидность, добавляем проверку и второй формы:
if user_info_form.is_valid() and user_profile_form.is_valid():
После чего, если обе формы валидны, сохраняем объекты с новыми данными:
user_info_form.save()
user_profile_form.save()
Если одна или обе формы не валидны, возвращаем формы с введёнными данными:
context['user_info_form'] = user_info_form
context['user_profile_form'] = user_profile_form
Код изменённых методов:
Много текста. Код доступен на сайте или в материалах к посту.
Шаблон страницы настроек:
Тут мы объединяем обе формы в одном теге
form. Дополнительным аргументом указываем enctype="multipart/form-data", сообщая, что эта форма может принимать файлы.Далее, можно по стандарту вывести обе формы:
{% csrf_token %}
{{ user_info_form.as_p }}
{{ user_profile_form.as_p }}Но я для лучшего отображения применил классы Bootstrap. Для этого пришлось каждое поле выводить по отдельности.
Код шаблона:
Много текста. Код доступен на сайте или в материалах к посту.
Шаблон страницы профиля.
Тут почти стандартно, отображаем нужные поля профиля с проверкой на наличие данных в них:
Много текста. Код доступен на сайте или в материалах к посту.
На этом всё. У нас теперь есть расширенный профиль пользователя с необходимыми полями. Вероятно, в будущем он будет изменяться или расширяться. Следующим шагом будет создание своего расширенного пользователя, но этим мы займёмся в одном из следующих постов.
Файлы к посту, можно получить в боте по коду: 206476
Пост на сайте.
Поддержать канал.
🔥1
Приветствую.
Хочу с вами поделиться своей радостью!
Я не так давно писал, что подал заявку на стажировку в IT-академию Lad.
Для прохождения необходимо было выполнить практическое задание и пройти тест на знания языка Python и Фреймворка Django.
По результатам отбора среди более 2000 заявок, после всех отборочных испытаний, я оказался в сотне счастливчиков, допущенных к стажировке.
С сегодняшнего дня начинается моя стажировка в IT-академии Lad, длительностью пять месяцев.
Этим постом начинаю новую рубрику "Вести с полей стажировки".
Буду рассказывать о процессе стажировки, нюансах и новых знаниях.
Хочу с вами поделиться своей радостью!
Я не так давно писал, что подал заявку на стажировку в IT-академию Lad.
Для прохождения необходимо было выполнить практическое задание и пройти тест на знания языка Python и Фреймворка Django.
По результатам отбора среди более 2000 заявок, после всех отборочных испытаний, я оказался в сотне счастливчиков, допущенных к стажировке.
С сегодняшнего дня начинается моя стажировка в IT-академии Lad, длительностью пять месяцев.
Этим постом начинаю новую рубрику "Вести с полей стажировки".
Буду рассказывать о процессе стажировки, нюансах и новых знаниях.
🔥15