Код на салфетке
2.22K subscribers
746 photos
14 videos
2 files
788 links
Канал для тех, кому интересно программирование на Python и не только.

Сайт: https://pressanybutton.ru/
Чат: https://t.iss.one/+Li2vbxfWo0Q4ZDk6
Заметки автора: @writeanynotes

Реклама и взаимопиар: @Murzyev1995
Сотрудничество и др.: @proDreams
Download Telegram
В профиле это будет отображаться несколько иначе:
- Вместо даты рождения, будет отображаться возраст пользователя, если указана дата.
- Ссылка на профиль в 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. Расширенный профиль пользователя - форма и шаблон

Мы написали модель и сделали сигнал о регистрации.
Теперь займёмся расширенной формой и доработкой шаблона.


Форма модели профиля.
В форме пропишем следующие поля: gender, dob, site_link, telegram_link, user_avatar, show_last_name, show_email, show_telegram.

В целом класс формы не отличается от других ранее созданных нами форм.
Описываем поле, указываем его тип, прописываем название поля и прописываем CSS-класс, также прописываем, что все поля необязательны к вводу.
Опишу только новые или отличающиеся поля:
- 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
Ох уж эти тестеры, любого программиста запугают))
😁4
Приветствую.

Хочу с вами поделиться своей радостью!

Я не так давно писал, что подал заявку на стажировку в IT-академию Lad.
Для прохождения необходимо было выполнить практическое задание и пройти тест на знания языка Python и Фреймворка Django.
По результатам отбора среди более 2000 заявок, после всех отборочных испытаний, я оказался в сотне счастливчиков, допущенных к стажировке.

С сегодняшнего дня начинается моя стажировка в IT-академии Lad, длительностью пять месяцев.

Этим постом начинаю новую рубрику "Вести с полей стажировки".
Буду рассказывать о процессе стажировки, нюансах и новых знаниях.
🔥15
Несколько месяцев тому назад, поступала идея провести "Тайного Санту" среди подписчиков канала.

С того времени идея как-то витала в воздухе, но руки не доходили её воплотить, пока не поступил резонный вопрос - "Где?".

Ну и вот, собравшись с мыслями, замучив Секретаря, встречайте - Тайный Дед Котямба!

Для участия, необходимо заполнить форму: https://forms.gle/adM65uCYJEPgSggW7

И желательно вступить в чат канала: https://t.iss.one/pressanybutton_chat

Давайте подарим друг-другу в этот новый год капельку загадочности и счастья 🙂
🎄3🥰1
Небольшая поправка к посту "Django 35.1. Расширенный профиль пользователя - модель и сигналы".

Я не учёл того, что пользователь может ввести имя на кириллице(или любом другом, отсутствующем в таблице ASCII языке).

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

Код в посте поправил, на сайте пофиксил 😎
🔥2
Статистика сайта за месяц
Автор: 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%.

Пост на сайте
Поддержать проект
🔥3
🔥4💩1
Напоминаю, на нашем канале проводится мероприятие по типу "Тайного Санты".

Пост тут: https://t.iss.one/press_any_button/263

Форма для участия тут: https://forms.gle/adM65uCYJEPgSggW7
🔥3
👀Стырил с другого канала, но думаю там не обидятся))
😁5
Вести с полей стажировки.

Приветствую.

Первого ноября началась стажировка и тогда же было первое организационное собрание.

Собрание вёл директор академии Lad.

Рассказывал:
- Об Академии. Это небольшое ответвление от компании Lad, направленное на обучение IT-специалистов. Базируются в Нижнем Новгороде. Мы 4-й поток стажировки. Они отлаживают механизмы, грубо говоря, пока мы учимся у них, они учатся на нас.

- Про стажёров и отбор. Всего прошло на стажировку свыше 100 человек. Больше всего набрали дизайнеров. Меньше всего бэкэндеров, по ним недобор по Node и всего один по PHP.

- Про гарантию трудоустройства. Обещания взять на работу по результатам стажировки не дают. Объяснил он это на примере академии и других онлайн-курсов (привет GB). Для того, чтобы гарантировать трудоустройство, необходимо иметь своё HR-агентство. Учитывая, что большинство стажёров выходцы из GB, ЯП и других, то почему мы тогда не трудоустроены? Вопрос риторический.

