Python для начинающих
1.06K subscribers
280 photos
3 videos
232 files
61 links
Python для начинающих
Download Telegram
Какие задачи на реальных проектах Python решает контейнеризация с помощью Docker.
Контейнеризация с Docker: как Python-проекты обретают суперсилу

Если вы когда-либо разворачивали Python-проект "голыми руками" — на сыром сервере, с настройкой окружения, системными пакетами, разрушающими зависимости, и мистическими багами, которые возникают только в "бою", то Docker для вас — как спасательный круг для утопающего.

Контейнеризация — это не просто модный термин, а реальное решение извечных проблем с "у меня работает". И для Python-проектов она особенно ценна.

Представим типичную ситуацию: у команды есть несколько микросервисов на Python — один парсит веб-сайты, второй обрабатывает данные, третий отдает API. Каждый использует разные версии библиотек, системных зависимостей, переменных окружения. Проблема номер один — воспроизводимость. Без Docker попытка развернуть всё это на сервере превращается в танцы с бубном.

С Docker каждый микросервис получает своё изолированное окружение. У вас есть Dockerfile — рецепт, по которому собирается образ: нужная версия Python, точные зависимости из requirements.txt, переменные, команды запуска. Команда docker build — и у вас готовый артефакт, который будет одинаково работать на разработке, в CI/CD или на проде.

Пример:

// Dockerfile
FROM python:3.10-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD "python", "main.py"

Это — вся магия запуска Python-приложения в изоляции. Никакого "где искать libxml2", никаких конфликтов версий pip или глобального Python.

Ещё одна суперспособность Docker — масштабирование. Например, для обработки миллионов задач вы запускаете несколько контейнеров с celery worker'ами. Они берут задачи из Redis, обрабатывают в параллели, и масштабируются по нагрузке. Не нужен отдельный сервер, просто запускаете больше контейнеров — и всё.

Также Docker незаменим в CI/CD. При пуше в Git ваш пайплайн может собрать Docker-образ, прогнать тесты в контейнере, и задеплоить его на сервер или в Kubernetes. Весь путь — от кода до продакшена — автоматизирован и стабилен.

А как насчет разработки? Docker позволяет создать docker-compose.yml, где в одном файле описываются все сервисы: база данных, бекенд, очереди, фронт — всё запускается одной командой docker-compose up. Нужно PostgreSQL для разработки? Просто добавьте:

services:
db:
image: postgres:14
environment:
POSTGRESUSER: user
POSTGRES
PASSWORD: pass

И вы работаете с полноценной базой в пару кликов.

Контейнеры решают задачи не только инфраструктуры, но и тестирования. Вы можете запускать юнит-тесты в izолированном контейнере, чтобы быть уверенным: никакие артефакты системы не влияют на поведение кода.

И наконец, контейнеризация — это комфорт и уверенность. Ваш Python-код живёт в предсказуемом, управляемом окружении. Вы точно знаете, как он будет работать, и можете легко обновлять, переносить и масштабировать свой проект.

Docker стал неотъемлемой частью современного Python-стека. Он не делает код лучше, но делает работу с кодом — быстрее, стабильнее и безопаснее. А это уже немалый шаг к зрелой разработке.
Как работать с разреженными матрицами с использованием библиотеки SciPy.
Иногда меньше — это больше. Особенно, когда речь заходит о матрицах, в которых абсолютное большинство элементов равны нулю. Такие матрицы называются разреженными (sparse), и если хранить их как обычные двумерные массивы в NumPy, то можно легко потратить кучу памяти впустую. Вот тут на сцену выходит библиотека SciPy с модулем scipy.sparse — быстрым, компактным и удобным инструментом для работы с разреженными матрицами.

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

Начнем с Compressed Sparse Row (CSR) — формат, удобный для быстрого умножения матриц и извлечения строк.

Пример:

from scipy.sparse import csr_matrix

data = [1, 2, 3]
rows = [0, 1, 2]
cols = [2, 0, 1]

sparse_matrix = csr_matrix((data, (rows, cols)), shape=(3, 3))
print(sparse_matrix)


Вывод:

  (0, 2) 1
