Skip to main content

django-shopify-toolkit

PyPI Version Python Versions Django Versions License: MIT

A reusable, installable Django app that gives any Django project Shopify Admin GraphQL integration out of the box — working database tables, an admin-registered ShopifyStore model with encrypted credentials, and a Python API (plus optional REST endpoints) for products, staged image uploads, product variants and options, orders, customers, webhooks, and bulk data exports.

The package is multi-tenant: one Django install can manage many Shopify stores, each with its own encrypted credentials. Every service function takes an explicit ShopifyStore — there is no global or default store.


Key Features

  • Modern GraphQL (2024-07 through 2026-07+): Full compatibility with Shopify's latest GraphQL APIs (productVariantsBulkCreate, stagedUploadsCreate, fulfillmentCreateV2).
  • Multi-Tenant & Encrypted: Stores encrypted access tokens and API secrets per tenant using django-encrypted-model-fields.
  • Fail-Safe Sanitization: Automatically handles currency symbols ($, €), comma decimals, non-numeric strings, and weight unit normalizations (kg, lbs, oz, grams).
  • Staged Image Uploads: Direct binary file uploads to Shopify CDN via Staged Uploads.
  • Webhook Receiver & Signal Dispatcher: Built-in HMAC SHA-256 verification and webhook_received Django signals.
  • Asynchronous Bulk Operations: Query hundreds of thousands of records via Shopify's JSONL bulk export pipeline.
  • Typed Exceptions: Catch clean typed exceptions (ShopifyGraphQLError, ShopifyUserError, ShopifyRateLimitError, ShopifyStoreNotConfigured) instead of raw HTTP errors.

Requirements

  • Python 3.10, 3.11, or 3.12
  • Django 4.2 or 5.x

Installation

pip install django-shopify-toolkit

# With optional Django REST Framework serializers and viewsets
pip install django-shopify-toolkit[drf]

# With test helpers for your own test suite
pip install django-shopify-toolkit[testing]

Quick Start

1. Configure settings.py

Add shopify_toolkit and encrypted_model_fields to INSTALLED_APPS:

INSTALLED_APPS = [
    ...,
    "encrypted_model_fields",
    "shopify_toolkit",
]

# 32-byte base64-encoded key used to encrypt store access tokens in the database
FIELD_ENCRYPTION_KEY = os.environ.get("FIELD_ENCRYPTION_KEY", "your-32-byte-base64-key")

SHOPIFY_TOOLKIT = {
    "API_VERSION": "2026-01",  # "2025-10", "2025-07", "2024-07", etc.
    "APP_TYPE": "custom",       # "custom" (private app) or "public" (OAuth)
    "CLIENT_ID": os.environ.get("SHOPIFY_CLIENT_ID", ""),
    "CLIENT_SECRET": os.environ.get("SHOPIFY_CLIENT_SECRET", ""),
    "SCOPES": ["read_products", "write_products", "read_orders", "write_orders", "read_customers"],
}

2. Run Migrations

python manage.py migrate

Usage Guide

1. Connecting a Shopify Store

from shopify_toolkit.models import ShopifyStore

store, created = ShopifyStore.objects.get_or_create(
    shop_domain="your-store.myshopify.com",
    defaults={
        "access_token": "shpat_xxxxxxxxxxxxxxxxxxxxx",
        "api_version": "2026-01",
        "is_active": True,
    }
)

2. Products & Staged Image Uploads

from shopify_toolkit.products import services as products
from shopify_toolkit.images import services as images

# Create a Product
product = products.create_product(
    store,
    title="Nimbus Running Shoes",
    vendor="Apex Athletics",
    status="ACTIVE",
    description_html="<p>Lightweight high-performance running shoes.</p>"
)

# Upload a Local Image File directly to Shopify CDN
with open("shoe_photo.jpg", "rb") as file_obj:
    media = images.upload_product_image_file(
        store,
        product_id=product.id,
        file_source=file_obj,
        filename="shoe_photo.jpg",
        alt_text="Nimbus Running Shoes - Side View"
    )

# Or attach an image from a public URL
image = images.add_product_image(
    store,
    product_id=product.id,
    src="https://images.unsplash.com/photo-1542291026-7eec264c27ff",
    alt_text="Nimbus Red"
)

# List Products (paginated)
page = products.list_products(store, first=20)
for prod in page.products:
    print(prod.title, len(prod.variants), len(prod.images))

3. Product Options & Variants

# 1. Create Options (e.g. Size, Color)
option = products.create_product_option(
    store,
    product_id=product.id,
    name="Size",
    values=["US 9", "US 10", "US 11"]
)

