`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
Несколько месяцев тому назад, поступала идея провести "Тайного Санту" среди подписчиков канала.
С того времени идея как-то витала в воздухе, но руки не доходили её воплотить, пока не поступил резонный вопрос - "Где?".
Ну и вот, собравшись с мыслями, замучив Секретаря, встречайте - Тайный Дед Котямба!
Для участия, необходимо заполнить форму: https://forms.gle/adM65uCYJEPgSggW7
И желательно вступить в чат канала: https://t.iss.one/pressanybutton_chat
Давайте подарим друг-другу в этот новый год капельку загадочности и счастья 🙂
С того времени идея как-то витала в воздухе, но руки не доходили её воплотить, пока не поступил резонный вопрос - "Где?".
Ну и вот, собравшись с мыслями, замучив Секретаря, встречайте - Тайный Дед Котямба!
Для участия, необходимо заполнить форму: https://forms.gle/adM65uCYJEPgSggW7
И желательно вступить в чат канала: https://t.iss.one/pressanybutton_chat
Давайте подарим друг-другу в этот новый год капельку загадочности и счастья 🙂
🎄3🥰1
Небольшая поправка к посту "Django 35.1. Расширенный профиль пользователя - модель и сигналы".
Я не учёл того, что пользователь может ввести имя на кириллице(или любом другом, отсутствующем в таблице ASCII языке).
В связи с этим, при регистрации пользователя с юзернеймом на русском языке не создавался профиль и выдавало ошибку.
Код в посте поправил, на сайте пофиксил 😎
Я не учёл того, что пользователь может ввести имя на кириллице(или любом другом, отсутствующем в таблице ASCII языке).
В связи с этим, при регистрации пользователя с юзернеймом на русском языке не создавался профиль и выдавало ошибку.
Код в посте поправил, на сайте пофиксил 😎
🔥2
Статистика сайта за месяц
Автор: proDream
Прошёл месяц с прошлого поста со статистикой сайта, что изменилось?
Переходы с Dzen'а упали, там в целом показы и просмотры просели, хотя и до этого не то, что бы были большие.
Переходы с канала упали, обидно 🙁.
И тут выходит поиск. За месяц показы и, что не мало важно, клики, сильно скаканули. Это приятно. Чаще всего ищут статьи про AIOgram(это при том-то, что на сайте сплошная джанга).
Также добавил на сайт небольшой блок с рекламой. Никаких всплывашек или баннеров на весь экран. Небольшой ненавязчивый блок. По этому большая просьба внести сайт в исключения блокировщика рекламы. Вам не сложно, а мне может хоть на оплату сервера капать будет 🙂.
Автор: proDream
Прошёл месяц с прошлого поста со статистикой сайта, что изменилось?
Переходы с Dzen'а упали, там в целом показы и просмотры просели, хотя и до этого не то, что бы были большие.
Переходы с канала упали, обидно 🙁.
И тут выходит поиск. За месяц показы и, что не мало важно, клики, сильно скаканули. Это приятно. Чаще всего ищут статьи про AIOgram(это при том-то, что на сайте сплошная джанга).
Также добавил на сайт небольшой блок с рекламой. Никаких всплывашек или баннеров на весь экран. Небольшой ненавязчивый блок. По этому большая просьба внести сайт в исключения блокировщика рекламы. Вам не сложно, а мне может хоть на оплату сервера капать будет 🙂.
👍2
В сухом итоге:
- Посетители: Было 210, стало 500. Прирост 138.09%.
- Переходы из Dzen: Было 37.6%, стало 12.6%. Падение 66.48%.
- Переходы из Telegram-канала: Было 24.2%, стало 18%. Падение 25.61%.
- Переходы из поиска: Было 17.6%, стало 48.1%. Прирост 173.29%.
Пост на сайте
Поддержать проект
- Посетители: Было 210, стало 500. Прирост 138.09%.
- Переходы из Dzen: Было 37.6%, стало 12.6%. Падение 66.48%.
- Переходы из Telegram-канала: Было 24.2%, стало 18%. Падение 25.61%.
- Переходы из поиска: Было 17.6%, стало 48.1%. Прирост 173.29%.
Пост на сайте
Поддержать проект
🔥3