django-uv
Skill0 starsChanged 27 days agoMITView on GitHub
Provides expert knowledge for building Django 5+ projects with UV as the package manager, domain-driven app structure, ruff for linting, and pytest-django for testing.
- Reads credentials
In this repository219 other files it gives its agents.
- .agents/AGENTS.mdAGENTS.md
- AGENTS.mdAGENTS.md
- .claude/CLAUDE.mdCLAUDE.md
- CLAUDE.mdCLAUDE.md
- .cursor/rules/behavioral-discipline.mdcCursor rule
- .cursor/rules/context-budget.mdcCursor rule
- .cursor/rules/orchestration.mdcCursor rule
- .cursor/rules/yagni-stdlib.mdcCursor rule
- androidSkill
- android-ui-designSkill
- api-versioningSkill
- astroSkill
- auth-token-inspectorSkill
- backlogSkill
- cc-api-contractSkill
- cc-db-migrationSkill
- cc-featureSkill
- cc-fixSkill
- cc-pagespeedSkill
- cc-refactorSkill
- cc-reviewSkill
- cc-spec-mutationSkill
- cc-tdd-cycleSkill
- cc-test-planSkill
- code-reviewSkill
- commitSkill
- conductor-setupSkill
- councilSkill
- database-migrationsSkill
- django-ormSkill
- django-testingSkill
- drizzle-schema-architectSkill
- evaluationSkill
- fastapi-pydantic-strictSkill
- find-skillsSkill
- jpa-nplusone-detectorSkill
- jpa-postgresSkill
- laravel-specialistSkill
- livewire-alpine-bridgeSkill
- multi-agent-orchestrationSkill
- nextjs-typescriptSkill
- openspecSkill
- pagespeed-insightsSkill
- pagespeed-perfSkill
- php-proSkill
- python-django-stackSkill
- python-fastapi-stackSkill
- pythonSkill
- rust-asyncSkill
- rust-engineeringSkill
- rust-sqlxSkill
- security-ai-llmSkill
- security-blue-teamSkill
- security-cloudSkill
- security-cryptoSkill
- security-exploit-devSkill
- security-grcSkill
- security-incident-responseSkill
- security-log-analysisSkill
- security-malware-analysisSkill
- The first 60 shown.
The file
We split this skill into the rules it gives an agent
7 rules. About 0 are common, 2 are distinctive, and 5 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈2
Distinctive · estimate
This author's own choices. Worth a look.
5
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- could be automatic: a setting could enforce it
- Distinctive: line 205
Use UUID primary keys — never expose sequential integer IDs in public APIs
- Very specific: line 207
Always define __str__ — it appears in admin and error messages
- Very specific: line 208
Use blank=True for optional strings (form validation), null=True only for nullable FK/non-string fields
- Very specific: line 247
Use keyword-only arguments (* separator) in service methods — prevents positional argument confusion
- Very specific: line 249
Use update_fields in save() — avoids overwriting unintended fields and reduces the UPDATE query scope
- Very specific: line 252
Never import from views.py in services.py — keep the dependency direction strict: views → services → models
- Distinctive: line 405
Run ruff in CI on every pull request.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Django + UV
Project Setup with UV
UV replaces pip, pip-tools, virtualenv, and pyenv in a single binary. Always use UV for dependency management.
# Create project
uv init my-project
cd my-project
# Add Django and dependencies
uv add django psycopg[binary] djangorestframework django-environ
# Add dev dependencies
uv add --dev pytest pytest-django ruff factory-boy coverage
# Run management commands
uv run python manage.py migrate
uv run python manage.py runserverpyproject.toml Layout
[project]
name = "my-project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = [
"django>=5.0",
"psycopg[binary]>=3.1",
"djangorestframework>=3.15",
"django-environ>=0.11",
]
[project.optional-dependencies]
dev = [
"pytest>=8.0",
"pytest-django>=4.8",
"ruff>=0.4",
"factory-boy>=3.3",
"coverage>=7.4",
]
[tool.ruff]
line-length = 88
target-version = "py312"
[tool.ruff.lint]
select = ["E", "F", "I", "N", "UP", "B", "SIM"]
ignore = ["E501"]
[tool.pytest.ini_options]
DJANGO_SETTINGS_MODULE = "config.settings.test"
python_files = ["test_*.py", "*_test.py"]
python_classes = ["Test*"]
python_functions = ["test_*"]
[tool.coverage.run]
source = ["."]
omit = ["*/migrations/*", "*/tests/*", "manage.py"]App Structure (Domain-Driven)
Organize by domain, not by technical layer. Each Django app owns its domain entirely.
my_project/
config/
settings/
base.py — shared settings
dev.py — local overrides
test.py — test-specific settings
prod.py — production settings
urls.py
wsgi.py
apps/
users/
models.py
services.py — business logic, never in views
views.py — thin; delegates to services
serializers.py
admin.py
urls.py
tests/
test_models.py
test_services.py
test_views.py
factories.py
orders/
...
manage.py
pyproject.tomlSettings Split
# config/settings/base.py
from pathlib import Path
import environ
env = environ.Env()
BASE_DIR = Path(__file__).resolve().parent.parent.parent
SECRET_KEY = env("SECRET_KEY")
DEBUG = env.bool("DEBUG", default=False)
INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"rest_framework",
"apps.users",
"apps.orders",
]
DATABASES = {
"default": env.db("DATABASE_URL")
}# config/settings/test.py
from .base import * # noqa: F403
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
"NAME": ":memory:",
}
}
# Never send real emails in tests
EMAIL_BACKEND = "django.core.mail.backends.locmem.EmailBackend"Models
# apps/users/models.py
import uuid
from django.db import models
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
email = models.EmailField(unique=True)
bio = models.TextField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username"]
class Meta:
ordering = ["-created_at"]
def __str__(self) -> str:
return self.emailRules:
- Use UUID primary keys — never expose sequential integer IDs in public APIs
auto_now_addandauto_nowfor timestamps — never set manually- Always define
__str__— it appears in admin and error messages - Use
blank=Truefor optional strings (form validation),null=Trueonly for nullable FK/non-string fields
Service Layer
Business logic lives in services.py. Views are thin HTTP adapters.
# apps/users/services.py
from django.db import transaction
from django.contrib.auth.hashers import make_password
from .models import User
class UserService:
@staticmethod
def create_user(*, email: str, password: str, username: str) -> User:
if User.objects.filter(email=email).exists():
raise ValueError(f"Email {email!r} is already registered")
with transaction.atomic():
user = User.objects.create(
email=email,
username=username,
password=make_password(password),
)
return user
@staticmethod
def deactivate_user(*, user_id: str) -> User:
user = User.objects.get(id=user_id)
user.is_active = False
user.save(update_fields=["is_active", "updated_at"])
return userRules:
- Use keyword-only arguments (
*separator) in service methods — prevents positional argument confusion - Use
update_fieldsinsave()— avoids overwriting unintended fields and reduces the UPDATE query scope - Wrap multi-step writes in
transaction.atomic() - Never import from
views.pyinservices.py— keep the dependency direction strict: views → services → models
Views (DRF)
# apps/users/views.py
from rest_framework import status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.request import Request
from rest_framework.response import Response
from .serializers import CreateUserSerializer, UserSerializer
from .services import UserService
@api_view(["POST"])
def create_user(request: Request) -> Response:
serializer = CreateUserSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
user = UserService.create_user(**serializer.validated_data)
return Response(UserSerializer(user).data, status=status.HTTP_201_CREATED)
@api_view(["DELETE"])
@permission_classes([IsAuthenticated])
def deactivate_user(request: Request, user_id: str) -> Response:
UserService.deactivate_user(user_id=user_id)
return Response(status=status.HTTP_204_NO_CONTENT)Testing with pytest-django
Test Factories
# apps/users/tests/factories.py
import factory
from factory.django import DjangoModelFactory
from apps.users.models import User
class UserFactory(DjangoModelFactory):
class Meta:
model = User
email = factory.Sequence(lambda n: f"user{n}@example.com")
username = factory.Sequence(lambda n: f"user{n}")
password = factory.PostGenerationMethodCall("set_password", "testpass123")
is_active = TrueService Tests
# apps/users/tests/test_services.py
import pytest
from apps.users.services import UserService
@pytest.mark.django_db
class TestUserService:
def test_create_user_succeeds_with_valid_data(self):
user = UserService.create_user(
email="new@example.com",
password="secure123",
username="newuser",
)
assert user.pk is not None
assert user.email == "new@example.com"
assert user.check_password("secure123")
def test_create_user_raises_when_email_exists(self, user_factory):
existing = user_factory(email="taken@example.com")
with pytest.raises(ValueError, match="already registered"):
UserService.create_user(
email=existing.email,
password="any",
username="other",
)View Tests
# apps/users/tests/test_views.py
import pytest
from django.urls import reverse
@pytest.mark.django_db
class TestCreateUser:
def test_returns_201_with_valid_payload(self, client):
response = client.post(
reverse("users:create"),
data={"email": "new@example.com", "password": "secure123", "username": "new"},
content_type="application/json",
)
assert response.status_code == 201
assert response.data["email"] == "new@example.com"
def test_returns_400_with_invalid_email(self, client):
response = client.post(
reverse("users:create"),
data={"email": "not-an-email", "password": "x", "username": "y"},
content_type="application/json",
)
assert response.status_code == 400
def test_returns_400_when_email_already_exists(self, client, user_factory):
user_factory(email="taken@example.com")
response = client.post(
reverse("users:create"),
data={"email": "taken@example.com", "password": "pass", "username": "z"},
content_type="application/json",
)
assert response.status_code == 400conftest.py
# conftest.py
import pytest
from pytest_factoryboy import register
from apps.users.tests.factories import UserFactory
register(UserFactory) # makes user_factory fixture available everywhereLinting
# Check
uv run ruff check .
# Fix auto-fixable issues
uv run ruff check --fix .
# Format
uv run ruff format .Run ruff in CI on every pull request. Do not merge code that fails lint.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

