Skip to main content

Execute Django ORM queries directly from the admin interface

Project description

Django Admin Query Executor

A powerful Django admin extension that allows you to execute Django ORM queries directly from the admin interface. It supports complex queries including Q() objects, annotations, aggregations, and all standard Django ORM methods.

Django Admin Query Executor Python Support License

Screenshot 2025-07-17 at 2 42 18 PM

Features

  • Direct Query Execution: Execute Django ORM queries directly from the admin changelist view
  • Seamless Integration: Query results replace the standard admin list view
  • Full Django ORM Support: Use Q(), F(), Count(), Sum(), Avg(), and other Django model functions
  • Custom Imports: Add your own modules, functions, and classes to the query execution environment
  • Query History: Automatically saves your recent queries for quick re-execution
  • Favorite Queries: Save frequently used queries with custom names
  • Collapsible Interface: Clean, collapsible UI that doesn't clutter your admin
  • Comprehensive Dark Mode Support:
    • Automatically adapts to system preferences
    • Compatible with Django admin's built-in dark mode
    • Works with popular admin themes (Grappelli, Jazzmin, etc.)
    • Smooth transitions between light and dark themes
    • Accessible color contrasts in both modes
  • Security: Queries execute in a restricted environment with whitelisted functions
  • Smart Result Detection: Automatically handles both queryset and scalar results

Installation

pip install django-admin-query-executor

Quick Start

Using in Django Admin (QueryExecutorMixin)

  1. Add django_admin_query_executor to your INSTALLED_APPS:
INSTALLED_APPS = [
    ...
    'django_admin_query_executor',
    ...
]
  1. Add the QueryExecutorMixin to your ModelAdmin classes:
from django.contrib import admin
from django_admin_query_executor import QueryExecutorMixin
from .models import MyModel

@admin.register(MyModel)
class MyModelAdmin(QueryExecutorMixin, admin.ModelAdmin):
    list_display = ['id', 'name', 'created_at']

    # Optional: Define custom example queries for this model
    query_examples = [
        ("Active items", "MyModel.objects.filter(is_active=True)"),
        ("Recent items", "MyModel.objects.filter(created_at__gte=timezone.now() - timedelta(days=7))"),
        ("Count by status", "MyModel.objects.values('status').annotate(count=Count('id'))"),
    ]

Using as Standalone Function (execute_django_query)

You can also use the query executor outside the admin interface in your views, management commands, APIs, Celery tasks, or scripts:

from django_admin_query_executor import execute_django_query
from myapp.models import Book

# Execute a query from a string
result = execute_django_query(
    "objects.filter(price__gte=20).count()",
    Book
)
print(f"Books priced $20 or more: {result}")

# With custom imports
custom_imports = {
    'json': 'json',
    'timedelta': ('datetime', 'timedelta'),
}
books = execute_django_query(
    "objects.filter(created_date__gte=now() - timedelta(days=30))",
    Book,
    custom_imports=custom_imports
)

Function Signature:

execute_django_query(query_string, model, custom_imports=None)

Parameters:

  • query_string (str): The Django ORM query string to execute
  • model (Model): The Django model class to use as the base model
  • custom_imports (dict, optional): Additional imports to make available in the query

Returns: QuerySet or other result (int, dict, etc.) depending on the query

Raises: ValueError if there's a syntax error or execution error in the query

Use Cases:

  • Django management commands for running scheduled queries
  • API endpoints that accept dynamic query strings
  • Celery tasks for background query execution
  • Admin actions with custom query logic
  • Testing and debugging scripts

See example_usage.py for detailed examples including usage in management commands, views, APIs, and Celery tasks.

Usage (Admin Interface)

  1. Navigate to any model's admin changelist that uses QueryExecutorMixin
  2. Click "Execute Django Query" to expand the query interface
  3. Enter your Django ORM query (e.g., MyModel.objects.filter(status='active'))
  4. Click "Execute Query"
  5. The admin list updates to show your query results

Query Examples

# Filter queries
Book.objects.filter(author__name__icontains='Smith')
Book.objects.filter(Q(title__icontains='Django') | Q(title__icontains='Python'))

# Annotations and aggregations
Book.objects.annotate(review_count=Count('reviews')).filter(review_count__gt=10)
Book.objects.aggregate(avg_price=Avg('price'), total_books=Count('id'))

# Complex queries with joins
Author.objects.filter(books__published_date__year=2023).distinct()
Book.objects.select_related('author', 'publisher').filter(price__lt=50)

# Counting and existence checks
Book.objects.filter(category='Fiction').count()
Book.objects.filter(reviews__rating__gte=4).exists()

# Using custom imports (see Custom Imports section)
Book.objects.filter(title__in=json.loads('[\"Book1\", \"Book2\"]'))
Book.objects.filter(created_date__gte=datetime.now() - timedelta(days=30))