(1, 0) 2
(2, 1) 3


Для сравнения, обычная матрица размером 10000x10000 потребляет почти 800 МБ памяти. А если в ней всего 0.01% ненулевых элементов, то разреженное представление на тех же данных использует минимум ресурсов.

Следующий формат — Compressed Sparse Column (CSC), оптимален для извлечения по столбцам. Создать такую матрицу можно просто вызвав .tocsc() у CSR:

csc_example = sparse_matrix.tocsc()


Еще один полезный тип — LIL (List of Lists). Он хорош для пошагового добавления элементов:

from scipy.sparse import lil_matrix

matrix_lil = lil_matrix((3, 3))
matrix_lil[0, 1] = 5
matrix_lil[1, 2] = 8
print(matrix_lil)


После наполнения её удобно конвертировать в CSR или CSC для дальнейших операций:

matrix_final = matrix_lil.tocsr()


Хотите работать с матрицами как с NumPy? Легко. Многие операции поддерживаются напрямую: сложение, умножение, транспонирование, извлечение подматриц. Но важно помнить: несмотря на общее API, sparse-матрицы — это не обычные ndarray. Прямой доступ к элементам может быть менее производителен, а вызовы типа .toarray() тянут действительную матрицу в память — осторожно с большими массивами!

Узнать плотность матрицы просто:

density = sparse_matrix.count_nonzero() / (sparse_matrix.shape[0] * sparse_matrix.shape[1])
print(f"Density: {density:.6f}")


Если результат меньше 0.01 — вы точно всё делаете правильно.

SciPy позволяет даже решать системы линейных уравнений и выполнять разложение sparse-матриц. Например:

from scipy.sparse.linalg import spsolve

A = csr_matrix([[3, 0, 1], [0, 4, 0], [1, 0, 2]])
b = [5, 8, 5]
x = spsolve(A, b)
print(x)


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

Так что если ваши матрицы — это в основном нули, не спешите забивать ими память. SciPy.sparse превращает недостаток в преимущество.
Расширенные возможности Pandas для обработки временных рядов.
Когда речь заходит об анализе временных рядов в Python, вездесущий pandas вызывает заслуженное уважение. Базовые возможности, такие как преобразование даты формата строки в datetime, или ресемплирование данных — уже почти рефлекс у каждого начинающего аналитика. Но сегодня я хочу показать вам кое-что посерьезнее. Pandas умеет гораздо больше, и это может по-настоящему сократить вам время и расширить горизонт возможностей.

Допустим, у нас есть DataFrame с погодными данными:

import pandas as pd

df = pd.read_csv('weather.csv', parse_dates=['timestamp'], index_col='timestamp')


Первое, на что стоит обратить внимание — это метод .asfreq() для смены частоты без усреднения. Например, если у нас почасовые данные, а мы хотим просто увидеть дневные “срезы”:

daily_df = df.asfreq('D')


Но зачастую данные нужно агрегировать. Вот тут вступает .resample() — он похож на .groupby(), но для времени:

mean_temp_per_day = df['temperature'].resample('D').mean()


Вроде бы ничего нового. Но вы знали, что можно использовать нестандартные правила частоты? Например, 'W-MON' даст недельную агрегацию с понедельника:

weekly_data = df.resample('W-MON').agg({'temperature': 'max', 'humidity': 'mean'})


А теперь магия: скользящие окна. Метод .rolling() — это ваш билет в мир сглаживания и анализа трендов:

df['temp_7d_avg'] = df['temperature'].rolling(window='7D').mean()


Обратите внимание: начиная с pandas 1.2 можно задавать окно в формате времени, не только в числах. Это даёт гибкость: окно “7 дней назад” будет учитывать фактические интервалы, а не просто 7 строк.

Идём глубже. Предположим, вы анализируете временной ряд с пропущенными значениями. В pandas есть умные способы заполнения:

df['temperature'] = df['temperature'].interpolate(method='time')


Интерполяция по времени — гораздо лучше "затыкания дыр" средним. Она учитывает временные интервалы, что важно для равномерности.

А теперь маленький шедевр: работа с временными “offsets”. Например, мы хотим сдвинуть данные на два месяца вперёд:

