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

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

Реклама и взаимопиар: @Murzyev1995
Сотрудничество и др.: @proDreams
Download Telegram
И правда как-то так...
😱1
Django 37. Две формы - добавление категории и файла
Автор: Иван Ашихмин

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

В процессе работы мы закрепим создание форм, создадим три представления, применив наследование, а также создадим два шаблона.
🔥1
Однако есть и второй вариант, а именно создание нового связанного объекта (в нашем случае категория и файл поста) прямо на странице добавления нового поста. Примерно также, как это реализовано в панели администратора Django. Подробнее можно прочитать в посте на Boosty "Django - Добавление новой категории в форме создания поста без перезагрузки страницы" (платный контент).

Формы добавления категории и файла поста.
Откроем файл forms.py в директории приложения user_app.

Форма добавления категории.
Создадим новый класс AddCategoryByAuthorForm, унаследованный от ModelForm.

Так же, как мы делали в посте "Django 36. Добавление постов пользователем", создаём конструктор класса __init__.
В нём добавляем всем полям формы bootstrap-класс form-control и дополнительный класс для поля description - django_ckeditor_5, для работы визуального редактора Django CKEditor 5.

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

Далее создаём подкласс Meta, прописываем модель и необходимые поля.

Код формы:
from blog.models import CategoryModel


class AddCategoryByAuthorForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].widget.attrs.update({'class': 'form-control', 'autofocus': ''})

self.fields['description'].widget.attrs.update({'class': 'django_ckeditor_5'})

class Meta:
model = CategoryModel
fields = ('title', 'parent', 'description', 'telegram_link')


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

Код формы:
from blog.models import PostFilesModel


class AddFileByAuthorForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
for field in self.fields:
self.fields[field].widget.attrs.update({'class': 'form-control', 'autofocus': ''})

class Meta:
model = PostFilesModel
fields = ('title', 'file')


Представления страницы добавления категории и страницы добавления файла поста.
Откроем файл views.py в директории приложения user_app.

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

Базовый класс.
Создадим класс AddCategoryAndFile с двойным наследованием: UserPassesTestMixin и CreateView.

В теле класса будет всего два метода:
🔥1
test_func - для проверки того, что пользователь входит в группу "Автор". Подробнее об этом рассказывал в прошлом посте - "Django 36. Добавление постов пользователем".
get_success_url - метод, определяющий куда будет перенаправлен пользователь после заполнения формы. В нашем случае на страницу профиля.

Это всё, что будет в нашем классе. Остальные параметры будут заменены в классах-наследниках.

Код класса:
from django.contrib.auth.mixins import UserPassesTestMixin
from django.views.generic import CreateView


class AddCategoryAndFile(UserPassesTestMixin, CreateView):
def test_func(self):
return self.request.user.groups.filter(name='Автор').exists()

def get_success_url(self):
return reverse('user_app:user_profile', kwargs={'username': self.request.user.username})


Представление добавления файла.
Создадим класс AddFileView, унаследованный от нашего класса AddCategoryAndFile.

В этом представлении не будет методов, только четыре поля:

template_name - шаблон страницы.
form_class - класс формы.
model - используемая модель.
extra_context - дополнительные данные, в нашем случае это заголовок страницы.

Это весь класс.

Код класса:
from blog.models import PostFilesModel


class AddFileView(AddCategoryAndFile):
template_name = 'user_app/add_file.html'
form_class = forms.AddFileByAuthorForm
model = PostFilesModel
extra_context = {'title': 'Добавление файла'}


Представление добавления категории.
Создадим класс AddCategoryView, унаследованный от нашего класса AddCategoryAndFile.

В этом представлении будут точно такие же поля, как и в предыдущем, а также один метод:

form_valid - в этом методе мы приводим поле slug к корректному виду. Почему это важно сделать, я объяснял в прошлом посте.

Код класса:
from blog.models import CategoryModel


class AddCategoryView(AddCategoryAndFile):
template_name = 'user_app/add_category.html'
form_class = forms.AddCategoryByAuthorForm
model = CategoryModel
extra_context = {'title': 'Добавление категории'}

def form_valid(self, form):
form.instance.slug = slugify(form.instance.title)
return super().form_valid(form)


