Connect Django to Xata
Learn how to connect your Django application to Xata's PostgreSQL platform. Get started with Django and PostgreSQL for robust web applications.
Prerequisites
- Xata account and project setup
- Python 3.8+ installed
- Basic knowledge of Python and Django
Setup Xata Database
First, set up your Xata database with the common e-commerce dataset:
- Create a project and branch in the Xata console
- Navigate to the Queries tab in your branch
- Run the following SQL commands to create the initial schema:
CREATE TABLE products (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
price NUMERIC(7,2) NOT NULL,
rating INTEGER
);
CREATE TABLE orders (
id SERIAL PRIMARY KEY,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE order_items (
order_id INTEGER REFERENCES orders(id),
product_id INTEGER REFERENCES products(id),
qty INTEGER NOT NULL,
PRIMARY KEY (order_id, product_id)
);
Create Django Project
Create a new Django project:
pip install django psycopg2-binary
django-admin startproject my_xata_app
cd my_xata_app
python manage.py startapp store
Initialize Xata Project
Initialize your Xata project configuration:
xata init
This will create a .xata
directory with your project configuration.
Store Your Credentials
Create a .env
file in your project root to store your Xata connection string:
# .env
DATABASE_URL="postgresql://username:password@host:port/database"
Get your connection string from the Xata console or CLI:
xata branch url
Important: Never commit your .env
file to version control. Add it to your .gitignore
file.
Install Dependencies
Install additional dependencies:
pip install python-decouple
Configure Database Connection
Update your settings.py
to use the Xata PostgreSQL database:
# my_xata_app/settings.py
import os
from decouple import config
# ... existing settings ...
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': config('DB_NAME', default='postgres'),
'USER': config('DB_USER', default='postgres'),
'PASSWORD': config('DB_PASSWORD', default=''),
'HOST': config('DB_HOST', default='localhost'),
'PORT': config('DB_PORT', default='5432'),
}
}
# Add 'store' to INSTALLED_APPS
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'store', # Add this line
]
Create a .env
file with the database components:
# .env
DB_NAME=your_database_name
DB_USER=your_username
DB_PASSWORD=your_password
DB_HOST=your_host
DB_PORT=5432
Create Models
Create your Django models in store/models.py
:
# store/models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=255)
price = models.DecimalField(max_digits=7, decimal_places=2)
rating = models.IntegerField(null=True, blank=True)
def __str__(self):
return self.name
class Order(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return f"Order {self.id} - {self.created_at}"
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
qty = models.IntegerField()
class Meta:
unique_together = ['order', 'product']
def __str__(self):
return f"{self.qty}x {self.product.name} in Order {self.order.id}"
Create Views
Create views in store/views.py
:
# store/views.py
from django.shortcuts import render
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
import json
from .models import Product, Order, OrderItem
def product_list(request):
products = Product.objects.all()
data = [{
'id': product.id,
'name': product.name,
'price': float(product.price),
'rating': product.rating
} for product in products]
return JsonResponse(data, safe=False)
def product_detail(request, product_id):
try:
product = Product.objects.get(id=product_id)
data = {
'id': product.id,
'name': product.name,
'price': float(product.price),
'rating': product.rating
}
return JsonResponse(data)
except Product.DoesNotExist:
return JsonResponse({'error': 'Product not found'}, status=404)
@csrf_exempt
@require_http_methods(["POST"])
def create_product(request):
try:
data = json.loads(request.body)
product = Product.objects.create(
name=data['name'],
price=data['price'],
rating=data.get('rating')
)
return JsonResponse({
'id': product.id,
'name': product.name,
'price': float(product.price),
'rating': product.rating
}, status=201)
except Exception as e:
return JsonResponse({'error': str(e)}, status=500)
def order_list(request):
orders = Order.objects.prefetch_related('orderitem_set__product').all()
data = []
for order in orders:
for item in order.orderitem_set.all():
data.append({
'order_id': order.id,
'created_at': order.created_at.isoformat(),
'product_name': item.product.name,
'qty': item.qty,
'total': float(item.product.price * item.qty)
})
return JsonResponse(data, safe=False)
Configure URLs
Update your main urls.py
:
# my_xata_app/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('store.urls')),
]
Create store/urls.py
:
# store/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('products/', views.product_list, name='product_list'),
path('products/<int:product_id>/', views.product_detail, name='product_detail'),
path('products/create/', views.create_product, name='create_product'),
path('orders/', views.order_list, name='order_list'),
]
Run Migrations
Since you're using an existing database schema, you can create a migration that matches your existing tables:
python manage.py makemigrations --empty store
Then edit the generated migration file to use RunSQL
:
# store/migrations/0001_initial.py
from django.db import migrations
class Migration(migrations.Migration):
initial = True
dependencies = []
operations = [
migrations.RunSQL("""
CREATE TABLE IF NOT EXISTS store_product (
id SERIAL PRIMARY KEY,
name VARCHAR(255) NOT NULL,
price NUMERIC(7,2) NOT NULL,
rating INTEGER NULL
);
"""),
migrations.RunSQL("""
CREATE TABLE IF NOT EXISTS store_order (
id SERIAL PRIMARY KEY,
created_at TIMESTAMPTZ DEFAULT NOW()
);
"""),
migrations.RunSQL("""
CREATE TABLE IF NOT EXISTS store_orderitem (
id SERIAL PRIMARY KEY,
order_id INTEGER REFERENCES store_order(id),
product_id INTEGER REFERENCES store_product(id),
qty INTEGER NOT NULL,
UNIQUE(order_id, product_id)
);
"""),
]
Run the migration:
python manage.py migrate
Run the Application
Start your development server:
python manage.py runserver
Your API will be available at:
http://localhost:8000/api/products/
http://localhost:8000/api/orders/
Test Your API
You can test the endpoints using curl:
# Get all products
curl http://localhost:8000/api/products/
# Create a new product
curl -X POST http://localhost:8000/api/products/create/ \
-H "Content-Type: application/json" \
-d '{"name":"Wireless Headphones","price":99.99,"rating":5}'
# Get orders with products
curl http://localhost:8000/api/orders/
Next Steps
- Explore Xata branching for development workflows
- Learn about schema changes with zero downtime
- Join our Discord community for help and support