- Про проекты. Организаторы подготовили ряд проектов над которыми мы будем работать. Часть это MVP, сделанные предыдущим потоком стажировки, а часть новые, которые будут разрабатываться с нуля. Изначально во время обора кандидатов, их распределяют на проекты, но в случае простоя, могут перебрасывать и на другие. И не факт, что мы к концу стажировки даже новый MVP сделаем.

- О стажировке. Стажировка длится пять месяцев. Первые пару недель уйдут на формирование команд и подготовке процесса. В целом первый месяц будет посвящён "вкатыванию". По окончании стажировки, у нас будет продуктовый опыт работы над реальным проектом, опыт работы в команде и с инструментами используемыми в IT. Также выдадут сертификат о прохождении стажировки.

Если подытожить, то эти пять месяцев обещают быть интересными. Организатор подкупает своей честностью и открытостью, вместо тонн лести и обещаний как в других организациях (привет GB).
В процессе буду делать себе заметки о происходящем и выпускать по этому поводу пост.
🔥12
Приветствую.

Изначально канал задумывался как личный, но в процессе появились люди, желающие поделиться своими знаниями и опытом с вами.

Спешу представить вам нового автора постов на моем канале!

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

Прошу любить и жаловать Андрея Лебедева!
🔥921
Новая рубрика "Код в мешке"
Автор: Андрей Лебедев

Привет! Меня зовут Андрей, и я с недавних пор занимаюсь программированием на Python. Я заинтересовался разработкой уже во взрослом возрасте на гребне IT-лихорадки, которая с подачи государства захлестнула российское общество. Многие, включая и меня самого, резко захотели “войти в IT”. Онлайн-курсов и всевозможных образовательных программ для взрослых появились десятки, и многие тысячи их выпускников заметно поддавливают рынок трудоустройства, поднимая до предела входной порог не только для “джунов”, но и даже для кандидатов на бесплатные стажировки в IT-компаниях.
🔥1
При этом мало кто из будущих разработчиков отдаёт себе отчёт в том, насколько сложные вещи обсуждаются на видеоуроках, которые они смотрят, и Zoom-семинарах, в которых они принимают участие. Люди молча кивают (или ставят плюсик в чате), когда им озвучиваются определения из разряда “Docker - программное обеспечение для автоматизации развёртывания и управления приложениями в средах с поддержкой контейнеризации, контейнеризатор приложений”. Здесь в пояснении нуждается буквально каждое слово, но мало кто из преподавателей будет заниматься подобной расшифровкой. А взрослым учащимся детально вникать в такие вещи зачастую просто некогда: надо делать домашнее задание, разрабатывать выпускные проекты, а еще ведь и работать, и с близкими общаться, и домашние дела делать, а иногда даже и отдыхать.

Как раз в помощь тем, кто постеснялся признаться себе и/или окружающим в том, что чего-то не понял в непрерывном потоке программистского жаргона, и создан этот блог. Здесь об экстремально сложных вещах мы постараемся рассказать экстремально простым языком. “Если вы что-то не можете объяснить 6-летнему ребёнку, вы сами этого не понимаете”, - одна из распиаренных фраз, которую приписывают то Эйнштейну, то Фейнману, то ещё кому-то. Возможно, у неё и вовсе одного автора нет, для нас это неважно. Мы просто возьмём её на вооружение как девиз. Постараемся настолько разложить сложные вещи, чтобы на выходе получился набор простых. Мы освоим их, а потом заново из них соберем сложную вещь, которая от этого сложной быть не перестанет, но при этом станет хотя бы приблизительно понятной для нас.

Сложно? Непонятно? Мне тоже. Давайте разбираться вместе!

P.S. Статьи в рамках этой рубрики будут неизбежно критиковаться опытными (и не очень) разработчиками, что и неудивительно: я тоже только учусь. Ориентируясь на конструктивную критику, мы будем улучшать качество материалов, делая их более точными, но не в ущерб понятности.

Пост на сайте
Поддержать проект
🔥8👏2
Напоминаю, на нашем канале проводится мероприятие по типу "Тайного Санты".

