Девман для питонистов
540 subscribers
161 photos
3 videos
211 links
Веб-разработка на Python. Канал от практиков.

Сайт школы Девман: https://dvmn.org/
Контакт для связи: @yulya_devman
Download Telegram
🎄 Продолжаем наш новогодний Python-интерактив! 🎄

❄️Давайте разберём, запустится ли этот код:

import random

gifts = (
"Годовой запас энергии",
"Новогодняя удача",
"Сбывшаяся мечта",
)


your_gift = random.choice(gifts)
print(f"Ваш подарок: {}")

👉Выбирайте свой вариант ответа в опросе и пишите объяснения в комментариях!
Запустится ли этот код?
Anonymous Poll
51%
Да
49%
Нет
Код не запустится! В f-строку обязательно нужно передать параметр, о чем намекнет линтер, если он настроен в вашей IDE или редакторе. Код не запускается — выдает ошибку SyntaxError. Не забывайте подарки!
👍3😱1
🎄 Продолжаем наш новогодний Python-интерактив! 🎄

❄️Давайте разберём, какой код работает:

Пример 1:
for symbol in ('Новый год!'):
print(symbol)

Пример 2:
python    
for symbol in (2026):
print(symbol)

👉Выбирайте свой вариант ответа в опросе и пишите объяснения в комментариях!
👍1
Цикл for пытается перебрать элементы, содержащиеся в (2026). Однако (2026) — это не коллекция элементов, а одно целое число, заключённое в скобки.

В Python для того, чтобы число стало коллекцией, его нужно представить в виде списка, кортежа или другого итерируемого объекта. Из-за этого при попытке выполнить данный код возникнет ошибка TypeError, указывающая на то, что объект типа int (целое число) не является итерируемым.

А вот “Новый Год” — это строка. Строки в Python являются коллекциями и по ним можно итерировать, т.е. проходить в цикле. Элементом станет каждый символ строки.
5
🤔 Давайте вместе разберемся, что не так с этим кодом?

def predict_rub_salary_hh(hh_vacancy):
if not hh_vacancy or hh_vacancy.get('currency') != 'RUR':
return

salary_from = hh_vacancy.get('from')
salary_to = hh_vacancy.get('to')

if not salary_to and salary_from:
return int(salary_from * 1.2)
if not salary_from and salary_to:
return int(salary_to * 0.8)
if salary_from and salary_to:
return int((salary_from + salary_to) / 2)


def predict_rub_salary_sj(sj_vacancy):
payment_from = sj_vacancy.get('payment_from')
payment_to = sj_vacancy.get('payment_to')
currency = sj_vacancy.get('currency')

if currency != 'rub':
return

if not payment_to and payment_from:
return int(payment_from * 1.2)
if not payment_from and payment_to:
return int(payment_to * 0.8)
if payment_from and payment_to:
return int((payment_from + payment_to) / 2)


👉 Чтобы понять, что можно исправить, загляните в типичные улучшения Девмана.
Копипаста кода — это плохо.

1️⃣ Если код нужно будет поменять — придётся искать все места, где он использовался и менять его везде, по всем файлам.

2️⃣ Если в коде будет ошибка — её не получится исправить разом, в одном месте, придётся опять же искать все места, где использовался этот код и чинить его несколько раз.

3️⃣Чем больше кода — тем труднее его читать.

Код из нашего примера может выглядеть так:
def get_expected_salary(salary_from, salary_to):
if not salary_to and salary_from:
return int(salary_from * 1.2)
if not salary_from and salary_to:
return int(salary_to * 0.8)
if salary_from and salary_to:
return int((salary_from + salary_to) / 2)


def predict_rub_salary_hh(hh_vacancy):
if not hh_vacancy or hh_vacancy.get('currency') != 'RUR':
return

salary_from = hh_vacancy.get('from')
salary_to = hh_vacancy.get('to')

return get_expected_salary(salary_from, salary_to)


def predict_rub_salary_sj(sj_vacancy):
payment_from = sj_vacancy.get('payment_from')
payment_to = sj_vacancy.get('payment_to')
currency = sj_vacancy.get('currency')

if currency.lower() != 'rub':
return

return get_expected_salary(payment_from, payment_to)


P.S. Спасибо нашим подписчикам за внимательное ревью!❤️ По ходу избавились от пустых return и elif. Если еще есть идеи как улучшить код — пишите свои варианты в комментариях!
👍4
🤔 Давайте вместе разберемся, что не так с этим кодом?
from django.db import models


class Owner(models.Model):
...

def __str__(self):
return f'{self.name}'



👉 Чтобы понять, что можно исправить, загляните в типичные улучшения Девмана
Бесполезные преобразования типов приводят к усложнению кода, дополнительным вычислениям и ухудшению производительности.

Код из нашего примера может выглядеть так:
from django.db import models


class Owner(models.Model):
...

def __str__(self):
return self.name
🔥21
Как оптимизировать запросы к БД