df_shifted = df.shift(periods=2, freq='M')


Не просто сдвинуть по индексам — а сместить даты! Это особенно удобно при сравнении "текущих" и "прошлогодних" метрик.

Финальный штрих — .between_time() и .at_time(). Когда вы работаете с данными по минутам или часам и хотите анализировать, например, только дневное время активности:

daytime_df = df.between_time('09:00', '18:00')


и

df_at_noon = df.at_time('12:00')


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

Pandas — не просто инструмент для таблиц. Это полноценный движок анализа данных по времени, скрывающий под капотом куда больше, чем кажется. Настройка частот, смещения, агрегирования, скользящие окна — всё это можно комбинировать для создания точных и наглядных аналитических инструментов. И в этом кроется сила.
Как создать приложение для мониторинга сети с использованием Scapy.
Как создать приложение для мониторинга сети с использованием Scapy.
Привет! Сегодня мы с вами разберем, как с помощью Python и мощного сетевого инструмента Scapy создать простое, но функциональное приложение для мониторинга сети. Этот инструмент стоит того, чтобы познакомиться с ним поближе: он позволяет захватывать, анализировать и даже генерировать сетевые пакеты. А главное — делать это в пару строк кода.

Что такое Scapy? Это библиотека, написанная на Python, которая дает полный контроль над сетевыми пакетами. Она позволяет легко писать собственные снифферы, сканеры и даже фреймы для тестирования безопасности. Нам же сегодня нужен сниффер — простой монитор сетевого трафика.

Устанавливается Scapy командой:

pip install scapy

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

from scapy.all import sniff, IP, TCP

def processpacket(packet):
if packet.haslayer(IP) and packet.haslayer(TCP):
ip
src = packetIP.src
ipdst = packet[IP].dst
port
src = packetTCP.sport
portdst = packet[TCP].dport
print(f"TCP Packet: {ip
src}:{portsrc} -> {ipdst}:{portdst}")

sniff(filter="tcp", prn=process
packet, store=0)

Что здесь происходит:

- sniff — основная функция для захвата пакетов.
- filter="tcp" — захватываем только TCP-пакеты (можно задавать любой pcap-фильтр: например, "udp", "icmp", "port 80").
- prn=processpacket — указываем функцию, которая будет вызываться для каждого пакета.
- store=0 — не сохраняем пакеты в память, чтобы избежать утечек при длительной работе.

Функция process
packet проверяет, содержит ли пакет уровни IP и TCP, и если да — выводит адреса отправителя и получателя, а также порты.

А теперь немного улучшений. Допустим, мы хотим видеть только трафик HTTP. Вспомним, что стандартный порт HTTP — 80. Добавим проверку на это:

def processpacket(packet):
if packet.haslayer(IP) and packet.haslayer(TCP):
port
dst = packetTCP.dport
if portdst == 80:
ip
src = packetIP.src
ipdst = packet[IP].dst
print(f"HTTP request from {ip
src} to {ipdst}")

Хотим ещё круче? Добавим логгирование в файл, чтобы потом можно было проанализировать происходящее:

import logging
logging.basicConfig(filename="netmon.log", level=
logging.INFO)

def process
packet(packet):
if packet.haslayer(IP) and packet.haslayer(TCP):
ipsrc = packet[IP].src
ip
dst = packetIP.dst
portsrc = packet[TCP].sport
port
dst = packetTCP.dport
logentry = f"{ipsrc}:{portsrc} -> {ipdst}:{portdst}"
logging.info(logentry)

Так мы получаем файл netmon.log, в котором накапливается информация обо всех TCP-соединениях.

Scapy дает гораздо больше, чем просто мониторинг. Можно парсить DNS-запросы, определять операционные системы, делать ARP-сканы, захватывать пароли — всё это в пределах одной библиотеки.

Наш мониторинг пока базовый, но даёт отличную основу для развития: вы можете строить систему оповещений, графики активности или даже мини firewall. Главное — не забывайте, что захват трафика на чужих сетях без разрешения незаконен! Используйте Scapy с умом и по назначению.