URL-паттерны.
Откроем файл urls.py в директории приложения user_app и в список urlpatterns добавим следующие строки:
path('post/add_category/', views.AddCategoryView.as_view(), name='add_category'),  
path('post/add_file/', views.AddFileView.as_view(), name='add_file'),


Шаблоны страниц.
В директории с шаблонами приложения user_app создадим два файла:

add_category.html - файл с формой добавления категории.
add_file.html - файл с формой добавления файла поста.

Оба шаблона практически идентичны.
Различия заключаются в том, что в форме добавления категории выводится {{ form.media }} для отображения визуального редактора, а в форме добавления файла указано enctype="multipart/form-data", означающее, что форма может передавать файлы.

Код страницы добавления категории:
🔥1
{% extends 'blog/base.html' %}
{% block title %}{{ title }}{% endblock %}

{% block content %}
<div class="container mt-3 d-flex justify-content-center">
<div class="col-lg-8 col-sm-12">
<h2>{{ title }}</h2>
<form method="post">
{% csrf_token %}
{{ form.media }}
{{ form.as_p }}
<button type="submit" class="btn btn-primary my-btn-success mt-3">Сохранить</button>
</form>
</div>
</div>
{% endblock %}


Код страницы добавления файла:
{% extends 'blog/base.html' %}
{% block title %}{{ title }}{% endblock %}

{% block content %}
<div class="container mt-3 d-flex justify-content-center">
<div class="col-lg-8 col-sm-12">
<h2>{{ title }}</h2>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary my-btn-success mt-3">Сохранить</button>
</form>
</div>
</div>
{% endblock %}


Добавляем ссылки в меню пользователя.
Откройте файл header.html и под ссылкой на добавление нового поста добавьте следующий код:
<li>  
<a class="dropdown-item dd-item-color" href="{% url 'user_app:add_category' %}">Добавить
категорию</a>
</li>
<li>
<a class="dropdown-item dd-item-color" href="{% url 'user_app:add_file' %}">Добавить
файл</a>
</li>


Заключение.
Довольно часто приходится создавать однотипные классы, страницы или просто использовать одни и те же фрагменты кода несколько раз.
Для решения проблемы ненужного "раздувания" кода - отлично подходит наследование и создание базовых классов.

Если вас заинтересует другой способ реализации подобного функционала (не в виде отдельных страниц, а непосредственно в форме добавления поста), то об этом я рассказываю в посте на Boosty "Django - Добавление новой категории в форме создания поста без перезагрузки страницы" (платный контент).

В следующем посте мы продолжим эту тему и затронем такие конструкции, как декораторы и миксины.

Файлы к посту, можно получить в боте по коду: 821104

Пост на сайте
Поддержать проект

#Django #Гайды #ООП #формы #представления #Код_на_салфетке #наследования #классы
🔥3
Django - Добавление новой категории в форме создания поста без перезагрузки страницы
Автор: Иван Ашихмин

Встроенная панель администратора - одно из главных преимуществ фреймворка Django. Это весьма функциональный и удобный инструмент. Одна из его возможностей - это добавление связанного с моделью объекта на странице создания этого самого объекта.

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

С появлением первых постов на канале ко мне обратились с вопросом: "Возможно ли реализовать функционал из панели администратора на страницах сайта?". Это меня заинтересовало, но ввиду того, что не было необходимости, решение данной задачи было отложено. При создании функционала для авторов я вернулся к этому вопросу.
🔥2
В этом посте будем продолжать написанное в "Django 37. Две формы - добавление категории и файла", а именно, добавим возможность создать новую категорию или добавить новый файл без перезагрузки страницы.

Продолжение в посте на Boosty (платный контент)

Пост на сайте
Поддержать проект

#Django #Гайды #ООП #формы #представления #Код_на_салфетке #наследования #классы #Boosty
🔥2
Зарождение проекта...
Автор: Некий Вестник Сплетен

Итак, начнём сначала..

Чат "Кот на салфетке" объединил в себе множество разных людей с отличающимися характерами и интересами, разного возраста и географии. Но всех нас объединяет любовь к программированию. Здесь общение происходит абсолютно на разные темы.. И это прекрасно! В обычное время это выглядит слегка "безумно" и человек "со стороны" может испугаться или счесть нас сумасшедшими. Но порой здесь можно встретить интересные темы, задачи, идеи.

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