# 2. Create Variant with Price, SKU, Weight, and Image attachment
variant = products.create_product_variant(
    store,
    product_id=product.id,
    price="139.99",
    compare_at_price="179.99",
    sku="NIMBUS-RED-10",
    weight=0.75,
    weight_unit="lbs",
    media_id=media.id,
    option_values=[{"optionName": "Size", "name": "US 10"}]
)

# 3. Update Variant
products.update_product_variant(
    store,
    product_id=product.id,
    variant_id=variant.id,
    price="129.99",
    sku="NIMBUS-RED-10-SALE"
)

# 4. List Variants
variants = products.list_product_variants(store, product.id)

4. Orders & Fulfillments

from shopify_toolkit.orders import services as orders

# List Orders
orders_page = orders.list_orders(store, first=25)

# Get Single Order
order = orders.get_order(store, "gid://shopify/Order/123456789")

# Fulfill an Order via FulfillmentOrder
orders.update_fulfillment_status(
    store,
    fulfillment_order_id="gid://shopify/FulfillmentOrder/987654321",
    tracking_number="1Z9999999999999999",
    tracking_company="UPS",
    notify_customer=True
)

# Iterate over all orders across pages
for order in orders.iter_all_orders(store):
    print(order.name, order.total_price, order.fulfillment_status)

5. Customers

from shopify_toolkit.customers import services as customers

# Create Customer
customer = customers.create_customer(
    store,
    first_name="Ada",
    last_name="Lovelace",
    email="ada@example.com",
    phone="+1234567890"
)

# List Customers
cust_page = customers.list_customers(store, first=30)

6. Webhooks & Signal Handling

# urls.py - exposes POST /shopify/webhooks/receive/
from django.urls import include, path

urlpatterns = [
    ...,
    path("shopify/webhooks/", include("shopify_toolkit.webhooks.urls")),
]

Incoming webhooks are automatically verified using HMAC SHA-256 and saved as WebhookEvent models. You can also react to webhooks anywhere in your project using Django signals:

from django.dispatch import receiver
from shopify_toolkit.signals import webhook_received

@receiver(webhook_received)
def on_order_created(sender, store, topic, payload, event, **kwargs):
    if topic == "orders/create":
        order_id = payload.get("id")
        print(f"New order received for {store.shop_domain}: {order_id}")

7. Asynchronous Bulk Operations

For datasets with tens of thousands of records, run Shopify Bulk Operations:

from shopify_toolkit.bulk_operations import services as bulk

# Run asynchronous bulk query
operation = bulk.run_bulk_query(
    store,
    query="{ products { edges { node { id title variants { edges { node { id sku price } } } } } } }"
)

# Wait for Shopify to complete the job and download JSONL results
completed_op = bulk.wait_for_bulk_operation(store, poll_interval=2.0, timeout=300.0)
records = bulk.download_bulk_operation_result(completed_op)

8. Testing Your Code

from shopify_toolkit.testing import mock_shopify_api, mock_shopify_error

def test_product_query(shopify_store):
    with mock_shopify_api(shopify_store, {"data": {"products": {"edges": []}}}):
        # Code under test
        ...

def test_api_error_handling(shopify_store):
    with mock_shopify_error(shopify_store, "Shopify API Throttled"):
        # Code under test raises ShopifyGraphQLError
        ...

License

MIT License.

Metadata

Release files for django-shopify-toolkit 1.0.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-shopify-toolkit 1.0.1
File Size Uploaded
django_shopify_toolkit-1.0.1.tar.gz 51.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-shopify-toolkit 1.0.1
File Interpreter ABI Platform
django_shopify_toolkit-1.0.1-py3-none-any.whl Python 3 none any Details

Total release size: 100.6 kB

Release files / django_shopify_toolkit-1.0.1.tar.gz

Download URL django_shopify_toolkit-1.0.1.tar.gz
Size 51.9 kB
Tags Source
SHA-256 checksum
How to use checksums
14dd6fd86117a876695c6ab3e9051ea9b2f4ca479eb51544920ae44e688f41dc
BLAKE2b-256 checksum
How to use checksums
b1b892fdb59e912049095a8512f0d98b1ba5a64372ce2460f2d9684eab4947ae
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.

Transparency log

Release files / django_shopify_toolkit-1.0.1-py3-none-any.whl

Download URL django_shopify_toolkit-1.0.1-py3-none-any.whl
Size 48.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0c4a6c76410f30620a349c9b39424ac3ba18a0437d2642559ca72a29f8ae53f4
BLAKE2b-256 checksum
How to use checksums
83776bd9ea8f74a4b8f693c28ead5ad1af62ccb4167cd7e6c8056d887a7cad93
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 20, 2026.

Transparency log

Release history Release notifications | RSS feed

1.2.0

2 release files

1.0.2

2 release files

This release

1.0.1 This release

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page