На этом всё — до встречи в следующем посте!
👍1
Работа с учётом контекста в Python: базовые конструкции и примеры применения.
Python — язык, который поощряет чистоту, читаемость и элегантность. И одно из самых мощных проявлений этих качеств — конструкции контекстного менеджмента. Возможно, ты уже встречал волшебное слово with, но не совсем понимал, что именно происходит под капотом. Давай разберёмся.

Представим себе файл. Мы его открываем, читаем, а потом… забываем закрыть. Вроде бы ничего страшного — но если таких забытых файлов десятки, появляются утечки ресурсов. Контекстные менеджеры помогают гарантировать, что нужные действия будут выполнены автоматически, даже если в процессе произойдёт ошибка.

Базовый пример:

with open('data.txt', 'r') as file:
content = file.read()

После выхода из блока with Python сам вызовет file.close(). Удобно и безопасно.

Но фокус в том, что можно писать свои контекстные менеджеры! Чтобы понять, как это работает, вспомним о двух магических методах:

- enter()
- exit()

Создадим простой таймер:

import time

class Timer:
def enter(self):
self.start = time.time()
return self
def exit(self, exctype, excval, exctb):
self.end = time.time()
print(f'Time elapsed: {self.end - self.start:.4f} seconds')

Теперь используем:

with Timer():
total = sum(i**2 for i in range(1000000))

Контекст открылся, засеклось время. После выхода — замер завершился, результат выведен.

Но писать собственные классы с enter и exit — не всегда удобно. Тут приходит модуль contextlib. Он предлагает простой способ создавать менеджеры контекста из функций.

Пример с contextlib.contextmanager:

from contextlib import contextmanager

@contextmanager
def change
directory(path):
import os
prevdir = os.getcwd()
os.chdir(path)
try:
yield
finally:
os.chdir(prev
dir)

Вот такой элегантный способ временно сменить директорию:

with changedirectory('/tmp'):
print('We are here:', os.getcwd())

После выхода — возвращаемся туда, откуда пришли. Даже если внутри блока произойдёт исключение.

А теперь чуть более продвинутый трюк: подавление ошибок. Модуль contextlib помогает снова:

from contextlib import suppress

with suppress(ZeroDivisionError):
print(1 / 0) # Ошибка будет проигнорирована

Очень полезно, когда есть неважные операции, которые могут не сработать, и их не хочется оборачивать в try/except.

И наконец: если ты работаешь с ресурсами — файлами, соединениями, блокировками — знай, что многие библиотеки уже поддерживают контекстные менеджеры. Например, threading.Lock:

import threading

lock = threading.Lock()

with lock:
# безопасный доступ к ресурсу
do
something()

Безопасность, лаконичность, надёжность — вот за что мы любим with. Он делает код чище и устойчивее к ошибкам. А знание, как писать свои менеджеры контекста, открывает путь к по-настоящему выразительному Python-коду.
Советы по интеграции Python и R для расширенного анализа данных.
Вы когда-нибудь задумывались, зачем использовать язык R, если у вас уже есть Python? Или наоборот? Казалось бы, оба отлично справляются с анализом данных. Но вот в чём соль: Python — это универсальный инструмент, бог с ним, швейцарский нож программиста. А R — это математика на стероидах. Его богатые статистические возможности делают его настоящим кладом для сложного анализа. В этом посте я расскажу, как объединить оба языка, чтобы выжать максимум из каждого.

🐍 + 📊 = ❤️

Для интеграции Python и R существует несколько способов, но самые удобные и популярные — это использование библиотек rpy2 и Jupyter с R-клетками через ipython-magic. Начнём с rpy2.

📦 Установка:

Убедитесь, что R установлен в вашей системе, затем:

pip install rpy2

Теперь магия:

from rpy2 import robjects

robjects.r('x <- rnorm(100)')
robjects.r('meanx <- mean(x)')
mean
x = robjects.r('meanx')[0]
print("Mean from R:", mean
x)

Здесь мы генерируем данные в стиле R, вычисляем среднее и забираем его обратно в Python. Очень удобно, когда у вас есть мощные R-пакеты вроде 'caret', 'forecast' или 'ggplot2', но вы хотите оборачивать их в пайтоновских скриптах.