«Магия» оптимизации запросов в Django ORM — это один из ключевых навыков для борьбы с перегрузом БД и тормознутостью сайта. Проблемы возникают, если использовать реляционную БД со сложными отношениями между таблицами: ForeignKey, ManyToMany.

📌Пример: запросили из базы список постов. Таблица постов связана с таблицей авторов. Если их не запросить сразу, то на каждый пост придется делать ещё запрос для получения автора. С ростом количества постов это приведет к огромному количеству запросов и перегрузу базы.

✍️Цель и метрики
Изначально хочется минимизировать количество запросов к БД. Но еще есть время обработки запроса на стороне базы данных. Чаще всего время обработки запроса в базе пропорционально количеству запросов, но есть исключения.

✍️Инструменты
В уроках курса по базам данных мы предлагаем использоваться Django Debug Toolbar для замера основных метрик: количество запросов, количество дублей, время обработки запроса на стороне БД, общее время запроса.

✍️Методы Django ORM

➡️`select_related`: один жирный JOIN
select_related использует оператор SQL JOIN (внешнее соединение) чтобы присоединить таблицы связанных объектов по внешнему ключу (ForeignKey или OneToOneField) к основному запросу.

Что происходит:
— Django строит один большой SQL-запрос с JOIN.
— База данных возвращает одну таблицу, где строки дублируются для данных из связанных таблиц. Т.е. если уникальных авторов всего два, то строк в таблице будет столько, сколько постов.
— ORM преобразует эту таблицу в объекты Python, уже связанные между собой.

Когда использовать: Когда вам нужно перемещаться «вперед» по связи — от объекта к связанному (книга -> автор). Идеально для связей «один к одному» и «многие к одному».
# ПЛОХО: N+1 запрос
books = Book.objects.all()
for book in books:
print(book.author.name) # Новый запрос к БД на каждой итерации!

# ХОРОШО: 1 запрос
books = Book.objects.select_related('author').all()
for book in books:
print(book.author.name) # Данные автора уже загружены!

➡️`prefetch_related`: Умная загрузка комплектами

prefetch_related делает отдельные запросы для каждой связи, а затем уже в памяти Python «сшивает» результаты. Python обычно работает медленнее, но база данных освобождается быстрее.

Что происходит:
— Django выполняет первый запрос для получения основных объектов (например, авторов).
— Затем второй запрос (или несколько) для получения ВСЕХ связанных объектов для этих основных (например, всех книг этих авторов).
— В Python ORM создает словарь-кэш и подставляет нужные связанные объекты к каждому основному. Используется оператор SQL IN.
# ПЛОХО: N+1 запрос
authors = Author.objects.all()
for author in authors:
for book in author.books.all(): # Новый запрос на каждом внешнем цикле!
print(book.title)

# ХОРОШО: 2 запроса
authors = Author.objects.prefetch_related('books').all()
for author in authors:
for book in author.books.all(): # Книги для всех авторов уже загружены в кэш!
print(book.title)

✍️Исключения

Иногда на глубоких цепочках (select_related('a__b__c')) JOIN может стать слишком тяжелым, и prefetch_related будет эффективнее.

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

Для метода tag_filter получили статистику на увеличенном вдвое количестве постов в БД с помощью Django Debug Toolbar:

select_related: 31 запрос, SQL ≈ 0.1288s, elapsed ≈ 0.1350s
prefetch_related: 33 запроса, SQL ≈ 0.0922s, elapsed ≈ 0.0980s

При увеличении количества постов результаты сохраняются:
select_related делает на 1-2 запроса меньше,
— время обработки запроса для prefetch_related на 40% меньше

Итого: prefetch_related — лучший вариант оптимизации.

P.S. Но скажем по секрету, если вы использовали любой из методов — это уже неплохо! Ну а проверить что эффективнее, лишним никогда не будет ;-)

P.P.S. Напоминаем, что у нас открыта запись на курс по БД! Успейте забронировать осталось всего два места!

👉 Для записи напишите нам в Телеграм!
1
⚠️ Сайт временно не работает. Чиним.

Сайт работает
Мы заметили, что в последнее время участились случаи мошенничества на собеседованиях и в процессе найма. Поговорили с нашим HR Светланой и собрали «красные флаги», чтобы помочь вам не попасться на удочку к мошенникам!

Случаи мошенничества замечены в Телеграм и на hh.ru — наиболее востребованные каналы по поиску работы в России сейчас. И там, и там админы стараются проверять и блокировать мошенников заранее, но не всегда успевают. Если вы заметили такую активность, поставьте в известность админа и заблокируйте контакт!

Что преследуют мошенники:
— Блокировка устройства с последующим вымогательством — чаще всего для владельцев MacBook;
— Слив паролей, токенов, персональных данных;
— Перехват вашего ТГ-аккаунта;
— Ваши личные данные, при заполнении договора ГПХ или ИП — возможно, оформление кредитов
— И многое другое, что покажется ценным мошенникам

Ссылка на полезные сервисы для проверки компаний:
https://pb.nalog.ru/
https://zachestnyibiznes.ru/
👍5🔥3