Так не могло продолжаться дальше. Не допустимо было допускать это откладывание, оттягивание и отсутствие собранности.

Тогда было решено создать отдельный чат и приступить к работе уже непосредственно с теми, кто желает этим заниматься. Создали чат, нарекли его на временной основе - "Некий проект", разместили ссылку в "Коте на салфетке", по которой желающие участвовать в проекте могли присоединиться самостоятельно.

Таким образом, собралась команда из 14 человек:
9 Backend-разработчиков
2 Frontend-разработчика
2 UX/UI-дизайнера
1 Project-менеджер

И началась череда созвонов...

Пост на сайте
Поддержать проект

#Кот_на_салфетке #Backend #Код_на_салфетке #Некий_проект #UI #созвоны #групповой_проект #UX #Frontend #Project
🔥5
Приветствую.

На канале сейчас активна только одна рубрика с гайдами и та посвящена Django. Помимо есть три информационные: про питон, про стажировку и про наш групповой проект.

Нужна ваша помощь. На какую тему вы бы хотели видеть гайды кроме Джанго?
Пишите в комментарии общую технологию или конкретные библиотеки, идеи или вещи.

Спасибо.
Начало работ
Автор: Иван Ашихмин

Прошел месяц с начала стажировки.

Первые пару недель заняли организационные вопросы:
- Формирование команд - Наш проект единственный разрабатывается на Django + VueJS, поэтому формирование команды не заняло много времени.
- Чаты - Сформировали чат всего проекта, а также чаты направлений.
- Доступы - Предоставили доступ к сервису Mattermost. Это такой "корпоративный чат" с разными "каналами", SCRUM-доской и так далее. Никогда с ним ранее не сталкивался, но, по словам организаторов, этот сервис используют многие IT-компании.
🔥5👍1
- Документы - На подписание дали два документа: Разрешение на обработку персональных данных и Соглашение о неразглашении (NDA). NDA в нашем случае с послаблениями, а именно, мы можем использовать собственно написанный код для предоставления работодателям или в обучающих целях. Тем не менее, публиковать полный код или результаты работы команды строго-настрого запрещено. Подписывал подобное в первый раз, предварительно связавшись с директором Академии LAD и уточнив, что мне можно рассказывать.


Потом была пара общих собраний, на которых в основном обсуждалась концепция проекта. Я на этих звонках сидел "ниже воды, тише травы", поскольку всё это для меня в новинку и, по правде говоря, мало что понимал в обсуждениях. Сидел, слушал, пытался уяснить и набирался опыта.
Объяснили, как работать в Mattermost и как будут распределяться задачи на SCRUM-доске. Придётся привыкать к нему, так как, не считая Telegram-чатов для "быстрого" реагирования, это должно стать основным место для обсуждений.

Продакты провели анализ конкурентов и предоставили варианты направления развития проекта.
Сейчас они продолжают исследования, для этого запустили опрос среди тех кто покупал курсы по обучению программированию себе или детям. Если есть желание помочь в исследовании, можете заполнить анкету по ссылке: https://docs.google.com/forms/d/e/1FAIpQLScmkxKpesSroNG0GYxuUS8ruOIjObQ1otITffpBoBPhFQvXBw/viewform


С бэками созванивались два раза.
Первый созвон был для знакомства с командой. На нём нужно было рассказать о себе. Я, конечно, волновался, потому что не очень понимал, что рассказать о себе. Но, послушав остальных, сумел кое-как рассказать о своем опыте и навыках. Команда подобралась разношерстная.
Второй созвон оказался интереснее и был посвящён обсуждению начала работы над проектом. Знания некоторых коллег впечатляют, но не могу сказать, чтобы я в целом в чём-то отставал, хотя теперь стало понятно, что в своем стеке надо подтянуть: работу с кастомной моделью пользователя и токенами аутентификации.

В самом начале определился лид команды - самый активный участник группы.
Сейчас, пока продакты исследуют рынок, а проджекты с аналитиками готовят документацию, перед нами стоит задача развернуть проект в репозитории и сделать базовую регистрацию, авторизацию и сброс пароля.
Определились с задачами:
- Организовать "основу" проекта и правила работы в репозитории.
- Сделать авторизацию и регистрацию с использованием Django REST Framework и JSON Web Token.
- Реализовать сброс пароля зарегистрированного пользователя.