Хочется смешивать код без лишнего бойлера? Тогда пришло время познакомиться с IPython magic-командой %%R. Установите R-кернел:

R
> install.packages("IRkernel")
> IRkernel::installspec()

Теперь в Jupyter:

%loadext rpy2.ipython

А в самой ячейке:

%%R
x <- rnorm(100)
print(summary(x))

Да-да, просто пишете R-код в Python-ноутбуке. Удобство в чистом виде.

🔁 Передача переменных

Обмен данными между языками возможен. Из Python в R:

import numpy as np
from rpy2.robjects import numpy2ri
numpy2ri.activate()

data = np.random.normal(size=100)
robjects.globalenv['x'] = data
robjects.r('summary(x)')

И обратно:

mean
r = robjects.r('mean(x)')0
print(meanr)

📊 Дополнительный бонус — визуализация. Например, используйте ggplot2:

robjects.r('''
library(ggplot2)
df <- data.frame(x=rnorm(100), y=rnorm(100))
p <- ggplot(df, aes(x=x, y=y)) + geom
point()
print(p)
''')

Такой подход отлично подходит, если вы уже строите пайплайны в Python, а кто-то в команде держится за проверенные R-инструменты. Или вы просто хотите построить точный статистический анализ без костылей.

Итог: интеграция Python и R — это не борьба за первенство, а мощный симбиоз. Используйте Python для автоматизации и потоков, а R — для глубоких аналитических выкопок. Вместе они могут гораздо больше.
Как разрабатывать VPN-приложения на основе Python.
Как разрабатывать VPN-приложения на основе Python.
Как разрабатывать VPN-приложения на основе Python

VPN — это не просто модный термин из мира информационной безопасности. Это реальный рабочий механизм, который позволяет шифровать трафик, обходить блокировки и защищать соединение в публичных сетях. Интересно, что с помощью Python можно построить простое VPN-приложение буквально с нуля — и это совсем не магия, а знание и немного кода.

Основная идея VPN — создание защищённого туннеля между клиентом и сервером, внутри которого весь сетевой трафик проходит в зашифрованном виде. В Python мы можем реализовать подобную функциональность, используя стандартные библиотеки socket и ssl, а также сторонние — такие как pycryptodome для дополнительного шифрования.

Начнем с основы — создадим шифрованное TCP-соединение. Допустим, у нас есть клиент и сервер, которые общаются по TLS:

Пример серверной части:

import socket
import ssl

context = ssl.create_default_context(ssl.Purpose.CLIENT_AUTH)
context.load_cert_chain(certfile='cert.pem', keyfile='key.pem')

bind_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
bind_socket.bind(('0.0.0.0', 9000))
bind_socket.listen(5)

while True:
new_socket, addr = bind_socket.accept()
conn = context.wrap_socket(new_socket, server_side=True)
data = conn.recv(1024)
print(f"Received: {data}")
conn.sendall(b'Encrypted Hello from VPN Server!')
conn.close()


Пример клиента:

import socket
import ssl

context = ssl.create_default_context()
conn = context.wrap_socket(socket.socket(socket.AF_INET), server_hostname='localhost')
conn.connect(('localhost', 9000))
conn.sendall(b'Hello from Client')
print(f"Server says: {conn.recv(1024)}")
conn.close()


Это уже зашифрованное соединение! На более высоком уровне мы можем добавить маршрут через этот туннель, используя iptables на Linux или прокси-настройки на других системах. Но стоит заметить: этот способ безопасен только внутри локального проекта, для полноценного VPN нужны туннелирование на уровне IP (например, средствами TUN/TAP).

Для работы с такими интерфейсами в Python можно использовать модуль pyroute2 (работает под Linux). Вот пример настройки туннеля:

from pyroute2 import IPRoute
ip = IPRoute()
idx = ip.link_create(ifname='tun0', kind='tun')
ip.addr('add', index=idx, address='10.0.0.1', prefixlen=24)
ip.link('set', index=idx, state='up')


Создав интерфейс, можно направлять трафик через него и обрабатывать поступающие IP-пакеты с помощью raw-сокетов. Например, чтобы захватить пакеты и переслать через защищённый TCP, мы можем использовать socket.socket с типом socket.SOCK_RAW.