Нас уже 8 участников!

Пост тут: https://t.iss.one/press_any_button/263

Форма для участия тут: https://forms.gle/adM65uCYJEPgSggW7
🔥2
Ветер переменных
Автор: Андрей Лебедев

Да, переменные - это основа основ. Если вы изучали Python хотя бы месяц, то не могли пройти мимо них. Хотя какой там месяц - о переменных обычно рассказывают на первом же занятии. А если Python - это не первый ваш язык, то вы тем более в курсе, что значит “переменная”. И всё-таки я рекомендую вам продолжить чтение в любом случае, потому что здесь не всё так просто. Но мы попробуем упростить.
👍1
Что такое переменная?
Переменная (что очевидно из названия) - это то, что можно легко изменить. Чаще всего в объяснениях мелькает сравнение переменных с коробочками. Любая коробочка - переменная, потому что можно легко изменить её содержимое. Сначала положить в неё ручку. И тогда она будет содержать ручку. Потом ручку вынуть и положить туда смартфон. Коробочка та же, а содержание изменилось. Вот и в переменную мы можем положить строку, можем список, а можем даже целую функцию. Что положили, то там и “лежит”. И если мы содержимое изменим, называться переменная будет прежним образом (коробочка та же). Чаще всего на этом объяснение и заканчивается. Всем всё понятно, расходимся. Попробуем немного усложнить.

Что значит “коробочка”, куда попадает содержимое в виде строк, списков и всего прочего, что мы туда кладём? В языке C (Си), например, коробочка (то есть переменная) - это ячейка памяти. То есть прям вот коробочка и есть. Когда мы объявляем переменную, в недрах компьютера (как на складе) резервируется ячейка памяти (коробка определенного размера), куда и попадает содержимое, которое мы в нее решили положить. Если мы содержимое коробочки решим поменять, то коробочка (ячейка памяти) в прямом смысле остаётся той же самой.

А как обстоит дело в Python?
Совсем не так. При объявлении переменной тоже резервируется ячейка памяти (коробочка), но когда мы решаем в ту же переменную записать что-то другое, мы кладем это в другую ячейку памяти (новую коробочку), хоть и называется она точно так же. Потому что то, что мы называем “переменной” в Python, - вовсе не коробочка, а бирка, которую мы на нее наклеиваем. И когда мы меняем содержимое переменной, мы не кладем в ту же коробочку (ячейку памяти) что-то новое, а переклеиваем ту же самую бирку на новую коробочку с новым содержимым.

Если говорить совсем уж строго, переменная в Python - вообще не переменная в том смысле, в котором это слово употребляется в контексте языка C. Она скорее ссылка на объект (object reference) или имя (name).

Тогда почему мы называем одним и тем же словом (“переменная”) вещи, которые в Python и других языках различаются? Для упрощения: потому что используем мы их в разных языках схожим образом. Объявил переменную, положил в неё что-нибудь - и вперед: крути циклы, отправляй в функции, меняй содержимое. Чаще всего задумываться о том, что она там означает на самом деле - коробочку или бирку на ней, не придется.

А зачем тогда вообще об этом знать?
Всё-таки этот момент нужно уяснить, чтобы разобраться с другими важными вещами, которые напрямую с ним связаны:
- разницу между оператором “==“ и ключевым словом ‘is’
- нюансы изменяемости и неизменяемости объектов
- сложности поведения некоторых переменных, которые передаются в функции в качестве параметров
- динамическую типизацию и т.д. и т.п.

Всё это мы обязательно обсудим, но как-нибудь в другой раз. А сейчас закрепим коробочно-бирочную аналогию на примере.

Пример

name = "Стэн"
print(id(name))
# 4427735920

same_name = "Стэн"
print(id(same_name))
# 4427735920

name = "Эрик"
print(id(name))
# 4428719728


Разберёмся в том, что только что произошло на наших глазах.
1️⃣ Мы завели бирку (переменную) name и наклеили ее на коробку (ячейку памяти), в которую положили строку “Стэн”. Дальше мы захотели посмотреть на уникальный заводской номер этой коробки (вызвали функцию id, которая возвращает уникальный адрес ячейки памяти, в которой хранится объект).
👍1