Разработка интернет-магазина на Saleor

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

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Разработка интернет-магазина на Saleor
Сложная
от 2 недель до 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

Разработка интернет-магазина на Saleor

Saleor — Python/Django e-commerce платформа с GraphQL API как единственным интерфейсом. Стек: Django 4.x + Graphene-Django, PostgreSQL, Celery + Redis для фоновых задач, OpenTelemetry для трейсинга. Архитектурно Saleor — headless по умолчанию: бэкенд предоставляет GraphQL API, фронтенд строится отдельно (официальный starter на Next.js — saleor/storefront).

Архитектура Saleor

┌─────────────────────────────────────┐
│         Saleor Core (Django)         │
├──────────────┬──────────────────────┤
│  GraphQL API │  REST Webhooks       │
│  (Graphene)  │  (Events)            │
├──────────────┴──────────────────────┤
│     Channel System (мультирегион)    │
├──────────┬────────────┬─────────────┤
│ Products │  Checkout  │  Orders     │
│ + Attrs  │  + Payments│  + Shipping │
├──────────┴────────────┴─────────────┤
│  PostgreSQL │ Redis │ Celery        │
└─────────────────────────────────────┘

Ключевая концепция Saleor — Channel (канал): каждый канал имеет собственную валюту, страны доставки, ценообразование, правила складского учёта. Один продукт может быть доступен в нескольких каналах с разными ценами.

Установка и начальная конфигурация

# Клонирование и настройка
git clone https://github.com/saleor/saleor.git
cd saleor

# Через Docker Compose (рекомендуется для разработки)
docker compose up -d

# Ручная установка
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt

# Переменные окружения (.env)
cat > .env << 'EOF'
SECRET_KEY=your-django-secret-key-50-chars-min
DATABASE_URL=postgresql://saleor:saleorpass@localhost:5432/saleor
CELERY_BROKER_URL=redis://localhost:6379/0
[email protected]
ALLOWED_HOSTS=localhost,api.example.com
ALLOWED_CLIENT_HOSTS=localhost:3000,store.example.com
AWS_ACCESS_KEY_ID=xxx
AWS_SECRET_ACCESS_KEY=xxx
AWS_STORAGE_BUCKET_NAME=saleor-media
DEFAULT_CHANNEL_SLUG=default-channel
EOF

# Миграции и начальные данные
python manage.py migrate
python manage.py collectstatic --no-input
python manage.py createsuperuser
python manage.py populatedb --createsuperuser  # seed демо-данных

GraphQL API: структура запросов

Весь фронтенд взаимодействует с Saleor через GraphQL. Endpoint: /graphql/.

Получение списка продуктов для канала:

query ProductList($channel: String!, $first: Int!, $after: String) {
  products(channel: $channel, first: $first, after: $after) {
    edges {
      node {
        id
        name
        slug
        description
        thumbnail(size: 800, format: WEBP) { url alt }
        pricing {
          priceRange {
            start { gross { amount currency } }
            stop  { gross { amount currency } }
          }
          onSale
          discount { gross { amount } }
        }
        variants {
          id
          name
          sku
          quantityAvailable(countryCode: RU)
          pricing {
            price { gross { amount currency } }
          }
          attributes {
            attribute { name slug }
            values { name slug }
          }
        }
        category { name slug }
        collections { name slug }
      }
    }
    pageInfo { hasNextPage endCursor }
    totalCount
  }
}

Channel System — мультирегиональность

Channel — ключевой механизм для работы с несколькими рынками:

# Создание канала для российского рынка (Admin GraphQL)
mutation CreateChannel {
  channelCreate(input: {
    name: "Россия"
    slug: "ru"
    currencyCode: "RUB"
    defaultCountry: RU
    countries: [RU, BY, KZ]
    stockSettings: {
      allocationStrategy: PRIORITIZE_HIGH_STOCK
    }
    orderSettings: {
      automaticallyConfirmAllNewOrders: false
      automaticallyFulfillNonShippableGiftCard: true
    }
    checkoutSettings: {
      useLegacyErrorFlow: false
    }
  }) {
    channel {
      id slug name currencyCode
    }
    errors { field message code }
  }
}

Привязка продукта к каналу с ценообразованием:

# saleor/product/models.py — программно через Django ORM
from saleor.product.models import Product, ProductChannelListing
from saleor.channel.models import Channel

channel = Channel.objects.get(slug='ru')
product = Product.objects.get(slug='kurtka-zimnyaya')

listing = ProductChannelListing.objects.create(
    product=product,
    channel=channel,
    is_published=True,
    visible_in_listings=True,
    available_for_purchase_at=timezone.now(),
)

# Цены на варианты
from saleor.product.models import ProductVariant, ProductVariantChannelListing
from saleor.warehouse.models import Warehouse, Stock

variant = ProductVariant.objects.get(sku='JACKET-S-BLACK')
ProductVariantChannelListing.objects.create(
    variant=variant,
    channel=channel,
    price_amount=Decimal('2999.00'),
    currency=channel.currency_code,
)

Кастомные атрибуты и типы продуктов

Saleor использует Product Type → Attribute систему:

# Создание кастомного атрибута
from saleor.attribute.models import Attribute, AttributeValue

material_attr = Attribute.objects.create(
    name='Материал',
    slug='material',
    type=AttributeType.PRODUCT_TYPE,
    input_type=AttributeInputType.DROPDOWN,
    filterable_in_storefront=True,
    filterable_in_dashboard=True,
    available_in_grid=True,
)

for material in ['Хлопок', 'Полиэстер', 'Шерсть', 'Нейлон']:
    AttributeValue.objects.create(
        attribute=material_attr,
        name=material,
        slug=slugify(material, allow_unicode=True),
    )