Standalone Function Examples

from django_admin_query_executor import execute_django_query
from myapp.models import Book, Author

# Basic filtering
active_books = execute_django_query("objects.filter(is_active=True)", Book)

# Count query
count = execute_django_query("objects.filter(price__gte=20).count()", Book)

# Annotations
stats = execute_django_query(
    "objects.aggregate(avg_price=Avg('price'), total=Count('id'))",
    Book
)

# Complex queries with Q objects
books = execute_django_query(
    "objects.filter(Q(category='Fiction') | Q(category='Mystery'))",
    Book
)

# With custom imports
result = execute_django_query(
    "objects.filter(published_date__gte=now() - timedelta(days=30))",
    Book,
    custom_imports={
        'timedelta': ('datetime', 'timedelta'),
        'now': ('django.utils.timezone', 'now'),
    }
)

Configuration

Custom Imports

You can add custom modules, functions, and classes to the query execution environment in two ways:

Method 1: Django Settings (Global)

Add a QUERY_EXECUTOR_CUSTOM_IMPORTS setting to your Django settings file:

# settings.py
QUERY_EXECUTOR_CUSTOM_IMPORTS = {
    # Import entire modules
    'json': 'json',
    'datetime': 'datetime',
    'timedelta': 'datetime.timedelta',
    'timezone': 'django.utils.timezone',

    # Import specific functions/classes from modules
    'settings': ('django.conf', 'settings'),
    'Decimal': ('decimal', 'Decimal'),

    # Import your custom models and functions
    'Listing': 'numi.models.Listing',
    'Coin': 'numi.models.Coin',
    'custom_function': 'myapp.utils.custom_function',
}

Method 2: ModelAdmin Class Attribute (Per-Admin)

Override the custom_imports attribute in your ModelAdmin:

@admin.register(PossibleMatch)
class PossibleMatchAdmin(QueryExecutorMixin, admin.ModelAdmin):
    # Custom imports specific to this admin
    custom_imports = {
        'json': 'json',
        'settings': ('django.conf', 'settings'),
        'Listing': 'numi.models.Listing',
        'Coin': 'numi.models.Coin',
        'timedelta': ('datetime', 'timedelta'),
        'now': ('django.utils.timezone', 'now'),
    }

    query_examples = [
        ("High confidence matches", "PossibleMatch.objects.filter(textual_score__gt=0.8, image_score__gt=0.8)"),
        ("Recent matches", "PossibleMatch.objects.filter(textual_match_date__gte=now() - timedelta(days=7))"),
        ("Using settings", "PossibleMatch.objects.filter(textual_score__gte=settings.TEXTUAL_SCORE_CUTOFF)"),
        ("With JSON data", "PossibleMatch.objects.filter(id__in=json.loads('[1, 2, 3]'))"),
    ]

Import Format Examples

custom_imports = {
    # Simple module imports
    'json': 'json',                    # import json
    'os': 'os',                        # import os

    # Import specific items from modules
    'settings': ('django.conf', 'settings'),              # from django.conf import settings
    'timezone': ('django.utils', 'timezone'),             # from django.utils import timezone
    'timedelta': ('datetime', 'timedelta'),               # from datetime import timedelta
    'Decimal': ('decimal', 'Decimal'),                    # from decimal import Decimal

    # Import your custom models
    'User': ('django.contrib.auth.models', 'User'),      # from django.contrib.auth.models import User
    'MyModel': ('myapp.models', 'MyModel'),               # from myapp.models import MyModel

    # Import custom functions/utilities
    'my_function': ('myapp.utils', 'my_function'),        # from myapp.utils import my_function
    'calculate_score': ('myapp.scoring', 'calculate_score'),
}

Custom Change List Templates

The mixin automatically overrides the ModelAdmin's change_list_template if the default template is in use. If your ModelAdmin uses a custom template, the template will need to extend admin/query_executor_change_list.html:

{% extends "admin/query_executor_change_list.html" %}

Custom Example Queries

Define model-specific example queries by adding a query_examples attribute to your ModelAdmin:

class BookAdmin(QueryExecutorMixin, admin.ModelAdmin):
    query_examples = [
        ("Bestsellers", "Book.objects.filter(is_bestseller=True)"),
        ("By price range", "Book.objects.filter(price__gte=20, price__lte=50)"),
        ("Review stats", "Book.objects.annotate(avg_rating=Avg('reviews__rating')).filter(avg_rating__gte=4.0)"),
        ("Using custom imports", "Book.objects.filter(created_date__gte=now() - timedelta(days=30))"),
    ]

Customizing Query History

Control the number of queries saved in history:

class BookAdmin(QueryExecutorMixin, admin.ModelAdmin):
    query_history_limit = 10  # Default is 5