Дополнительно, для шифрования полезной нагрузки можно подключить AES:

from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes

key = get_random_bytes(16)
cipher = AES.new(key, AES.MODE_EAX)

data = b'Secret payload'
ciphertext, tag = cipher.encrypt_and_digest(data)
print(ciphertext)


Таким образом, VPN-приложение на Python может включать в себя:
- шифрованный TCP-туннель (через ssl);
- работу с сетевыми интерфейсами (через pyroute2);
- обработку и маршрутизацию IP-пакетов (через raw-сокеты и TUN);
- шифрование всех данных (через pycryptodome).

Конечно, это всё требует продуманной архитектуры, обработки ошибок и аутентификации. Настоящий VPN — больше, чем просто код: это защита всего маршрута данных. Но начать проще, чем кажется. Python даёт достаточный инструментарий, чтобы понимать, как всё устроено на самом деле.

Звучит как вызов? Отлично. Потому что любой хороший девелопер любит разбираться в инфраструктуре, не только писать логику веб-приложений. VPN на Python — это именно тот случай, когда ты понимаешь, как работает интернет изнутри.
👍41
Как использовать Apache Beam с Python для обработки потоков данных.
Когда дело доходит до обработки больших объемов данных в реальном времени, на сцену выходит Apache Beam — мощный инструмент с лаконичным API на Python. Эта библиотека позволяет писать единый код как для пакетной, так и для потоковой обработки, который затем можно выполнить на разных движках: Apache Flink, Google Cloud Dataflow, Spark и других.

Представим себе поток логов от веб-приложения: каждый лог — это JSON с информацией о пользователе, времени и действии. Нужно агрегировать количество кликов по страницам — и желательно делать это непрерывно. Как?

Устанавливаем Beam:

pip install apache-beam


Теперь создадим простой pipeline, который будет считать количество кликов по каждой странице за определённый промежуток времени.

import apache_beam as beam
from apache_beam.options.pipeline_options import PipelineOptions
from datetime import datetime
import json

class ParseEvent(beam.DoFn):
def process(self, element):
event = json.loads(element)
timestamp = datetime.strptime(event['timestamp'], "%Y-%m-%dT%H:%M:%S")
yield beam.window.TimestampedValue(event, timestamp.timestamp())

class ExtractPage(beam.DoFn):
def process(self, event):
yield (event['page'], 1)

with beam.Pipeline(options=PipelineOptions()) as p:
events = (
p
| 'ReadFromSocket' >> beam.io.ReadFromText('events.json') # для простоты: читаем из файла
| 'ParseEvent' >> beam.ParDo(ParseEvent())
| 'WindowIntoFixed' >> beam.WindowInto(beam.window.FixedWindows(60)) # окна по 60 секунд
| 'ExtractPage' >> beam.ParDo(ExtractPage())
| 'CountPerPage' >> beam.CombinePerKey(sum)
| 'PrintResults' >> beam.Map(print)
)


Вот что здесь происходит:

- Чтение данных (в реальности это может быть сокет, Kafka или Pub/Sub).
- ParseEvent превращает строку JSON в объект и прикрепляет временную метку, чтобы Beam мог "понять", к какому окну относится событие.
- WindowIntoFixed разбивает поток по временным окнам — здесь это фиксированные 60-секундные интервалы.
- ExtractPage — извлекаем имя страницы, по которой был клик.
- CombinePerKey(sum) — просто считаем количество кликов по каждой странице в каждом окне.

Beam заботится о многих "тяжёлых" вещах сам: повторная попытка обработки, управление временем и поздними событиями, масштабирование, параллелизм.

Особенность Beam — в "watermark"-подходе: он умеет понимать, когда данные за конкретное окно можно считать полученными с достаточной полнотой, и тогда он “закрывает” окно. Это делает Beam удобной основой для real-time аналитики в больших системах.

И да, Beam — не замена Pandas или обычному Python-скрипту. Он нужен, когда объёмы данных становятся больше возможностей одной машины, а результаты нужно получать почти мгновенно.