# Привязка к Product Type
from saleor.product.models import ProductType
product_type = ProductType.objects.get(slug='clothing')
product_type.product_attributes.add(material_attr)

Webhooks и интеграции

Saleor отправляет события через webhooks. Список ключевых событий:

Событие Триггер
ORDER_CREATED Создание заказа
ORDER_PAID Оплата заказа
ORDER_FULFILLED Отгрузка
PRODUCT_UPDATED Изменение продукта
CHECKOUT_FILTER_SHIPPING_METHODS Синхронная фильтрация методов доставки
PAYMENT_GATEWAY_INITIALIZE_SESSION Инициализация платёжной сессии

Регистрация webhook через Admin API:

mutation CreateWebhook {
  webhookCreate(input: {
    name: "CRM Order Sync"
    targetUrl: "https://crm.example.com/saleor/orders"
    events: [ORDER_CREATED, ORDER_PAID, ORDER_CANCELLED]
    secretKey: "webhook-secret-key-here"
    isActive: true
    asyncEvents: [ORDER_CREATED, ORDER_PAID]
    syncEvents: []
  }) {
    webhook { id name targetUrl }
    errors { field message }
  }
}

Обработка webhook:

# В Django view (или FastAPI/любой другой сервис)
import hashlib, hmac
from django.http import JsonResponse

def saleor_webhook(request):
    # Верификация подписи
    signature = request.headers.get('Saleor-Signature', '')
    secret = b'webhook-secret-key-here'
    computed = hmac.new(secret, request.body, hashlib.sha256).hexdigest()

    if not hmac.compare_digest(signature, computed):
        return JsonResponse({'error': 'Invalid signature'}, status=400)

    event_type = request.headers.get('Saleor-Event')
    payload = json.loads(request.body)

    if event_type == 'ORDER_PAID':
        order_id = payload['order']['id']
        sync_order_to_crm.delay(order_id)  # Celery task

    return JsonResponse({'status': 'ok'})

Apps и платёжные провайдеры

Saleor использует концепцию Saleor Apps — отдельные микросервисы, подключаемые через App Store или самостоятельно:

# Кастомный платёжный провайдер через Synchronous Webhooks
# При PAYMENT_GATEWAY_INITIALIZE_SESSION Saleor ожидает синхронный ответ

@app.post("/saleor/payment-gateway-initialize")
async def payment_initialize(request: Request):
    payload = await request.json()

    return {
        "data": {
            "publishableKey": settings.CLOUDPAYMENTS_PUBLIC_ID,
            "currency": payload["sourceObject"]["currency"],
        }
    }

@app.post("/saleor/transaction-initialize")
async def transaction_initialize(request: Request):
    payload = await request.json()
    amount = payload["action"]["amount"]
    currency = payload["action"]["currency"]

    # Создание транзакции в CloudPayments
    transaction = await cloudpayments_client.create_order(amount, currency)

    return {
        "pspReference": transaction["id"],
        "result": "CHARGE_ACTION_REQUIRED",
        "data": {"confirmationToken": transaction["token"]},
        "amount": amount,
        "currency": currency,
        "externalUrl": transaction["url"],
    }

Dashboard (Admin) — Next.js приложение

Официальный Saleor Dashboard — отдельное React/Next.js приложение:

git clone https://github.com/saleor/saleor-dashboard.git
cd saleor-dashboard

cat > .env << 'EOF'
NEXT_PUBLIC_API_URI=https://api.example.com/graphql/
NEXT_PUBLIC_SALEOR_APPS_PAGE_PATH=/extensions
EOF

npm install
npm run dev       # http://localhost:9000
npm run build     # production build

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

# saleor/celeryconf.py уже настроен, добавление кастомных задач:
from celery import shared_task
from django.utils import timezone

@shared_task(bind=True, max_retries=3, default_retry_delay=60)
def sync_inventory_from_erp(self, product_variant_id: str):
    try:
        from saleor.warehouse.models import Stock
        from .erp_client import ErpClient

        client = ErpClient()
        sku = ProductVariant.objects.get(id=product_variant_id).sku
        quantity = client.get_stock(sku)

        Stock.objects.filter(
            product_variant_id=product_variant_id
        ).update(quantity=quantity, quantity_allocated=models.F('quantity_allocated'))

    except Exception as exc:
        raise self.retry(exc=exc)

Производительность и масштабирование

Saleor тяжёл на GraphQL-запросах с глубокими связями. Ключевые настройки:

# settings.py — настройки для production
GRAPHQL_MIDDLEWARE = [
    'saleor.graphql.middleware.OpMetricsMiddleware',
]

# DataLoader включён по умолчанию через Promise/graphene
# Настройка кэша Django для фрагментов
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": os.environ.get("REDIS_URL"),
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100},
        },
        "TIMEOUT": 300,
    }
}

# Query complexity limit
GRAPHQL_QUERY_MAX_COMPLEXITY = 50000
# Nginx: кэширование статических ответов GraphQL (только для публичных)
location /graphql/ {
    proxy_cache_valid 200 1m;
    proxy_cache_key "$request_method$request_uri$request_body";
    proxy_cache_bypass $cookie_session_id;  # не кэшировать авторизованные
}

Sроки разработки

  • Базовая настройка + Saleor Dashboard + Next.js Storefront Starter: 2–3 недели
  • Магазин с кастомными типами продуктов, атрибутами, каналами (2–3 рынка): 5–8 недель
  • Полная e-commerce платформа: кастомные App, интеграции ERP/CRM, кастомные платёжные провайдеры, мультиканальность: 14–20 недель