Supported Django ORM Features

Query Methods

  • filter(), exclude(), get()
  • order_by(), reverse(), distinct()
  • values(), values_list()
  • select_related(), prefetch_related()
  • annotate(), aggregate()
  • first(), last(), exists(), count()

Query Expressions

  • Q() for complex queries
  • F() for field references
  • Count(), Sum(), Avg(), Max(), Min()
  • Case(), When() for conditional expressions
  • Exists(), OuterRef(), Subquery()

Database Functions

  • String functions: Lower(), Upper(), Length(), Concat()
  • Date functions: TruncDate(), Extract(), Now()
  • Type casting: Cast(), Coalesce()

Dark Mode Support

The package includes comprehensive dark mode support that:

  • Auto-detects your system's color scheme preference
  • Integrates seamlessly with Django admin's native dark mode
  • Supports popular admin themes including:
    • Django's built-in dark mode
    • Grappelli dark theme
    • Django Jazzmin dark mode
    • Django Admin Interface dark themes
  • Provides smooth transitions when switching between themes
  • Ensures accessibility with proper color contrasts
  • Includes custom CSS variables for easy customization

Customizing Dark Mode Colors

You can override the default colors by adding CSS variables to your admin CSS:

.query-executor-container {
    --qe-bg-primary: #1a1a1a;
    --qe-text-primary: #ffffff;
    --qe-button-primary-bg: #007bff;
    /* See query_executor_dark_mode.css for all available variables */
}

Security

The query executor runs in a restricted environment with:

  • Whitelisted functions and classes only
  • No access to private attributes or methods
  • No direct database access beyond Django ORM
  • No file system or network access
  • Custom imports are loaded with error handling
  • Failed imports are logged but don't break functionality

Requirements

  • Django >= 3.2
  • Python >= 3.8

License

MIT License - see LICENSE file for details

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

API Reference

execute_django_query(query_string, model, custom_imports=None)

Standalone function for executing Django ORM queries from text strings outside the admin interface.

Parameters:

  • query_string (str): Django ORM query string (e.g., "objects.filter(status='active').count()")
  • model (django.db.models.Model): The Django model class to query
  • custom_imports (dict, optional): Additional modules/functions to make available
    • Format: {alias: module_path} or {alias: (module_path, attribute)}
    • Example: {'json': 'json', 'MyModel': ('myapp.models', 'MyModel')}

Returns:

  • QuerySet, int, dict, or other result depending on the query

Raises:

  • ValueError: If there's a syntax error or execution error in the query

Security:

  • Queries execute in a restricted environment with whitelisted functions only
  • No access to private attributes, file system, or network
  • Custom imports are loaded with error handling

Example:

from django_admin_query_executor import execute_django_query
from myapp.models import Book

# Simple usage
books = execute_django_query("objects.filter(price__lt=30)", Book)

# With custom imports
result = execute_django_query(
    "objects.filter(created__gte=now() - timedelta(days=7))",
    Book,
    custom_imports={
        'timedelta': ('datetime', 'timedelta'),
        'now': ('django.utils.timezone', 'now'),
    }
)

Changelog

1.2.0 (TBD)

  • Added standalone execute_django_query() function for use outside admin interface
  • Function can be used in management commands, views, APIs, Celery tasks, and scripts
  • Refactored internal implementation to share code between mixin and standalone function

1.1.0 (2025-01-17)

  • Added custom imports support via Django settings and ModelAdmin attribute

1.0.0 (2025-07-17)

  • Initial release
  • Full Django ORM query support
  • Query history and favorites
  • Dark mode support
  • Collapsible interface

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_admin_query_executor-1.2.0.tar.gz (25.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_admin_query_executor-1.2.0-py3-none-any.whl (20.1 kB view details)

Uploaded Python 3

File details

Details for the file django_admin_query_executor-1.2.0.tar.gz.

File metadata

File hashes

Hashes for django_admin_query_executor-1.2.0.tar.gz
Algorithm Hash digest
SHA256 c95215b122de0a9ebfec5f2079d2594155c809bd06f2c0461a3a489aa6a31d7f
MD5 36be36f3b5531acd51d8932566c20be8
BLAKE2b-256 33b036d9a76aafb6b177b18cac52284787e6ebe4e6a90aa945be54425aea1183

See more details on using hashes here.

File details

Details for the file django_admin_query_executor-1.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_admin_query_executor-1.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 f6accf89e20b3aaba925481686f69c138bcc6abf8c0207dbbfceff7cde8b4e89
MD5 ac3ce006a7228b7c2592004bbe985a01
BLAKE2b-256 d5b8cad021a3f9ba1810d5d33b708cf0af03bc1828a0af3c4f58a1ecfda783b1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page