Первую задачу взял на себя наш лид. После того, как он всё сделает, а мы это изучим, созвонимся снова и распределим оставшиеся задачи.
На удивление, мне есть, что предложить проекту, а именно у меня есть небольшой опыт работы с JWT аутентификацией между Django и Vue. Конечно, тут всё серьёзнее, чем на моём lkeep.ru, но, тем не менее, я не "хлопаю глазами" и не задаюсь вопросом "а как?".

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

Пост на сайте
Поддержать проект

#Django #Стажировка #LAD_Academy #Backend #Код_на_салфетке #Frontend #Project #Product #Analytic #Vue
🔥8
Что выведет этот код? №1
🔥2
Вчера мы опубликовали первую задачу из рубрики «Полезное из мешка». Задача скорее требовала внимательности, а не специальных знаний.

Общее количество ответов на данный момент 43, из них верных 11, а если вычесть 4-х человек, которые точно знали ответ на задачу, то правильных остаётся всего 7 ответов. Это даже меньше, чем если бы каждый отвечавший выбирал ответ случайным образом :(

Код из задачи:
def get_candy():
candy = 5

def increment_candy():
nonlocal candy
candy += 1
return candy

return increment_candy


result = get_candy()
print('Всего {} конфет.'.format(result))


Объяснение задачи:
В переменную result мы помещаем результат вызова функции get_candy.

Функция get_candy: в ней мы объявляем переменную candy и записываем в неё пять конфет. Далее в ней же создается внутренняя функция increment_candy.

Функция increment_candy: в ней мы объявляем переменную candy нелокальной: то есть работая с этой переменной далее, мы будем обращаться к переменной из внешней функции get_candy - той самой, куда мы записали 5 конфет. Далее мы увеличиваем число конфет в этой переменной на единицу и возвращаем ее значение 6.

Хитрость в том, что функция get_candy (внешняя) не возвращает результат работы функции increment_candy (внутренней). Она лишь возвращает саму эту внутреннюю функцию, не вызывая ее. Чтобы вернуть именно результат ее работы, нужно вызвать эту внутреннюю фунцию, добавив скобки либо в этой строке:

return increment_candy()


либо в этой:
result = get_candy()()



Как вам новая рубрика? Стоит продолжать?

#что_выведет_данный_код #задачи_на_салфетке #python #функции #полезное_из_мешка
🔥12
Коротко о событиях в "Неком проекте"
😁8
Статистика сайта за месяц 03.11-04.12
Автор: Иван Ашихмин

Прошёл ещё месяц и пора изучать статистику.

Растёт доля переходов из поиска. Основными поисковыми запросами по-прежнему являются AIOgram и FreeGPT, а в этом месяце к ним присоединились ещё и запросы про Docker (в основном MailServer) и стажировку в Aston. Удивительно, что на сайте столько постов про Django, а его в запросах почти нет.

Переходы из Telegram, Dzen и прямые заходы практически сравнялись.

В целом меня радует рост поисковой выдачи, но над SEO ещё работать и работать.
К слову, если кто-то из вас разбирается в SEO-оптимизации и сможет подсказать по основным моментам, как и что, буду благодарен 🙂.

В сухом итоге:
- Посетители: Было 500, стало 785. Прирост 57%.
- Переходы из Dzen: Было 12.6%, стало 13.1%. Прирост 3.96%.
- Переходы из Telegram-канала: Было 18%, стало 11.6%. Падение 35.55%.
- Переходы из поиска: Было 48.1%, стало 58.3%. Прирост 21.20%.
Релиз Django 5.0
Автор: Иван Ашихмин

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

4 декабря, Django Team представили релиз фреймворка Django 5.0.

Примечания к выпуску подробно охватывают все изменения и новые функции, но вот несколько ключевых моментов:
- Значения по умолчанию, вычисляемые базой данных, позволяют определять значения по умолчанию, вычисляемые базой данных, для полей модели.
- Продолжая тенденцию расширения Django ORM, сгенерированное поле модели, позволяет создавать столбцы, сгенерированные базой данных.
- В шаблонную систему была добавлена концепция группы полей для упрощения отображения полей формы.

Список изменений Django 5.0 на русском языке

Установить Django 5.0 можно из PyPi или используя pip:
pip install Django5.0
🔥3