---
title: Интеграция с Django
description: Подключение Payme, Click, Uzum, Paynet и Octo к проекту на Django через PayTechUZ: настройки, модели, webhook и обработка callback.
source: https://pay-tech.uz/ru/docs/integrations/django
---

# Интеграция с Django

Полное руководство по интеграции PayTechUZ с Django приложениями.

:::tip Готовые примеры проектов

Ищете готовые Django проекты? У нас есть комплексные примеры для различных платёжных сценариев:

- **🛒 [Пример Shop](https://github.com/PayTechUz/Shop)** - Полная интеграция электронной коммерции с **платежами на основе заказов** через Payme, Click. Идеально для интернет-магазинов и маркетплейсов.

- **🚕 [Пример Taxi](https://github.com/PayTechUz/Taxi)** - Полная реализация **пополнения баланса кошелька** через Payme, Click, Uzum. Идеально для сервисных приложений, служб такси и систем на основе баланса.

Оба примера включают полную настройку Django, обработчики вебхуков и готовый к продакшену код!
:::

## Установка

Установите PayTechUZ с поддержкой Django:

```bash
pip install paytechuz[django]
```

## Настройки Django

Добавьте конфигурацию PayTechUZ в настройки Django:

:::note
Вы можете удалить конфигурацию для платёжных провайдеров, которые вам не нужны. Настраивайте только те провайдеры, которые планируете использовать в вашем проекте.
:::

```python
# settings.py

INSTALLED_APPS = [
    # ...
    'paytechuz.integrations.django',
]

PAYTECHUZ = {
    'PAYME': {
        'PAYME_ID': 'your_payme_id',
        'PAYME_KEY': 'your_payme_key',
        'ACCOUNT_MODEL': 'payment.models.Invoice',  #  Your invoice model
        'ACCOUNT_FIELD': 'id',
        'AMOUNT_FIELD': 'amount',
        'ONE_TIME_PAYMENT': True,
        'IS_TEST_MODE': True,  # Set to False in production
    },
    'CLICK': {
        'SERVICE_ID': 'your_service_id',
        'MERCHANT_ID': 'your_merchant_id',
        'MERCHANT_USER_ID': 'your_merchant_user_id',
        'SECRET_KEY': 'your_secret_key',
        'ACCOUNT_MODEL': 'payment.models.Invoice',
        'ACCOUNT_FIELD': 'id',
        'COMMISSION_PERCENT': 0.0,
        'ONE_TIME_PAYMENT': True,
        'IS_TEST_MODE': True,  # Set to False in production
    },
    'UZUM': {
        'SERVICE_ID': 'your_service_id',  # ID сервиса Uzum для Biller URL
        'USERNAME': 'your_uzum_username',  # Для Basic Auth вебхука
        'PASSWORD': 'your_uzum_password',  # Для Basic Auth вебхука
        'ACCOUNT_MODEL': 'payment.models.Invoice',
        'ACCOUNT_FIELD': 'id',  # или 'id'
        'AMOUNT_FIELD': 'amount',
        'ONE_TIME_PAYMENT': True, # Set to False if you want to allow multiple payments for the same invoice
        'IS_TEST_MODE': True,  # Установите False в продакшене
    },
    'PAYNET': {
        'MERCHANT_ID': 'your_merchant_id',  # Paynet Merchant ID
        'SERVICE_ID': 'your_paynet_service_id',
        'USERNAME': 'your_paynet_username',
        'PASSWORD': 'your_paynet_password',
        'ACCOUNT_MODEL': 'payment.models.Invoice',
        'ACCOUNT_FIELD': 'id',
        'AMOUNT_FIELD': 'amount',
        'ONE_TIME_PAYMENT': True,
        'IS_TEST_MODE': True,
    },
    'OCTO_BANK': {
        'OCTO_SHOP_ID': 42125,  # Octo Shop ID
        'OCTO_SECRET': 'your_octo_secret',  # Octo Secret Key
        'OCTO_UNIQUE_KEY': 'your_octo_unique_key',  # Required in production
        'NOTIFY_URL': 'https://example.com/webhooks/octo/',  # Callback URL
        'ACCOUNT_MODEL': 'payment.models.Invoice',
        'ACCOUNT_FIELD': 'id',
        'AMOUNT_FIELD': 'amount',
        'ONE_TIME_PAYMENT': True,
        'TEST_MODE': True,
    }
}
```

:::warning Проверка подписи Octo
`TEST_MODE: True` отключает проверку подписи колбэка. Перед выходом в прод
поставьте `False` и укажите `OCTO_UNIQUE_KEY`, который выдаёт команда Octo —
без него вебхук не запустится.
:::

Создайте модели для обработки заказов и платежей:

```python
# shop/models.py
from django.db import models
from django.contrib.auth.models import User

class Order(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    product_name = models.CharField(max_length=255)
    total_amount = models.DecimalField(max_digits=12, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Order {self.id} - {self.product_name}"

# payment/models.py
from django.db import models
from django.contrib.auth.models import User
from django.utils import timezone
from shop.models import Order  # Import Order from shop app

class Invoice(models.Model):
    STATUS_CHOICES = (
        ('pending', 'Pending'),
        ('paid', 'Paid'),
        ('cancelled', 'Cancelled'),
    )

    user = models.ForeignKey(User, on_delete=models.CASCADE)
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    amount = models.DecimalField(max_digits=12, decimal_places=2)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
    created_at = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return f"Invoice {self.id} for Order {self.order.id}"
```

## Представления (Views)

Создайте представления для обработки платежей:

:::note
Вам нужно создавать webhook представления только для тех платёжных провайдеров, которые вы используете. Удалите импорты и классы для ненужных провайдеров.
:::

```python
# payment/views.py
from paytechuz.integrations.django.views import (
    BasePaymeWebhookView,
    BaseClickWebhookView,
    BaseUzumWebhookView,
    BasePaynetWebhookView,
    BaseOctoWebhookView,
)

from payment.models import Invoice
from shop.models import Order

class PaymeWebhookView(BasePaymeWebhookView):
    def successfully_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'paid'
        invoice.save()

    def cancelled_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'cancelled'
        invoice.save()

    def get_check_data(self, params, account): # optional
        """
        Return additional data for CheckPerformTransaction (fiscal receipt)

        You can override this method to return additional data for fiscal receipt
        """
        return {
            "additional": {"first_name": account.user.first_name}, # optional
            "detail": { # optional
                "receipt_type": 0,
                "shipping": {"title": "Yetkazib berish", "price": 10000},
                "items": [
                    {
                        "discount": 0,
                        "title": account.product_name,
                        "price": account.amount,
                        "count": 1,
                        "code": "00001",
                        "units": 1,
                        "vat_percent": 0,
                        "package_code": "123456"
                    }
                ]
            }
        }

class ClickWebhookView(BaseClickWebhookView):
    def successfully_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'paid'
        invoice.save()

    def cancelled_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'cancelled'
        invoice.save()

    def successfully_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'paid'
        invoice.save()

    def cancelled_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'cancelled'
        invoice.save()

class UzumWebhookView(BaseUzumWebhookView):
    def successfully_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'paid'
        invoice.save()

    def cancelled_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'cancelled'
        invoice.save()

class PaynetWebhookView(BasePaynetWebhookView):
    def successfully_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'paid'
        invoice.save()

    def cancelled_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'cancelled'
        invoice.save()

    def get_check_data(self, params, account):  # опционально
        # Возврат дополнительных данных для GetInformation
        # Вы можете использовать любые пары ключ-значение
        return {
            "fields": {
                "first_name": account.user.first_name,
                "balance": 0  # account.user.balance
            }
        }
class OctoWebhookView(BaseOctoWebhookView):
    def successfully_payment(self, params, transaction):
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'paid'
        invoice.save()

    def cancelled_payment(self, params, transaction):
        # Возврат тоже приходит сюда: оплаченная транзакция станет cancelled
        invoice = Invoice.objects.get(id=transaction.account_id)
        invoice.status = 'cancelled'
        invoice.save()
```

## URL маршруты

Настройте URL маршруты:

:::note
Добавляйте URL маршруты только для тех платёжных провайдеров, которые вы используете. Удалите импорты и пути для ненужных провайдеров.
:::

```python
# urls.py
from django.urls import path
from payment.views import PaymeWebhookView, ClickWebhookView, UzumWebhookView, PaynetWebhookView, OctoWebhookView
from shop.views import OrderCreateView

urlpatterns = [
    # ...
    path('webhooks/payme/', PaymeWebhookView.as_view(), name='payme_webhook'),
    path('webhooks/click/', ClickWebhookView.as_view(), name='click_webhook'),
    path('webhooks/uzum/<str:action>/', UzumWebhookView.as_view(), name='uzum_webhook'),
    path('webhooks/paynet/', PaynetWebhookView.as_view(), name='paynet_webhook'),
    path('webhooks/octo/', OctoWebhookView.as_view(), name='octo_webhook'),
    
    # Order creation endpoint
    path('order/create/', OrderCreateView.as_view(), name='order_create'),
]
```


## Создание платёжных ссылок

Пример представления **Django Rest Framework (DRF)**, которое обрабатывает создание заказа и генерирует платёжную ссылку на основе выбранного платёжного провайдера (без использования сериализаторов):

:::note
Настройте логику так, чтобы она включала только те платежные системы, которые вы хотите поддерживать. Удалите импорты и блоки `elif` для неиспользуемых систем.
:::

```python
# shop/views.py
from django.conf import settings
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status

from paytechuz.gateways.payme import PaymeGateway
from paytechuz.gateways.click import ClickGateway
from paytechuz.gateways.octo import OctoGateway
from payment.models import Invoice

class OrderCreateView(APIView):
    def post(self, request):
        data = request.data
        product_name = data.get('product_name')
        amount = data.get('amount')
        payment_type = data.get('payment_type')  # 'payme', 'click', 'uzum', 'paynet'

        if not all([product_name, amount, payment_type]):
            return Response(
                {'error': 'product_name, amount, and payment_type are required.'},
                status=status.HTTP_400_BAD_REQUEST
            )

        # 1. Create Order
        order = Order.objects.create(
            user=request.user,
            product_name=product_name,
            total_amount=amount
        )

        # 2. Create Invoice linked to the Order
        invoice = Invoice.objects.create(
            user=request.user,
            order=order,
            amount=amount,
            status='pending'
        )

        payment_url = None

        # 3. Generate Payment Link based on payment_type
        if payment_type == 'payme':
            gateway = PaymeGateway(
                payme_id=settings.PAYTECHUZ['PAYME']['PAYME_ID'],
                payme_key=settings.PAYTECHUZ['PAYME']['PAYME_KEY'],
                is_test_mode=settings.PAYTECHUZ['PAYME']['IS_TEST_MODE']
            )
            payment_url = gateway.create_payment(
                id=invoice.id,
                amount=invoice.amount,
                return_url="https://example.com/success",
                account_field_name=settings.PAYTECHUZ['PAYME']['ACCOUNT_FIELD']
            )

        elif payment_type == 'click':
            gateway = ClickGateway(
                service_id=settings.PAYTECHUZ['CLICK']['SERVICE_ID'],
                merchant_id=settings.PAYTECHUZ['CLICK']['MERCHANT_ID'],
                merchant_user_id=settings.PAYTECHUZ['CLICK']['MERCHANT_USER_ID'],
                secret_key=settings.PAYTECHUZ['CLICK']['SECRET_KEY'],
                is_test_mode=settings.PAYTECHUZ['CLICK']['IS_TEST_MODE']
            )
            payment_url = gateway.create_payment(
                id=invoice.id,
                amount=invoice.amount,
                return_url="https://example.com/success"
            )

            payment_url = gateway.create_payment(
                account_id=invoice.id,
                amount=invoice.amount,
            )

        elif payment_type == 'uzum':
            gateway = UzumGateway(
                service_id=settings.PAYTECHUZ['UZUM']['SERVICE_ID'],
                is_test_mode=settings.PAYTECHUZ['UZUM']['IS_TEST_MODE']
            )
            payment_url = gateway.create_payment(
                id=invoice.id,
                amount=invoice.amount,
                return_url="https://example.com/success"
            )

        elif payment_type == 'paynet':
            gateway = PaynetGateway(
                merchant_id=settings.PAYTECHUZ['PAYNET']['MERCHANT_ID'],
                is_test_mode=settings.PAYTECHUZ['PAYNET']['IS_TEST_MODE']
            )
            # Генерация URL платежа Paynet
            # Формат URL: https://app.paynet.uz/?m={merchant_id}&c={payment_id}&a={amount}
            payment_url = gateway.create_payment(
                id=invoice.id,  # ID платежа (параметр c)
                amount=invoice.amount  # сумма в тийинах (опционально, параметр a)
            )
            # Или без суммы (сумма будет настроена на стороне Paynet)
            # payment_url = gateway.create_payment(id=invoice.id)

        elif payment_type == 'octo':
            gateway = OctoGateway(
                octo_shop_id=settings.PAYTECHUZ['OCTO_BANK']['OCTO_SHOP_ID'],
                octo_secret=settings.PAYTECHUZ['OCTO_BANK']['OCTO_SECRET'],
                notify_url=settings.PAYTECHUZ['OCTO_BANK']['NOTIFY_URL'],
                is_test_mode=settings.PAYTECHUZ['OCTO_BANK']['TEST_MODE']
            )
            # Одностадийный платёж (auto_capture), возвращает ссылку Octo
            payment_url = gateway.create_payment(
                id=invoice.id,
                amount=invoice.amount,  # в сумах
                return_url="https://example.com/success",
                description=f"Invoice #{invoice.id}"
            )

        return Response({
            'order_id': order.id,
            'invoice_id': invoice.id,
            'payment_url': payment_url
        }, status=status.HTTP_201_CREATED)
```