В следующем шаге можно заменить источник данных на apache_beam.io.kafka.ReadFromKafka, использовать сессионные окна или включить таймеры — всё, как в серии про настоящую потоковую обработку данных.

Apache Beam с Python — не просто модный инструмент, а реальный способ построить масштабируемую ETL-систему, которая справится даже с нестабильными потоками от миллионов пользователей. Если вы думали, что Python — язык только для аналитиков, Beam разрушит это представление.
Создание собственной системы управления контентом (CMS) с использованием Django.
На этой неделе я решил затронуть тему, которая волнует многих начинающих разработчиков: создание собственной системы управления контентом (CMS) на Django. Часто при изучении фреймворка мы учимся делать блоги, страницы и формы. Но что, если попробовать сделать нечто большее — свою CMS? Управляемый контент, возможность редактирования без кода, гибкое расширение — звучит вдохновляюще? Тогда поехали.

С чего начать? Django уже практически готов для построения CMS. У него есть админка, модели, формы, авторизация, шаблоны — всё, что нужно новичку для уверенного старта.

Создадим базу: установим Django и создадим проект.

django-admin startproject cms_project
cd cms_project
python manage.py startapp core


В core создаём первую модель — ContentPage:

from django.db import models

class ContentPage(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)
body = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)

def __str__(self):
return self.title


Подключим её в админку:

from django.contrib import admin
from .models import ContentPage

admin.site.register(ContentPage)


Теперь, зайдя в admin-панель, можно добавлять страницы с уникальным slug и текстом. Но наша цель — чтобы эти страницы отдавались по соответствующему URL, не создавая вручную views под каждую.

Создаём "умный" view:

from django.shortcuts import get_object_or_404, render
from .models import ContentPage

def content_page_view(request, slug):
page = get_object_or_404(ContentPage, slug=slug)
return render(request, 'core/page.html', {'page': page})


И URL-шаблон:

from django.urls import path
from .views import content_page_view

urlpatterns = [
path('<slug:slug>/', content_page_view, name='content_page'),
]


Всё. Теперь любой контент с определённым slug — например, "about" — будет доступен по адресу /about/. Но что, если хотим, чтобы администратор мог задавать не только текст, но и типы блоков? Представим блок "цитата", "изображение + текст", "галерея".

Решение: отдельные модели блоков.

class PageBlock(models.Model):
page = models.ForeignKey(ContentPage, related_name='blocks', on_delete=models.CASCADE)
block_type = models.CharField(max_length=50, choices=[
('text', 'Text'),
('quote', 'Quote'),
('image', 'Image'),
])
content = models.TextField()
order = models.PositiveIntegerField(default=0)

class Meta:
ordering = ['order']


Теперь страницы можно собирать как конструктор: добавлять разнообразные блоки, управлять их порядком. Через админку пользователь собирает страницу сам, без кода. В шаблоне просто итерируем blocks и отображаем нужный HTML под каждый тип:

{% for block in page.blocks.all %}
{% if block.block_type == 'text' %}
<p>{{ block.content }}</p>
{% elif block.block_type == 'quote' %}
<blockquote>{{ block.content }}</blockquote>
{% elif block.block_type == 'image' %}
<img src="{{ block.content }}" alt="Image block">
{% endif %}
{% endfor %}


Хочется вложений страниц, как у real CMS? Добавим parent-связь в ContentPage и дорисуем древовидную структуру — можно с помощью django-mptt.

Хотим редактор, вместо plain TextField? Подключаем django-ckeditor и получаем визуальную обработку контента.

В этой архитектуре вся мощь CMS оказывается в руках администратора: он создаёт новые страницы, меняет их, комбинирует блоки — без программирования. Мы же, как разработчики, создаём каркас и логику.

Таким образом, используя стандартный инструментарий Django, мы получаем лёгкую, настраиваемую и расширяемую CMS. Не надо ждать "идеальную" CMS от третьих лиц — можно построить свою. Понятную, минималистичную и под конкретные задачи. И это, по моему личному опыту, куда ценнее универсальных монстров.
👍1
Создание графиков потока работы с помощью диаграмм процессного моделирования BPMN.