chore(root): scafold the project
This commit is contained in:
27 files changed
+1476
No files matched your search
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"project_name": ".",
|
||||
"structure": {
|
||||
"standard": false,
|
||||
"predefined": false,
|
||||
"unified": false,
|
||||
"single": true
|
||||
},
|
||||
"apps": {
|
||||
"nested": false,
|
||||
"nested_dir": null
|
||||
},
|
||||
"settings": {
|
||||
"use_database_url": false,
|
||||
"database_type": "mysql",
|
||||
"use_tailwind": false,
|
||||
"use_htmx": false,
|
||||
"use_vite": true
|
||||
},
|
||||
"cicd": {
|
||||
"github": true,
|
||||
"gitlab": false
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
__pycache__
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.Python
|
||||
*.so
|
||||
.venv
|
||||
venv
|
||||
ENV
|
||||
.env
|
||||
.git
|
||||
.gitignore
|
||||
*.md
|
||||
README*
|
||||
LICENSE
|
||||
.coverage
|
||||
htmlcov
|
||||
.pytest_cache
|
||||
.mypy_cache
|
||||
.ruff_cache
|
||||
.DS_Store
|
||||
node_modules
|
||||
*.log
|
||||
db.sqlite3
|
||||
media
|
||||
staticfiles
|
||||
@@ -0,0 +1,23 @@
|
||||
# Django settings
|
||||
DJANGO_SETTINGS_MODULE=app.settings.development
|
||||
SECRET_KEY=your-secret-key
|
||||
ALLOWED_HOSTS=api.your-domain.com,www.your-domain.com
|
||||
|
||||
# Database (individual parameters)
|
||||
DB_NAME=
|
||||
DB_USER=
|
||||
DB_PASSWORD=
|
||||
DB_HOST=
|
||||
DB_PORT=
|
||||
|
||||
# Frontend URL
|
||||
FRONTEND_URL=https://frontend.your-domain.com,https://www.frontend.your-domain.com
|
||||
|
||||
# Email settings
|
||||
EMAIL_HOST=
|
||||
EMAIL_PORT=
|
||||
EMAIL_USE_TLS=
|
||||
EMAIL_HOST_USER=
|
||||
EMAIL_HOST_PASSWORD=
|
||||
DEFAULT_FROM_EMAIL=
|
||||
SERVER_EMAIL=
|
||||
Vendored
+75
@@ -0,0 +1,75 @@
|
||||
name: Django CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main, develop ]
|
||||
pull_request:
|
||||
branches: [ main, develop ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
python-version: ["3.13"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Python ${{ matrix.python-version }}
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install uv
|
||||
uses: astral-sh/setup-uv@v4
|
||||
with:
|
||||
enable-cache: true
|
||||
cache-suffix: ${{ matrix.python-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: uv sync
|
||||
|
||||
- name: Install Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Build frontend
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
|
||||
- name: Run linting
|
||||
run: uv run ruff check .
|
||||
|
||||
- name: Format check
|
||||
run: uv run ruff format --check .
|
||||
|
||||
- name: Run Django checks
|
||||
env:
|
||||
DJANGO_SETTINGS_MODULE: app.settings.development
|
||||
SECRET_KEY: test-secret-key-for-ci
|
||||
run: |
|
||||
uv run python manage.py check
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
DJANGO_SETTINGS_MODULE: app.settings.development
|
||||
SECRET_KEY: test-secret-key-for-ci
|
||||
run: |
|
||||
uv run python manage.py test
|
||||
|
||||
- name: Check migrations
|
||||
env:
|
||||
DJANGO_SETTINGS_MODULE: app.settings.development
|
||||
SECRET_KEY: test-secret-key-for-ci
|
||||
run: |
|
||||
uv run python manage.py makemigrations --check --dry-run
|
||||
|
||||
- name: Security check
|
||||
env:
|
||||
DJANGO_SETTINGS_MODULE: app.settings.development
|
||||
SECRET_KEY: test-secret-key-for-ci
|
||||
run: |
|
||||
uv run python manage.py check --deploy
|
||||
@@ -0,0 +1,93 @@
|
||||
#--------------------------------------------------#
|
||||
# The following was generated by djinit: #
|
||||
#--------------------------------------------------#
|
||||
|
||||
# Python
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
*.so
|
||||
__pycache__/
|
||||
*.egg-info/
|
||||
dist/
|
||||
build/
|
||||
.eggs/
|
||||
*.egg
|
||||
|
||||
# Django
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
*.sqlite3
|
||||
|
||||
# Environment
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# IDEs
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.project
|
||||
.pydevproject
|
||||
.settings/
|
||||
.ropeproject/
|
||||
|
||||
# OS
|
||||
.DS_Store
|
||||
*.DS_Store
|
||||
Thumbs.db
|
||||
desktop.ini
|
||||
|
||||
# Django specific
|
||||
media/
|
||||
staticfiles/
|
||||
staticfiles/
|
||||
static_root/
|
||||
/static/
|
||||
|
||||
# Testing
|
||||
.coverage
|
||||
htmlcov/
|
||||
.pytest_cache/
|
||||
.tox/
|
||||
coverage.xml
|
||||
*.cover
|
||||
.hypothesis/
|
||||
.cache
|
||||
|
||||
# Logs
|
||||
logs/
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# Node modules (if using frontend tools)
|
||||
node_modules/
|
||||
|
||||
# Secret keys
|
||||
secret.txt
|
||||
secrets.json
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# Backup files
|
||||
*.bak
|
||||
*.tmp
|
||||
*~
|
||||
|
||||
# Database
|
||||
*.db
|
||||
*.sql
|
||||
|
||||
# Cloud
|
||||
.cloud
|
||||
@@ -0,0 +1,37 @@
|
||||
FROM python:3.13-slim
|
||||
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PIP_NO_CACHE_DIR=1
|
||||
ENV PIP_DISABLE_PIP_VERSION_CHECK=1
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
default-libmysqlclient-dev \
|
||||
build-essential \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
ENV NODE_VERSION=20
|
||||
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash - \
|
||||
&& apt-get install -y nodejs \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
|
||||
|
||||
COPY package.json package-lock.json ./
|
||||
RUN npm ci
|
||||
RUN npm run build
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN python manage.py collectstatic --noinput || true
|
||||
|
||||
EXPOSE 8000
|
||||
|
||||
CMD ["gunicorn", "app.wsgi:application", "--bind", "0.0.0.0:8000"]
|
||||
@@ -0,0 +1,20 @@
|
||||
# Procfile for .
|
||||
# Used for deploying to PaaS platforms like Heroku, Railway, Render, etc.
|
||||
|
||||
# Web server process (using Gunicorn)
|
||||
# Adjust workers based on your needs: (2 x CPU cores) + 1
|
||||
web: gunicorn app.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --timeout 120 --access-logfile - --error-logfile - --log-level info
|
||||
|
||||
# Alternative web server configurations (uncomment to use):
|
||||
# web: gunicorn app.wsgi:application --bind 0.0.0.0:$PORT --workers 4 --threads 2 --timeout 120
|
||||
# web: gunicorn app.wsgi:application --bind 0.0.0.0:$PORT --workers 2 --worker-class gevent --worker-connections 1000 --timeout 120
|
||||
|
||||
# Release task (runs migrations before deployment)
|
||||
release: python manage.py migrate --noinput && python manage.py collectstatic --noinput
|
||||
|
||||
# Uncomment below to run scheduled tasks (if using Celery)
|
||||
# worker: celery -A app worker --loglevel=info
|
||||
# beat: celery -A app beat --loglevel=info
|
||||
|
||||
# Development server (for local testing with Foreman/Overmind)
|
||||
# web: python manage.py runserver 0.0.0.0:$PORT
|
||||
@@ -0,0 +1,112 @@
|
||||
# .
|
||||
|
||||
A Django project folder structure is generated with [djinitx/djinit/dj](https://github.com/S4NKALP/djinit).
|
||||
|
||||
## Features
|
||||
|
||||
- Modern project structure with environment-specific settings
|
||||
- Pre-configured REST API with JWT authentication
|
||||
- Essential dependencies and utilities
|
||||
- Production-ready configuration
|
||||
|
||||
## Setup
|
||||
|
||||
### Using Just (Recommended)
|
||||
|
||||
1. Set environment variables in `.env` file
|
||||
|
||||
2. Run setup (installs dependencies, runs migrations, creates superuser):
|
||||
```bash
|
||||
just setup
|
||||
```
|
||||
|
||||
3. Start development server:
|
||||
```bash
|
||||
just dev
|
||||
```
|
||||
|
||||
### Traditional Method
|
||||
|
||||
1. Install dependencies:
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
2. Set environment variables in `.env` file
|
||||
|
||||
3. Run migrations:
|
||||
```bash
|
||||
python manage.py migrate
|
||||
```
|
||||
|
||||
4. Create superuser:
|
||||
```bash
|
||||
python manage.py createsuperuser
|
||||
```
|
||||
|
||||
5. Start development server:
|
||||
```bash
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
## Available Commands
|
||||
|
||||
Run `just` to see all available commands, including:
|
||||
|
||||
- `just dev` - Run development server
|
||||
- `just migrate` - Run migrations
|
||||
- `just makemigrations` - Create migrations
|
||||
- `just createsuperuser` - Create superuser
|
||||
- `just test` - Run tests
|
||||
- `just lint` - Lint code
|
||||
- `just format` - Format code
|
||||
- `just shell` - Django shell
|
||||
- `just clean` - Clean cache files
|
||||
- `just install <package>` - Install package
|
||||
- `just remove <package>` - Remove package
|
||||
- `just server` - Run production server
|
||||
- `just ci` - Run all linting and checks
|
||||
- `just test-coverage` - Run tests with coverage
|
||||
|
||||
## Project Structure
|
||||
|
||||
```
|
||||
./
|
||||
├── app/
|
||||
│ ├── settings/
|
||||
│ │ ├── base.py
|
||||
│ │ ├── development.py
|
||||
│ │ └── production.py
|
||||
│ ├── admin/
|
||||
│ ├── api/ # API endpoints organized by model
|
||||
│ │ ├── user/ # Example: if you have a User model
|
||||
│ │ │ ├── views.py
|
||||
│ │ │ ├── serializers.py
|
||||
│ │ │ └── urls.py
|
||||
│ │ └── urls.py
|
||||
│ ├── models/ # Django models
|
||||
│ ├── tests/
|
||||
│ ├── urls.py
|
||||
│ ├── wsgi.py
|
||||
│ └── asgi.py
|
||||
├── manage.py
|
||||
├── requirements.txt
|
||||
├── pyproject.toml
|
||||
├── uv.lock
|
||||
├── .env.sample
|
||||
└── README.md
|
||||
|
||||
**Note:** For the single folder layout, organize your API endpoints by model name under the `api/` directory.
|
||||
For example, if you have a `User` model in `models/user.py`, create:
|
||||
- `api/user/views.py` - API views for User
|
||||
- `api/user/serializers.py` - Serializers for User
|
||||
- `api/user/urls.py` - URL patterns for User endpoints
|
||||
|
||||
See the README files in `api/` and `models/` directories for more details.
|
||||
```
|
||||
|
||||
## API Documentation
|
||||
|
||||
When running in development mode, API documentation is available at:
|
||||
- Swagger UI: http://localhost:8000/docs/
|
||||
- Schema: http://localhost:8000/schema/
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,76 @@
|
||||
# API Directory
|
||||
|
||||
This directory contains your API endpoints organized by model/resource.
|
||||
|
||||
## Structure
|
||||
|
||||
For each model in your `models/` directory, create a corresponding subdirectory here with the following files:
|
||||
|
||||
```
|
||||
api/
|
||||
├── __init__.py
|
||||
├── urls.py # Main API URL router
|
||||
└── <model_name>/ # e.g., user, product, order
|
||||
├── __init__.py
|
||||
├── views.py
|
||||
├── serializers.py
|
||||
└── urls.py
|
||||
```
|
||||
|
||||
## Example
|
||||
|
||||
If you have a `User` model in `models/user.py`, create:
|
||||
|
||||
### 1. `api/user/serializers.py`
|
||||
```python
|
||||
from rest_framework import serializers
|
||||
from app.models.user import User
|
||||
|
||||
class UserSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = User
|
||||
fields = '__all__'
|
||||
```
|
||||
|
||||
### 2. `api/user/views.py`
|
||||
```python
|
||||
from rest_framework import viewsets
|
||||
from app.models.user import User
|
||||
from .serializers import UserSerializer
|
||||
|
||||
class UserViewSet(viewsets.ModelViewSet):
|
||||
queryset = User.objects.all()
|
||||
serializer_class = UserSerializer
|
||||
```
|
||||
|
||||
### 3. `api/user/urls.py`
|
||||
```python
|
||||
from django.urls import path, include
|
||||
from rest_framework.routers import DefaultRouter
|
||||
from .views import UserViewSet
|
||||
|
||||
router = DefaultRouter()
|
||||
router.register(r'', UserViewSet, basename='user')
|
||||
|
||||
urlpatterns = [
|
||||
path('', include(router.urls)),
|
||||
]
|
||||
```
|
||||
|
||||
### 4. Update `api/urls.py`
|
||||
```python
|
||||
from django.urls import path, include
|
||||
|
||||
urlpatterns = [
|
||||
path('user/', include('app.api.user.urls')),
|
||||
# Add more API endpoints here
|
||||
]
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **One model per subdirectory**: Keep API endpoints for each model in its own subdirectory
|
||||
2. **Consistent naming**: Use lowercase, plural names for API endpoints (e.g., `users/`, `products/`)
|
||||
3. **Version your API**: Consider adding versioning (e.g., `api/v1/user/`)
|
||||
4. **Use ViewSets**: Leverage DRF's ViewSets for standard CRUD operations
|
||||
5. **Custom actions**: Add custom actions using `@action` decorator for non-CRUD operations
|
||||
Whitespace-only changes.
@@ -0,0 +1,13 @@
|
||||
"""generated with djinit"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import environ
|
||||
from django.core.asgi import get_asgi_application
|
||||
|
||||
env_path = Path(__file__).resolve().parent.parent / ".env"
|
||||
env = environ.Env()
|
||||
environ.Env.read_env(env_path)
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE", default="app.settings.production"))
|
||||
application = get_asgi_application()
|
||||
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,182 @@
|
||||
"""
|
||||
generated with djinit
|
||||
Common settings shared between development and production environment
|
||||
"""
|
||||
|
||||
from datetime import timedelta
|
||||
from pathlib import Path
|
||||
|
||||
import environ
|
||||
|
||||
env_path = Path(__file__).resolve().parent.parent.parent / ".env"
|
||||
env = environ.Env()
|
||||
environ.Env.read_env(env_path)
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/6.1/howto/deployment/checklist/
|
||||
|
||||
|
||||
# Application definition
|
||||
THIRD_PARTY_APPS = [
|
||||
"rest_framework",
|
||||
"corsheaders",
|
||||
"django_filters",
|
||||
"django_vite",
|
||||
]
|
||||
|
||||
USER_DEFINED_APPS = [
|
||||
"app.apps.AppConfig",
|
||||
]
|
||||
|
||||
BUILT_IN_APPS = [
|
||||
"django.contrib.admin",
|
||||
"django.contrib.auth",
|
||||
"django.contrib.contenttypes",
|
||||
"django.contrib.sessions",
|
||||
"django.contrib.messages",
|
||||
"django.contrib.staticfiles",
|
||||
]
|
||||
|
||||
INSTALLED_APPS = BUILT_IN_APPS + THIRD_PARTY_APPS + USER_DEFINED_APPS
|
||||
INSTALLED_APPS.insert(0, "jazzmin")
|
||||
|
||||
MIDDLEWARE = [
|
||||
"corsheaders.middleware.CorsMiddleware",
|
||||
"django.middleware.security.SecurityMiddleware",
|
||||
"whitenoise.middleware.WhiteNoiseMiddleware",
|
||||
"django.contrib.sessions.middleware.SessionMiddleware",
|
||||
"django.middleware.common.CommonMiddleware",
|
||||
"django.middleware.csrf.CsrfViewMiddleware",
|
||||
"django.contrib.auth.middleware.AuthenticationMiddleware",
|
||||
"django.contrib.messages.middleware.MessageMiddleware",
|
||||
"django.middleware.clickjacking.XFrameOptionsMiddleware",
|
||||
]
|
||||
|
||||
ROOT_URLCONF = "app.urls"
|
||||
|
||||
TEMPLATES = [
|
||||
{
|
||||
"BACKEND": "django.template.backends.django.DjangoTemplates",
|
||||
"DIRS": [],
|
||||
"APP_DIRS": True,
|
||||
"OPTIONS": {
|
||||
"context_processors": [
|
||||
"django.template.context_processors.request",
|
||||
"django.contrib.auth.context_processors.auth",
|
||||
"django.contrib.messages.context_processors.messages",
|
||||
],
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
WSGI_APPLICATION = "app.wsgi.application"
|
||||
|
||||
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/6.1/ref/settings/#auth-password-validators
|
||||
|
||||
AUTH_PASSWORD_VALIDATORS = [
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.UserAttributeSimilarityValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.MinimumLengthValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.CommonPasswordValidator",
|
||||
},
|
||||
{
|
||||
"NAME": "django.contrib.auth.password_validation.NumericPasswordValidator",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
# Internationalization
|
||||
# https://docs.djangoproject.com/en/6.1/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = "en-us"
|
||||
TIME_ZONE = "UTC"
|
||||
USE_I18N = True
|
||||
USE_TZ = True
|
||||
|
||||
# Static files and media files
|
||||
STATIC_URL = "/static/"
|
||||
STATIC_ROOT = BASE_DIR / "staticfiles"
|
||||
|
||||
MEDIA_URL = "/media/"
|
||||
MEDIA_ROOT = BASE_DIR / "media"
|
||||
|
||||
STORAGES = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.files.storage.FileSystemStorage",
|
||||
},
|
||||
"staticfiles": {
|
||||
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
|
||||
},
|
||||
}
|
||||
|
||||
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
||||
|
||||
# REST Framework Settings
|
||||
REST_FRAMEWORK = {
|
||||
"DEFAULT_RENDERER_CLASSES": [
|
||||
"rest_framework.renderers.JSONRenderer",
|
||||
],
|
||||
"DEFAULT_PARSER_CLASSES": [
|
||||
"rest_framework.parsers.JSONParser",
|
||||
],
|
||||
"DEFAULT_AUTHENTICATION_CLASSES": (
|
||||
"rest_framework_simplejwt.authentication.JWTAuthentication",
|
||||
"rest_framework.authentication.SessionAuthentication",
|
||||
),
|
||||
"DEFAULT_SCHEMA_CLASS": "rest_framework.schemas.coreapi.AutoSchema",
|
||||
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
|
||||
"PAGE_SIZE": 20,
|
||||
}
|
||||
|
||||
# JWT Settings
|
||||
SIMPLE_JWT = {
|
||||
"ACCESS_TOKEN_LIFETIME": timedelta(days=1),
|
||||
"REFRESH_TOKEN_LIFETIME": timedelta(days=3),
|
||||
"ROTATE_REFRESH_TOKENS": True,
|
||||
"BLACKLIST_AFTER_ROTATION": True,
|
||||
}
|
||||
|
||||
# CORS Settings
|
||||
CORS_ALLOW_METHODS = [
|
||||
"DELETE",
|
||||
"GET",
|
||||
"OPTIONS",
|
||||
"PATCH",
|
||||
"POST",
|
||||
"PUT",
|
||||
]
|
||||
|
||||
CORS_ALLOW_HEADERS = [
|
||||
"accept",
|
||||
"accept-encoding",
|
||||
"authorization",
|
||||
"content-type",
|
||||
"dnt",
|
||||
"origin",
|
||||
"user-agent",
|
||||
"x-csrftoken",
|
||||
"x-requested-with",
|
||||
]
|
||||
|
||||
CORS_PREFLIGHT_MAX_AGE = 86400 # 24 hours
|
||||
# Security Settings
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
X_FRAME_OPTIONS = "DENY"
|
||||
|
||||
|
||||
# Vite Settings
|
||||
DJANGO_VITE = {
|
||||
"default": {
|
||||
"manifest_path": BASE_DIR / "static" / "dist" / "manifest.json",
|
||||
"static_url_prefix": "dist",
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
"""generated with djinit"""
|
||||
|
||||
from .base import * # noqa: F401, F403
|
||||
|
||||
SECRET_KEY = "bUD+1$5)NUfhrNiYfKEeX#JSz*Crzw78O2@O(rr@o#t5ehQ3tY"
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/6.1/ref/settings/#databases
|
||||
|
||||
DATABASES = {
|
||||
"default": {
|
||||
"ENGINE": "django.db.backends.sqlite3",
|
||||
"NAME": BASE_DIR / "db.sqlite3",
|
||||
"OPTIONS": {
|
||||
"transaction_mode": "IMMEDIATE",
|
||||
"timeout": 5, # seconds
|
||||
"init_command": """
|
||||
PRAGMA journal_mode=WAL;
|
||||
PRAGMA synchronous=NORMAL;
|
||||
PRAGMA mmap_size = 134217728;
|
||||
PRAGMA journal_size_limit = 27103364;
|
||||
PRAGMA cache_size=2000;
|
||||
""",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
# Email settings for development
|
||||
MAILERS = {
|
||||
"default": {
|
||||
"BACKEND": "django.core.mail.backends.console.EmailBackend",
|
||||
},
|
||||
}
|
||||
|
||||
# CORS settings for development
|
||||
# Allow all origins in development (convenient but not secure)
|
||||
CORS_ALLOW_ALL_ORIGINS = True
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
|
||||
# Disable HTTPS redirect in development
|
||||
SECURE_SSL_REDIRECT = False
|
||||
|
||||
# Vite Settings
|
||||
DJANGO_VITE["default"]["dev_mode"] = True
|
||||
@@ -0,0 +1,59 @@
|
||||
"""generated with djinit"""
|
||||
|
||||
from .base import * # noqa: F401, F403
|
||||
|
||||
DEBUG = False
|
||||
SECRET_KEY = env('SECRET_KEY')
|
||||
ALLOWED_HOSTS = env.list('ALLOWED_HOSTS', default=[])
|
||||
|
||||
# Database
|
||||
# Using individual database parameters
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.mysql',
|
||||
'PORT': env('DB_PORT', default='3306'),
|
||||
'NAME': env('DB_NAME'),
|
||||
'USER': env('DB_USER'),
|
||||
'PASSWORD': env('DB_PASSWORD'),
|
||||
'HOST': env('DB_HOST'),
|
||||
}
|
||||
}
|
||||
|
||||
# CORS settings for production
|
||||
# Filter out empty strings from FRONTEND_URL
|
||||
CORS_ALLOWED_ORIGINS = env.list('FRONTEND_URL', default=[])
|
||||
CORS_ALLOW_CREDENTIALS = True
|
||||
|
||||
# Additional CORS security for production
|
||||
CORS_ALLOW_PRIVATE_NETWORK = False
|
||||
|
||||
# Email settings
|
||||
MAILERS = {
|
||||
'default': {
|
||||
'BACKEND': 'django.core.mail.backends.smtp.EmailBackend',
|
||||
'OPTIONS': {
|
||||
'host': env('EMAIL_HOST', default='smtp.gmail.com'),
|
||||
'port': env.int('EMAIL_PORT', default=587),
|
||||
'use_tls': env.bool('EMAIL_USE_TLS', default=True),
|
||||
'username': env('EMAIL_HOST_USER', default=''),
|
||||
'password': env('EMAIL_HOST_PASSWORD', default=''),
|
||||
},
|
||||
},
|
||||
}
|
||||
DEFAULT_FROM_EMAIL = env('EMAIL_HOST_USER', default='')
|
||||
SERVER_EMAIL = env('EMAIL_HOST_USER', default='')
|
||||
|
||||
# Security settings for production
|
||||
SECURE_SSL_REDIRECT = True
|
||||
SECURE_HSTS_SECONDS = 31536000
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||
SECURE_HSTS_PRELOAD = True
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
|
||||
# Session settings
|
||||
SESSION_COOKIE_SECURE = True
|
||||
CSRF_COOKIE_SECURE = True
|
||||
|
||||
|
||||
# Vite Settings
|
||||
DJANGO_VITE["default"]["dev_mode"] = False
|
||||
Whitespace-only changes.
@@ -0,0 +1,45 @@
|
||||
"""generated with djinit"""
|
||||
|
||||
from django.contrib import admin
|
||||
from django.urls import path, re_path
|
||||
from django.conf import settings
|
||||
from django.views.static import serve
|
||||
from django.urls import include
|
||||
from drf_yasg.views import get_schema_view
|
||||
from drf_yasg import openapi
|
||||
from rest_framework_simplejwt.views import (
|
||||
TokenObtainPairView,
|
||||
TokenRefreshView,
|
||||
TokenBlacklistView,
|
||||
)
|
||||
|
||||
urlpatterns = [
|
||||
path("admin/", admin.site.urls),
|
||||
# JWT tokens
|
||||
path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
|
||||
path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
|
||||
path("token/blacklist/", TokenBlacklistView.as_view(), name="token_blacklist"),
|
||||
# path("api/", include("app.api.urls")),
|
||||
]
|
||||
|
||||
# Don't show schema in production
|
||||
if settings.DEBUG:
|
||||
schema_view = get_schema_view(
|
||||
openapi.Info(
|
||||
title=". API",
|
||||
default_version="v1",
|
||||
),
|
||||
public=True,
|
||||
)
|
||||
urlpatterns += [
|
||||
path("docs/", schema_view.with_ui("swagger", cache_timeout=0)),
|
||||
path("schema/", schema_view.with_ui("redoc", cache_timeout=0)),
|
||||
]
|
||||
|
||||
urlpatterns += [
|
||||
re_path(
|
||||
r"^media/(?P<path>.*)$",
|
||||
serve,
|
||||
{"document_root": settings.MEDIA_ROOT},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,14 @@
|
||||
"""generated with djinit"""
|
||||
|
||||
import os
|
||||
from pathlib import Path
|
||||
import environ
|
||||
from django.core.wsgi import get_wsgi_application
|
||||
|
||||
env_path = Path(__file__).resolve().parent.parent / ".env"
|
||||
env = environ.Env()
|
||||
environ.Env.read_env(env_path)
|
||||
|
||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", env("DJANGO_SETTINGS_MODULE", default="app.settings.production"))
|
||||
|
||||
application = get_wsgi_application()
|
||||
@@ -0,0 +1,238 @@
|
||||
# Justfile for .
|
||||
# Task runner for Django development
|
||||
# Install just: https://github.com/casey/just
|
||||
|
||||
# Default task: show available commands
|
||||
default:
|
||||
@just --list
|
||||
|
||||
# Run development server
|
||||
dev:
|
||||
uv run python manage.py runserver
|
||||
|
||||
# Run development server with custom host and port
|
||||
dev-server HOST="0.0.0.0" PORT="8000":
|
||||
uv run python manage.py runserver {{ HOST }}:{{ PORT }}
|
||||
|
||||
# Start Vite dev server
|
||||
vite:
|
||||
npm run dev
|
||||
|
||||
# Start both Django and Vite dev servers
|
||||
dev-full:
|
||||
@just dev &
|
||||
@just vite
|
||||
|
||||
# Create migrations for all apps
|
||||
makemigrations:
|
||||
uv run python manage.py makemigrations
|
||||
|
||||
# Create migrations for specific app
|
||||
makemigrations-app APP:
|
||||
uv run python manage.py makemigrations {{ APP }}
|
||||
|
||||
# Run all migrations
|
||||
migrate:
|
||||
uv run python manage.py migrate
|
||||
|
||||
# Reset database (delete all migrations)
|
||||
reset-db:
|
||||
uv run python manage.py flush --noinput
|
||||
uv run python manage.py migrate
|
||||
|
||||
# Create superuser
|
||||
createsuperuser:
|
||||
uv run python manage.py createsuperuser
|
||||
|
||||
# Collect static files
|
||||
collectstatic:
|
||||
uv run python manage.py collectstatic --noinput
|
||||
|
||||
# Run Django shell
|
||||
shell:
|
||||
uv run python manage.py shell
|
||||
|
||||
# Run Django shell plus (IPython)
|
||||
shell-plus:
|
||||
uv run python manage.py shell_plus
|
||||
|
||||
# Run tests
|
||||
test:
|
||||
uv run python manage.py test
|
||||
|
||||
# Run tests with coverage
|
||||
test-coverage:
|
||||
uv run pytest --cov=. --cov-report=html --cov-report=term
|
||||
|
||||
# Lint code with ruff
|
||||
lint:
|
||||
uv run ruff check .
|
||||
|
||||
# Format code with ruff
|
||||
format:
|
||||
uv run ruff format .
|
||||
|
||||
# Lint and format code
|
||||
style:
|
||||
uv run ruff check .
|
||||
uv run ruff format .
|
||||
|
||||
# Check security issues
|
||||
check:
|
||||
uv run python manage.py check
|
||||
|
||||
# Check security issues (production settings)
|
||||
check-deploy:
|
||||
uv run python manage.py check --deploy
|
||||
|
||||
# Show all database migrations status
|
||||
showmigrations:
|
||||
uv run python manage.py showmigrations
|
||||
|
||||
# Sync dependencies (uv equivalent of pip freeze)
|
||||
requirements:
|
||||
#!/usr/bin/env -S uv run python
|
||||
import tomllib
|
||||
from pathlib import Path
|
||||
pyproject = Path("pyproject.toml")
|
||||
if not pyproject.exists():
|
||||
print("pyproject.toml not found")
|
||||
raise SystemExit(1)
|
||||
data = tomllib.loads(pyproject.read_text())
|
||||
deps = data.get("project", {}).get("dependencies", [])
|
||||
Path("requirements.txt").write_text("\n".join(deps) + "\n")
|
||||
print("Generated requirements.txt from pyproject.toml")
|
||||
|
||||
# Run all linting and checks
|
||||
ci:
|
||||
uv run ruff check .
|
||||
uv run ruff format --check .
|
||||
uv run python manage.py check
|
||||
|
||||
# Start interactive shell
|
||||
shell-ipython:
|
||||
uv run python manage.py shell_plus
|
||||
|
||||
# Clear all cache
|
||||
clear-cache:
|
||||
uv run python manage.py clear_cache
|
||||
|
||||
# Show Django version
|
||||
version:
|
||||
uv run python manage.py version
|
||||
|
||||
# Run database shell
|
||||
dbshell:
|
||||
uv run python manage.py dbshell
|
||||
|
||||
# Start production server with gunicorn
|
||||
server:
|
||||
uv run gunicorn app.wsgi:application --bind 0.0.0.0:8000
|
||||
|
||||
# Start production server with gunicorn workers
|
||||
server-prod WORKERS="4":
|
||||
uv run gunicorn app.wsgi:application --bind 0.0.0.0:8000 --workers {{ WORKERS }}
|
||||
|
||||
# Start production server with gunicorn and reload on file changes
|
||||
server-watch:
|
||||
uv run gunicorn app.wsgi:application --bind 0.0.0.0:8000 --reload
|
||||
|
||||
# Clean Python cache files
|
||||
clean:
|
||||
find . -type d -name "__pycache__" -exec rm -rf {} +
|
||||
find . -type f -name "*.pyc" -delete
|
||||
find . -type f -name "*.pyo" -delete
|
||||
find . -type f -name ".coverage" -delete
|
||||
find . -type d -name "*.egg-info" -exec rm -rf {} +
|
||||
rm -rf htmlcov/
|
||||
rm -rf .pytest_cache/
|
||||
|
||||
# Pin dependencies in pyproject.toml using versions from uv.lock, keeping >= and extras
|
||||
pin-deps:
|
||||
#!/usr/bin/env -S uv run python
|
||||
import tomllib, re
|
||||
from pathlib import Path
|
||||
|
||||
lock = Path("uv.lock")
|
||||
if not lock.exists():
|
||||
print("uv.lock not found — run `uv sync` first")
|
||||
raise SystemExit(0)
|
||||
|
||||
data = tomllib.loads(lock.read_text())
|
||||
packages = {p["name"].lower(): p["version"] for p in data.get("package", [])}
|
||||
|
||||
py = Path("pyproject.toml")
|
||||
lines = py.read_text().splitlines()
|
||||
|
||||
pattern = re.compile(r'^(\s*)"([^"]+)"(,?)')
|
||||
|
||||
out = []
|
||||
for line in lines:
|
||||
m = pattern.match(line)
|
||||
if not m:
|
||||
out.append(line)
|
||||
continue
|
||||
|
||||
indent, dep, comma = m.groups()
|
||||
|
||||
base = dep
|
||||
extras = ""
|
||||
operator = ">="
|
||||
version = None
|
||||
|
||||
# extras: django[postgres]
|
||||
if "[" in base and "]" in base:
|
||||
before, after = base.split("[", 1)
|
||||
extras = "[" + after.split("]")[0] + "]"
|
||||
base = before
|
||||
|
||||
# detect >= or ==
|
||||
if ">=" in dep:
|
||||
operator = ">="
|
||||
base, version = dep.split(">=")
|
||||
base = base.strip()
|
||||
elif "==" in dep:
|
||||
operator = "=="
|
||||
base, version = dep.split("==")
|
||||
base = base.strip()
|
||||
else:
|
||||
base = dep
|
||||
|
||||
base_lower = base.lower()
|
||||
new_version = packages.get(base_lower)
|
||||
|
||||
if new_version:
|
||||
new_dep = f'{base}{extras}{operator}{new_version}'
|
||||
line = f'{indent}"{new_dep}"{comma}'
|
||||
|
||||
out.append(line)
|
||||
|
||||
py.write_text("\n".join(out) + "\n")
|
||||
print("Pinned dependencies (>= preserved, extras preserved).")
|
||||
|
||||
|
||||
# Setup project for development (using uv)
|
||||
setup:
|
||||
uv sync
|
||||
just pin-deps
|
||||
uv run python manage.py migrate
|
||||
uv run python manage.py createsuperuser
|
||||
|
||||
# Complete setup including static files
|
||||
setup-complete:
|
||||
uv sync
|
||||
uv run python manage.py migrate
|
||||
uv run python manage.py collectstatic --noinput
|
||||
uv run python manage.py createsuperuser
|
||||
|
||||
# Install a new package
|
||||
install PACKAGE:
|
||||
uv add {{ PACKAGE }}
|
||||
|
||||
# Install a dev package
|
||||
install-dev PACKAGE:
|
||||
uv add --dev {{ PACKAGE }}
|
||||
|
||||
# Remove a package
|
||||
remove PACKAGE:
|
||||
uv remove {{ PACKAGE }}
|
||||
Executable
+42
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""generated with djinit"""
|
||||
|
||||
"""Django's command-line utility for administrative tasks."""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import environ
|
||||
|
||||
# Load environment variables from .env
|
||||
BASE_DIR = Path(__file__).resolve().parent
|
||||
env = environ.Env()
|
||||
env.read_env(BASE_DIR / ".env")
|
||||
|
||||
|
||||
def main():
|
||||
"""Run administrative tasks."""
|
||||
os.environ.setdefault(
|
||||
"DJANGO_SETTINGS_MODULE",
|
||||
env(
|
||||
"DJANGO_SETTINGS_MODULE",
|
||||
default="app.settings.production",
|
||||
),
|
||||
)
|
||||
|
||||
try:
|
||||
from django.core.management import execute_from_command_line
|
||||
except ImportError as exc:
|
||||
raise ImportError(
|
||||
"Couldn't import Django. Are you sure it's installed and "
|
||||
"available on your PYTHONPATH environment variable? Did you "
|
||||
"forget to activate a virtual environment?"
|
||||
) from exc
|
||||
|
||||
execute_from_command_line(sys.argv)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,51 @@
|
||||
[project]
|
||||
name = "backend"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.13"
|
||||
license = { text = "MIT" }
|
||||
dependencies = [
|
||||
"django>=6.1.1",
|
||||
"django-environ>=0.14.0",
|
||||
"django-jazzmin>=3.0.5",
|
||||
"djangorestframework>=3.18.1",
|
||||
"django-cors-headers>=4.9.0",
|
||||
"whitenoise>=6.12.0",
|
||||
"mysqlclient>=2.2.8",
|
||||
"django-vite>=3.1.0",
|
||||
"gunicorn>=26.2.0",
|
||||
"django-filter>=26.1",
|
||||
]
|
||||
|
||||
[dependency-groups]
|
||||
dev = [
|
||||
"ruff>=0.16.7",
|
||||
"pytest>=9.1.1",
|
||||
"pytest-django>=4.14.0",
|
||||
]
|
||||
|
||||
[tool.ruff]
|
||||
line-length = 88
|
||||
target-version = "py313"
|
||||
|
||||
[tool.ruff.lint]
|
||||
select = [
|
||||
"E", # pycodestyle errors
|
||||
"W", # pycodestyle warnings
|
||||
"F", # pyflakes
|
||||
"I", # isort
|
||||
"B", # flake8-bugbear
|
||||
"C4", # flake8-comprehensions
|
||||
"UP", # pyupgrade
|
||||
]
|
||||
ignore = [
|
||||
"E501", # line too long, handled by formatter
|
||||
"B008", # do not perform function calls in argument defaults
|
||||
]
|
||||
|
||||
[tool.ruff.lint.isort]
|
||||
known-first-party = ["."]
|
||||
|
||||
[tool.ruff.lint.per-file-ignores]
|
||||
"./settings/*.py" = ["F403", "F405"]
|
||||
@@ -0,0 +1,10 @@
|
||||
django>=6.1.1
|
||||
django-environ>=0.14.0
|
||||
django-jazzmin>=3.0.5
|
||||
djangorestframework>=3.18.1
|
||||
django-cors-headers>=4.9.0
|
||||
whitenoise>=6.12.0
|
||||
mysqlclient>=2.2.8
|
||||
django-vite>=3.1.0
|
||||
gunicorn>=26.2.0
|
||||
django-filter>=26.1
|
||||
@@ -0,0 +1 @@
|
||||
python-3.13
|
||||
Generated
+286
@@ -0,0 +1,286 @@
|
||||
version = 1
|
||||
revision = 3
|
||||
requires-python = ">=3.13"
|
||||
|
||||
[[package]]
|
||||
name = "asgiref"
|
||||
version = "3.12.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e6/26/3b59f2bdae5f640389becb1f673cded775287f5fc4f816309d9ca9a3f93d/asgiref-3.12.1.tar.gz", hash = "sha256:59dcb51c272ad209d59bed5708a64a333083e86017d7fcdd67498eeab7784340", size = 42378, upload-time = "2026-07-14T09:56:18.087Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/c0/1b/54f4ad77cd8a584fa70746c47df988e002cf1ee1eba43364d46f87803647/asgiref-3.12.1-py3-none-any.whl", hash = "sha256:fe386d1c2bff7259ea95929266d12a8cf9a8b5a1c2598402967d8792e7a7c094", size = 25478, upload-time = "2026-07-14T09:56:16.926Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "backend"
|
||||
version = "0.1.0"
|
||||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
{ name = "django-cors-headers" },
|
||||
{ name = "django-environ" },
|
||||
{ name = "django-filter" },
|
||||
{ name = "django-jazzmin" },
|
||||
{ name = "django-vite" },
|
||||
{ name = "djangorestframework" },
|
||||
{ name = "gunicorn" },
|
||||
{ name = "mysqlclient" },
|
||||
{ name = "whitenoise" },
|
||||
]
|
||||
|
||||
[package.dev-dependencies]
|
||||
dev = [
|
||||
{ name = "pytest" },
|
||||
{ name = "pytest-django" },
|
||||
{ name = "ruff" },
|
||||
]
|
||||
|
||||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "django", specifier = ">=6.1.1" },
|
||||
{ name = "django-cors-headers", specifier = ">=4.9.0" },
|
||||
{ name = "django-environ", specifier = ">=0.14.0" },
|
||||
{ name = "django-filter", specifier = ">=26.1" },
|
||||
{ name = "django-jazzmin", specifier = ">=3.0.5" },
|
||||
{ name = "django-vite", specifier = ">=3.1.0" },
|
||||
{ name = "djangorestframework", specifier = ">=3.18.1" },
|
||||
{ name = "gunicorn", specifier = ">=26.2.0" },
|
||||
{ name = "mysqlclient", specifier = ">=2.2.8" },
|
||||
{ name = "whitenoise", specifier = ">=6.12.0" },
|
||||
]
|
||||
|
||||
[package.metadata.requires-dev]
|
||||
dev = [
|
||||
{ name = "pytest", specifier = ">=9.1.1" },
|
||||
{ name = "pytest-django", specifier = ">=4.14.0" },
|
||||
{ name = "ruff", specifier = ">=0.16.7" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "colorama"
|
||||
version = "0.4.6"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django"
|
||||
version = "6.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asgiref" },
|
||||
{ name = "sqlparse" },
|
||||
{ name = "tzdata", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f8/d4/8314b5bdef20832f0ac6ae3b3e4d4924e4759fa3b4af27609dd747e7a6be/django-6.1.1.tar.gz", hash = "sha256:7ab93536d8e677aa14554c56426290c69480bf2ee68d7513d4a22f57d6bfeb84", size = 11284905, upload-time = "2026-09-02T17:20:45.621Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/8d/ca/c1040a4fd15754ede7df15fd72fc2e123045b473b253ab5f5284e11c651e/django-6.1.1-py3-none-any.whl", hash = "sha256:585fb82bf15053c42cf52e67c2f1b54a032dca384759315fd6678ab1870d1d72", size = 8419512, upload-time = "2026-09-02T17:20:39.153Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-cors-headers"
|
||||
version = "4.9.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asgiref" },
|
||||
{ name = "django" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/21/39/55822b15b7ec87410f34cd16ce04065ff390e50f9e29f31d6d116fc80456/django_cors_headers-4.9.0.tar.gz", hash = "sha256:fe5d7cb59fdc2c8c646ce84b727ac2bca8912a247e6e68e1fb507372178e59e8", size = 21458, upload-time = "2025-09-18T10:40:52.326Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/30/d8/19ed1e47badf477d17fb177c1c19b5a21da0fd2d9f093f23be3fb86c5fab/django_cors_headers-4.9.0-py3-none-any.whl", hash = "sha256:15c7f20727f90044dcee2216a9fd7303741a864865f0c3657e28b7056f61b449", size = 12809, upload-time = "2025-09-18T10:40:50.843Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-environ"
|
||||
version = "0.14.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/57/e1/4c4ddcf6e90f023e89edb1d92f9a7fffce61ad4b691df497f2f5c0be6e26/django_environ-0.14.0.tar.gz", hash = "sha256:b6c48d93b9d2ff8a3ea14099e90c35aa4f101c1b4d5f262dfee0d27b06742ed7", size = 60417, upload-time = "2026-06-18T22:49:55.847Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1a/fe/67b423fc30f16d10259e901320fbc121746bf168aaaad9043e6ebb0110c1/django_environ-0.14.0-py3-none-any.whl", hash = "sha256:8dbe8a57f0a540ab8abd6f54f230de5e99e3a2c9d797cb9caecb037bca3d47d8", size = 20934, upload-time = "2026-06-18T22:49:54.355Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-filter"
|
||||
version = "26.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cb/3e/563965173d4cbb5fc308087e7b3d11a115b7b67273d093622480b1e31f78/django_filter-26.1.tar.gz", hash = "sha256:66ea04031b068c77c86e1ac26ced7a3f8f13ce797f5795751707e3deefc58054", size = 144299, upload-time = "2026-07-11T09:27:02.767Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/01/afffed1e3c4540fb75bf550a18b6176a9f6371b5f3e52b69a28995b6480c/django_filter-26.1-py3-none-any.whl", hash = "sha256:7d98ef2899218e6242619b532cb1b95af14e09dfcf74844aecb550ad27b59ff2", size = 94069, upload-time = "2026-07-11T09:27:01.012Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-jazzmin"
|
||||
version = "3.0.5"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/15/e4/17cd62e80c4876088bc5f8bca24446586a62eca386c82755894408751a44/django_jazzmin-3.0.5.tar.gz", hash = "sha256:7e39b029bddbb60f3aaf9897bd009f39f8f2bdc8a7d86beed1e943706dd79692", size = 2509734, upload-time = "2026-06-25T21:05:52.699Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/23/40/892f4c922c92d0d2b8ca5f96f556c5dc04d19ea2ea717910d8bbf2dc23fc/django_jazzmin-3.0.5-py3-none-any.whl", hash = "sha256:578fb1fc0a1b7e3b8472d2692ace60b1584ccd937c3828e2c9a89bdf94067f94", size = 2581722, upload-time = "2026-06-25T21:05:50.948Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "django-vite"
|
||||
version = "3.1.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/23/fe/4be07f538bbf9bf8bf73b045552ec2a1b4fba67e3176abb30490b643368e/django_vite-3.1.0.tar.gz", hash = "sha256:8b4ffe4a9fa81ff568bfb195e74dde8694aaf13fd4b656ae60bf59cce08b85e8", size = 25434, upload-time = "2025-02-23T15:32:07.914Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/30/59/7df4b1077fa41b43b4e542696d75138dbb86a65f44248c607b3e0f1014ce/django_vite-3.1.0-py3-none-any.whl", hash = "sha256:4e46572bd6b1ce70784be129205dc2ffcbc7a3c19fea50bebfb72b327bbde5fc", size = 23579, upload-time = "2025-02-23T15:32:06.603Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "djangorestframework"
|
||||
version = "3.18.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "django" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8a/2e/b3ce9d449b1ed9f9dd74fb7dfbc5f20860d5f40c2b4b10a2c3eabd8ff579/djangorestframework-3.18.1.tar.gz", hash = "sha256:605d79fa2ec2f02905492e5ea13d903c2d842d0b4c915a57f7bf02ab9f3c91dd", size = 915653, upload-time = "2026-09-07T18:04:08.288Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/83/5ed615e47339d8e65f62eb1a8133f8f046492eb3a25ad40d90acb9a208b3/djangorestframework-3.18.1-py3-none-any.whl", hash = "sha256:f1409d698967aaf82d5d98d76b549c8fba8bd92ebd0d83d24454508f72168dc2", size = 901373, upload-time = "2026-09-07T18:04:06.237Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gunicorn"
|
||||
version = "26.2.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/8a/e4ef6ee11701b6cd64702848415ffb69eeff85cb388a3c6c7fe86f22f3f8/gunicorn-26.2.0.tar.gz", hash = "sha256:62b864895d9ebff0b2f9867ba04fe811c93121596540830c9c916d0769668447", size = 787921, upload-time = "2026-08-24T15:05:59.3Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/85/7522a52e5e2f42faf1a129113ab63e548c42e103e9af395b7bfe65e403e2/gunicorn-26.2.0-py3-none-any.whl", hash = "sha256:bd249d0b3f7972f7432f0a6b6ff3b3ee2d129f70cd1ff6c09a9dd9e29a2b88e3", size = 228389, upload-time = "2026-08-24T15:05:57.67Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iniconfig"
|
||||
version = "2.3.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/72/34/14ca021ce8e5dfedc35312d08ba8bf51fdd999c576889fc2c24cb97f4f10/iniconfig-2.3.0.tar.gz", hash = "sha256:c76315c77db068650d49c5b56314774a7804df16fee4402c1f19d6d15d8c4730", size = 20503, upload-time = "2025-10-18T21:55:43.219Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/cb/b1/3846dd7f199d53cb17f49cba7e651e9ce294d8497c8c150530ed11865bb8/iniconfig-2.3.0-py3-none-any.whl", hash = "sha256:f631c04d2c48c52b84d0d0549c99ff3859c98df65b3101406327ecc7d53fbf12", size = 7484, upload-time = "2025-10-18T21:55:41.639Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mysqlclient"
|
||||
version = "2.2.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/eb/b0/9df076488cb2e536d40ce6dbd4273c1f20a386e31ffe6e7cb613902b3c2a/mysqlclient-2.2.8.tar.gz", hash = "sha256:8ed20c5615a915da451bb308c7d0306648a4fd9a2809ba95c992690006306199", size = 92287, upload-time = "2026-02-10T10:58:37.405Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e6/d5/76e369b0fdccd2eb9ed7d890e4e3e23aa1344fea62f0180d7f1574285e54/mysqlclient-2.2.8-cp313-cp313-win_amd64.whl", hash = "sha256:a81f5e12f8d05439709cb02fba97f9f76d1a6c528164f2260d8798fec969e300", size = 207158, upload-time = "2026-02-10T10:58:38.663Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/42/44/6ae21b4e8490eb5167d04fa7452c462ffd72a502b96bf531477ef044a380/mysqlclient-2.2.8-cp314-cp314-win_amd64.whl", hash = "sha256:9bed7c8d3b629bdc09e17fb628d5b3b0a5fd1f12b09432b464b9126c727bedc0", size = 211644, upload-time = "2026-02-10T10:58:45.022Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/66/e5/037d55623be9f681236e04abe12e1290847c06bd48270c3f19ac33493cbf/mysqlclient-2.2.8-cp314-cp314t-win_amd64.whl", hash = "sha256:260cce0e81446c83bf0a389e0fae38d68547d9f8fc0833bc733014e10ce28a99", size = 213067, upload-time = "2026-02-10T10:58:43.389Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "packaging"
|
||||
version = "26.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79", size = 313412, upload-time = "2026-08-04T18:15:28.737Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c", size = 129956, upload-time = "2026-08-04T18:15:27.159Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pluggy"
|
||||
version = "1.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f9/e2/3e91f31a7d2b083fe6ef3fa267035b518369d9511ffab804f839851d2779/pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3", size = 69412, upload-time = "2025-05-15T12:30:07.975Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/54/20/4d324d65cc6d9205fabedc306948156824eb9f0ee1633355a8f7ec5c66bf/pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746", size = 20538, upload-time = "2025-05-15T12:30:06.134Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pygments"
|
||||
version = "2.21.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c", size = 5005329, upload-time = "2026-08-17T08:02:48.824Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9", size = 1250147, upload-time = "2026-08-17T08:02:44.912Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest"
|
||||
version = "9.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
{ name = "iniconfig" },
|
||||
{ name = "packaging" },
|
||||
{ name = "pluggy" },
|
||||
{ name = "pygments" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl", hash = "sha256:37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c", size = 386536, upload-time = "2026-06-19T10:58:31.347Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pytest-django"
|
||||
version = "4.14.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "pytest" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/44/f6/3851312120c2bf2f19cafff931e75059aad1ba670703cd751e2fde9bc942/pytest_django-4.14.0.tar.gz", hash = "sha256:26787dd3f422cfbab8f55b80a776e2edea7a11092cb74e960bef1312515708ef", size = 94700, upload-time = "2026-08-10T14:13:08.319Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/9c/03/850bffad2b581c440ca51c039d74504d5a422c94bda0bdb8a8ba5068d48b/pytest_django-4.14.0-py3-none-any.whl", hash = "sha256:c533b08d89cc675efcd5398eea270b34547e35f9a3608e2c9748dd88428ea187", size = 27067, upload-time = "2026-08-10T14:13:06.998Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ruff"
|
||||
version = "0.16.7"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/82/bb/5a449b9162e49b139d72f61672bd3ac1d790221f796d3304e2241fff4c58/ruff-0.16.7.tar.gz", hash = "sha256:5f71d004ac1263b22fa39462ac5ae618a4b77d58981af2cc79bf79a29c12b1a6", size = 4924184, upload-time = "2026-09-10T18:04:06.336Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e3/b2/c80aeeb7f9e469c0d63a85d2f1ab6e1ebfbe10ea7a8d2438b7e09e3ff09e/ruff-0.16.7-py3-none-linux_armv6l.whl", hash = "sha256:727307773e7c7f9181d3ed3a2484186e56c1fa1874255911c74585eb2c7c19f9", size = 10048917, upload-time = "2026-09-10T18:03:30.28Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/96/20bb7bcae008004df52afcb7ac83432d4a467f2c17b672fe46d26be231c5/ruff-0.16.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9d61c258deabf58f34c67bd4bb4d939c7f2e6b5f0e59c1cdd1cf771b11cde929", size = 10242929, upload-time = "2026-09-10T18:03:32.706Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/90/b2/f184b0d5abec02db69cfd7e49b688ae0237554528ca777136c613bf36bee/ruff-0.16.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:7ab81118df8945e0193d0240712aa4496573595b75185c3636ed825592a0f728", size = 9847245, upload-time = "2026-09-10T18:03:34.509Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/2d/db1633a641866ed801e34cc6b60ef236c5e16f9b2124ab1d49cc24a5fe4f/ruff-0.16.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c196c968874fc8019da8e7163de7a1a370f111e2309b4b7dfea0fce950198d0", size = 9961780, upload-time = "2026-09-10T18:03:36.618Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/98/edea21e1a3e38dbbc3bf6bb068b863b3b06184cf8533a4c7dbbe208a89d5/ruff-0.16.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac8c3bd0a7e10ad31e6ce51e7a99f3cb772e69aecdd6b9ea7e99b362f62a62c0", size = 9866337, upload-time = "2026-09-10T18:03:38.805Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0b/11/a15e60d4c87b214646f116ca9d204475bf993ee1047459bc9a360fd4d6d1/ruff-0.16.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:398d3988edde000b5c75dc1b3f584708da9bc990de069c18909142580fec1af9", size = 10562512, upload-time = "2026-09-10T18:03:40.71Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/29/42/eaff4c9b6d0c7cdf56df313a17e89ae854f5bbc0b0c8f9cce19be0ab7a8f/ruff-0.16.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce05b62b770a8217c4646a9c4139fca00efe8fe5d71f87df2b243ff20d4584d1", size = 11302938, upload-time = "2026-09-10T18:03:42.607Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5d/43/c75aa59a4ec181fe2ec06cab30e198c1c6d107229a9f008ae3a7c16cabd8/ruff-0.16.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af1b576fddb9d9ef2ececfb5fadcd6a624b25070ed85e3cfcfe449fc3ff6a7b9", size = 10840857, upload-time = "2026-09-10T18:03:44.604Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/21/33/81f3da371942ea031105ba679d8d6e28ec1660ccd690a45f42d381161356/ruff-0.16.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce7f8f22df67c93ed96c717f9128eadb797144ac2bad475cf536f31d6100c55", size = 10370001, upload-time = "2026-09-10T18:03:46.706Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fa/0b/6345fb4dbf6dd0ed1cfe5d18391dc9c3f59cc81622a7b0a65b84b3e730ba/ruff-0.16.7-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:06d0e93d04f392996435ebd600c153f65b47d73fbec2415aa99c5ee5756b3a5f", size = 10548735, upload-time = "2026-09-10T18:03:48.658Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3f/4d/c5576adf511f92a328e5569dda190ecdd430da51f1a649f3a4a2fd73e21e/ruff-0.16.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:142151a5e7b93c1b11111337142f89dd2fbfee92161225c99a97222f22e32656", size = 10108496, upload-time = "2026-09-10T18:03:50.563Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/8c/667d83c16199a17a56adc6b0bd4c3beb5b767a2babcd16a56f76f9be7fd6/ruff-0.16.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:e6651f97a342d8b35d54d8991544ca22169b86dc54111cb604666940c431b750", size = 9860136, upload-time = "2026-09-10T18:03:52.621Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/99/75/78d401106731999a1dd20cc5a6961e37e1eb9397a3b589f73f3a5ce146a3/ruff-0.16.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:ef140c6eb935fa9a84c9c607dfb2cb1b85843c192e79265b0c54f35f557ea8e5", size = 10286290, upload-time = "2026-09-10T18:03:55.207Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/49/56f9c3a8b755df93a0ad318b2147bf4ef5dae9a7e5ec61c460109c67957f/ruff-0.16.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:53e39506a730fadeee0d998ed5946f30671f0db240c6c7c73bdabbe33604bb6f", size = 10745048, upload-time = "2026-09-10T18:03:57.299Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/ea/7f9b938a63ece4bec677ad7f9f7fa02df3383db1949ed93a382441c09a87/ruff-0.16.7-py3-none-win32.whl", hash = "sha256:2ea3470fcebcbc5df2fb0c6f3b90333fa9084c534e0111c038fa4a6ab9f1c4b7", size = 10059082, upload-time = "2026-09-10T18:03:59.632Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/11/480a6973a927aa653e1cead6a6416008640e03a99d05b34c0434b8c6c366/ruff-0.16.7-py3-none-win_amd64.whl", hash = "sha256:7ac26aca826e9e21d0f1cb25b54ac660760a9fdd094d3e4df9848232be98cfc6", size = 10593368, upload-time = "2026-09-10T18:04:01.999Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/8b/4b/51327018d056f0dad2c2238f26d1fb0f53707a9d91b75dea6d1b3039f136/ruff-0.16.7-py3-none-win_arm64.whl", hash = "sha256:aab7f39e2c9df6c596216070f98eef1207b94f8516cca20c808826974971855b", size = 10412401, upload-time = "2026-09-10T18:04:04.098Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlparse"
|
||||
version = "0.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5f/d3/3f06a1006f2261d1342aefb3c71eed02f5d4ca5bdbecd86ebc12ad38306e/sqlparse-0.6.0.tar.gz", hash = "sha256:113c35c75365ab9cc9c7231d68c6428fb11c085fc8e9eb1ad659b7ddbf6cd2b9", size = 178477, upload-time = "2026-08-13T19:16:06.396Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/d9/50/f00935da0ec7cbf325f8dc4f772ae46fbc7b672dd62876e73f0a94adda57/sqlparse-0.6.0-py3-none-any.whl", hash = "sha256:b861c0288ce2fa56209a9a6412d2e066ac664b3873b89c26c9d8415e8e32996f", size = 50070, upload-time = "2026-08-13T19:16:04.062Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2026.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/92/ff/5a28bdfd8c3ebec42564ac7d0e54ca3db65044a9314a97f9564fa7a1e926/tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415", size = 198674, upload-time = "2026-07-10T08:50:37.887Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", size = 348168, upload-time = "2026-07-10T08:50:36.46Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "whitenoise"
|
||||
version = "6.12.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cb/2a/55b3f3a4ec326cd077c1c3defeee656b9298372a69229134d930151acd01/whitenoise-6.12.0.tar.gz", hash = "sha256:f723ebb76a112e98816ff80fcea0a6c9b8ecde835f8ddda25df7a30a3c2db6ad", size = 26841, upload-time = "2026-02-27T00:05:42.028Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/db/eb/d5583a11486211f3ebd4b385545ae787f32363d453c19fffd81106c9c138/whitenoise-6.12.0-py3-none-any.whl", hash = "sha256:fc5e8c572e33ebf24795b47b6a7da8da3c00cff2349f5b04c02f28d0cc5a3cc2", size = 20302, upload-time = "2026-02-27T00:05:40.086Z" },
|
||||
]
|
||||
Reference in new issue
Block a user