Розробка бекенду сайту на Python (Django)

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.
Розробка та обслуговування будь-яких видів сайтів:
Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Розробка бекенду сайту на Python (Django)
Середня
від 1 тижня до 3 місяців
Часті питання
Наші компетенції:
Етапи розробки
Останні роботи
  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Розробка бекенду сайту на Python (Django)

Django — "все з коробки" в буквальному сенсі. ORM, міграції, адмін-панель, аутентифікація, форми, кешування, i18n — все це є з коробки, без вибору бібліотек та інтеграції компонентів. Це робить Django найшвидшим способом запустити повноцінний бекенд, якщо вам не потрібні екзотичні можливості.

Типова область застосування: корпоративні сайти, CMS, портали, API для SPA та мобільних додатків, системи з багатою бізнес-логікою та рольовою моделлю.

Структура проекту

Django-проект складається з проекту та додатків. Гарна практика — робити додатки невеликими та функціонально ізольованими:

myproject/
  manage.py
  config/
    settings/
      base.py
      development.py
      production.py
    urls.py
    wsgi.py
    asgi.py
  apps/
    users/
      models.py
      views.py
      serializers.py  # для DRF
      urls.py
      admin.py
      services.py      # бізнес-логіка окремо від views
      tests/
        test_models.py
        test_views.py
    products/
    orders/
  requirements/
    base.txt
    development.txt
    production.txt

Налаштування ділимо по оточенням та ніколи не комітимо секрети в репозиторій:

# config/settings/base.py
from pathlib import Path
import environ

env = environ.Env()
BASE_DIR = Path(__file__).resolve().parent.parent.parent

SECRET_KEY = env('DJANGO_SECRET_KEY')
DATABASES = {
    'default': env.db('DATABASE_URL', default='postgres://localhost/mydb')
}
CACHES = {
    'default': {
        'BACKEND': 'django_redis.cache.RedisCache',
        'LOCATION': env('REDIS_URL', default='redis://localhost:6379/0'),
        'OPTIONS': {'CLIENT_CLASS': 'django_redis.client.DefaultClient'}
    }
}

Моделі та ORM

Сильна сторона Django — виразна ORM з підтримкою складних запитів:

from django.db import models
from django.contrib.postgres.fields import ArrayField
from django.contrib.postgres.indexes import GinIndex

class Product(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    category = models.ForeignKey('Category', on_delete=models.SET_NULL, null=True)
    attributes = models.JSONField(default=dict)
    tags = ArrayField(models.CharField(max_length=50), default=list)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        indexes = [
            models.Index(fields=['slug']),
            models.Index(fields=['category', 'is_active']),
            GinIndex(fields=['attributes']),  # для пошуку по JSONB
        ]
        ordering = ['-created_at']

    def __str__(self):
        return self.name

Складні запити через annotate, aggregate, prefetch_related:

from django.db.models import Count, Avg, Q, Prefetch

# Отримати категорії з кількістю активних продуктів та середньою ціною
categories = Category.objects.annotate(
    products_count=Count('product', filter=Q(product__is_active=True)),
    avg_price=Avg('product__price', filter=Q(product__is_active=True))
).filter(products_count__gt=0).order_by('-products_count')

# N+1 проблема вирішується через prefetch_related
orders = Order.objects.prefetch_related(
    Prefetch('items', queryset=OrderItem.objects.select_related('product'))
).select_related('user').filter(status='processing')

Django REST Framework

DRF — стандарт для API на Django. Серіалізатори, ViewSets, пагінація:

from rest_framework import serializers, viewsets, permissions, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend

class ProductSerializer(serializers.ModelSerializer):
    category_name = serializers.CharField(source='category.name', read_only=True)

    class Meta:
        model = Product
        fields = ['id', 'name', 'slug', 'price', 'category', 'category_name', 'attributes']
        read_only_fields = ['slug']

    def validate_price(self, value):
        if value <= 0:
            raise serializers.ValidationError('Ціна повинна бути додатною')
        return value

class ProductViewSet(viewsets.ModelViewSet):
    queryset = Product.objects.select_related('category').filter(is_active=True)
    serializer_class = ProductSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
    filterset_fields = ['category', 'is_active']
    search_fields = ['name', 'description']
    ordering_fields = ['price', 'created_at']
    ordering = ['-created_at']

    @action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated])
    def favorite(self, request, pk=None):
        product = self.get_object()
        request.user.favorites.add(product)
        return Response({'status': 'added'})

Аутентифікація

JWT через djangorestframework-simplejwt:

# config/urls.py
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

urlpatterns = [
    path('api/auth/login/', TokenObtainPairView.as_view()),
    path('api/auth/refresh/', TokenRefreshView.as_view()),
]

Користувальницький JWT payload:

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer

class CustomTokenSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['email'] = user.email
        token['role'] = user.role
        return token

Celery для фонових задач

# tasks.py
from celery import shared_task
from django.core.mail import send_mail

@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def send_order_confirmation(self, order_id: int) -> None:
    try:
        order = Order.objects.select_related('user').get(id=order_id)
        send_mail(
            subject=f'Замовлення #{order.id} підтверджено',
            message=render_email_template('order_confirmation', order),
            from_email=settings.DEFAULT_FROM_EMAIL,
            recipient_list=[order.user.email]
        )
    except Order.DoesNotExist:
        # не повторювати — об'єкт не знайдено
        return
    except Exception as exc:
        raise self.retry(exc=exc)

Кешування

from django.core.cache import cache
from django.views.decorators.cache import cache_page
from functools import wraps

# Низькорівневе кешування
def get_popular_products():
    cache_key = 'popular_products'
    result = cache.get(cache_key)
    if result is None:
        result = list(Product.objects.filter(is_active=True).order_by('-views')[:10])
        cache.set(cache_key, result, timeout=300)
    return result

# Інвалідація по тегах через django-cache-memoize
from cache_memoize import cache_memoize

@cache_memoize(300, extra_verbose_cache_key=True)
def get_category_products(category_id: int, page: int = 1):
    # ...

Адмін-панель

Вбудована адмін-панель Django економить тижні роботи:

@admin.register(Product)
class ProductAdmin(admin.ModelAdmin):
    list_display = ['name', 'price', 'category', 'is_active', 'created_at']
    list_filter = ['category', 'is_active', 'created_at']
    search_fields = ['name', 'slug']
    list_editable = ['is_active', 'price']
    prepopulated_fields = {'slug': ('name',)}
    readonly_fields = ['created_at', 'updated_at']

    def get_queryset(self, request):
        return super().get_queryset(request).select_related('category')

Терміни розробки

  • Налаштування проекту, БД, auth — 3–5 днів
  • Моделі + міграції + адмін — 1 тиждень
  • API на DRF — 1–3 тижні залежно від складності
  • Celery + Redis + очереди — 3–5 днів
  • Інтеграції (платежі, email, сторонні API) — 1–2 тижні
  • Тести (pytest-django) — 1 тиждень

Повноцінний бекенд для корпоративного сайту чи портального сайту: 5–10 тижнів. Django окуповується вбудованою адмін-панеллю — часто клієнт управляє контентом через неї без окремої CMS.