[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6DAEHA7SSC8KA76AJNXKKHQ":3,"skill-same:01M6DAEHA7SSC8KA76AJNXKKHQ":68},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":26,"publishedAt":42,"linkOnly":43,"markdownContent":44,"markdownBody":45,"frontMatter":46,"refName":48,"commitSha":49,"skillDirectory":50,"forksCount":14,"repositoryHtmlUrl":51,"repositoryHomepageUrl":6,"ownerHtmlUrl":52,"ownerBlogUrl":6,"ownerDescription":6,"updatedAt":53,"install":54,"resources":67},"01M6DAEHA7SSC8KA76AJNXKKHQ","django-patterns",null,"Django architecture patterns, REST API design with DRF, ORM best practices, caching, signals, middleware, and production-grade Django apps.","Prekzursil\u002Fagent-skills-toolchain","Prekzursil","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F54636077?v=4","01M6DACZ1PCQHD99SCR1YXG28B","Andrei Mihai Visalon","01M6DACZ670WZF535V3WYYSS4Z",0,"MIT","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Flibrary\u002Fskills\u002Fdjango-patterns\u002FSKILL.md",[18,23],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000010","后端与接口","SCENARIO","使用场景",{"categoryNo":24,"categoryName":25,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000015","视觉设计",[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41],"django patterns","django","patterns","design","architecture","api design","best practices","Production","REST","architecture patterns","api","orm","caching","signals","rest api","2026-11-10 10:12:30",false,"---\nname: django-patterns\ndescription: Django architecture patterns, REST API design with DRF, ORM best practices, caching, signals, middleware, and production-grade Django apps.\norigin: ECC\n---\n\n# Django Development Patterns\n\nProduction-grade Django architecture patterns for scalable, maintainable applications.\n\n## When to Activate\n\n- Building Django web applications\n- Designing Django REST Framework APIs\n- Working with Django ORM and models\n- Setting up Django project structure\n- Implementing caching, signals, middleware\n\n## Project Structure\n\n### Recommended Layout\n\n```\nmyproject\u002F\n├── config\u002F\n│   ├── __init__.py\n│   ├── settings\u002F\n│   │   ├── __init__.py\n│   │   ├── base.py          # Base settings\n│   │   ├── development.py   # Dev settings\n│   │   ├── production.py    # Production settings\n│   │   └── test.py          # Test settings\n│   ├── urls.py\n│   ├── wsgi.py\n│   └── asgi.py\n├── manage.py\n└── apps\u002F\n    ├── __init__.py\n    ├── users\u002F\n    │   ├── __init__.py\n    │   ├── models.py\n    │   ├── views.py\n    │   ├── serializers.py\n    │   ├── urls.py\n    │   ├── permissions.py\n    │   ├── filters.py\n    │   ├── services.py\n    │   └── tests\u002F\n    └── products\u002F\n        └── ...\n```\n\n### Split Settings Pattern\n\n```python\n# config\u002Fsettings\u002Fbase.py\nfrom pathlib import Path\n\nBASE_DIR = Path(__file__).resolve().parent.parent.parent\n\nSECRET_KEY = env('DJANGO_SECRET_KEY')\nDEBUG = False\nALLOWED_HOSTS = []\n\nINSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    'rest_framework',\n    'rest_framework.authtoken',\n    'corsheaders',\n    # Local apps\n    'apps.users',\n    'apps.products',\n]\n\nMIDDLEWARE = [\n    'django.middleware.security.SecurityMiddleware',\n    'whitenoise.middleware.WhiteNoiseMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'corsheaders.middleware.CorsMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n]\n\nROOT_URLCONF = 'config.urls'\nWSGI_APPLICATION = 'config.wsgi.application'\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.postgresql',\n        'NAME': env('DB_NAME'),\n        'USER': env('DB_USER'),\n        'PASSWORD': env('DB_PASSWORD'),\n        'HOST': env('DB_HOST'),\n        'PORT': env('DB_PORT', default='5432'),\n    }\n}\n\n# config\u002Fsettings\u002Fdevelopment.py\nfrom .base import *\n\nDEBUG = True\nALLOWED_HOSTS = ['localhost', '127.0.0.1']\n\nDATABASES['default']['NAME'] = 'myproject_dev'\n\nINSTALLED_APPS += ['debug_toolbar']\n\nMIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']\n\nEMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'\n\n# config\u002Fsettings\u002Fproduction.py\nfrom .base import *\n\nDEBUG = False\nALLOWED_HOSTS = env.list('ALLOWED_HOSTS')\nSECURE_SSL_REDIRECT = True\nSESSION_COOKIE_SECURE = True\nCSRF_COOKIE_SECURE = True\nSECURE_HSTS_SECONDS = 31536000\nSECURE_HSTS_INCLUDE_SUBDOMAINS = True\nSECURE_HSTS_PRELOAD = True\n\n# Logging\nLOGGING = {\n    'version': 1,\n    'disable_existing_loggers': False,\n    'handlers': {\n        'file': {\n            'level': 'WARNING',\n            'class': 'logging.FileHandler',\n            'filename': '\u002Fvar\u002Flog\u002Fdjango\u002Fdjango.log',\n        },\n    },\n    'loggers': {\n        'django': {\n            'handlers': ['file'],\n            'level': 'WARNING',\n            'propagate': True,\n        },\n    },\n}\n```\n\n## Model Design Patterns\n\n### Model Best Practices\n\n```python\nfrom django.db import models\nfrom django.contrib.auth.models import AbstractUser\nfrom django.core.validators import MinValueValidator, MaxValueValidator\n\nclass User(AbstractUser):\n    \"\"\"Custom user model extending AbstractUser.\"\"\"\n    email = models.EmailField(unique=True)\n    phone = models.CharField(max_length=20, blank=True)\n    birth_date = models.DateField(null=True, blank=True)\n\n    USERNAME_FIELD = 'email'\n    REQUIRED_FIELDS = ['username']\n\n    class Meta:\n        db_table = 'users'\n        verbose_name = 'user'\n        verbose_name_plural = 'users'\n        ordering = ['-date_joined']\n\n    def __str__(self):\n        return self.email\n\n    def get_full_name(self):\n        return f\"{self.first_name} {self.last_name}\".strip()\n\nclass Product(models.Model):\n    \"\"\"Product model with proper field configuration.\"\"\"\n    name = models.CharField(max_length=200)\n    slug = models.SlugField(unique=True, max_length=250)\n    description = models.TextField(blank=True)\n    price = models.DecimalField(\n        max_digits=10,\n        decimal_places=2,\n        validators=[MinValueValidator(0)]\n    )\n    stock = models.PositiveIntegerField(default=0)\n    is_active = models.BooleanField(default=True)\n    category = models.ForeignKey(\n        'Category',\n        on_delete=models.CASCADE,\n        related_name='products'\n    )\n    tags = models.ManyToManyField('Tag', blank=True, related_name='products')\n    created_at = models.DateTimeField(auto_now_add=True)\n    updated_at = models.DateTimeField(auto_now=True)\n\n    class Meta:\n        db_table = 'products'\n        ordering = ['-created_at']\n        indexes = [\n            models.Index(fields=['slug']),\n            models.Index(fields=['-created_at']),\n            models.Index(fields=['category', 'is_active']),\n        ]\n        constraints = [\n            models.CheckConstraint(\n                check=models.Q(price__gte=0),\n                name='price_non_negative'\n            )\n        ]\n\n    def __str__(self):\n        return self.name\n\n    def save(self, *args, **kwargs):\n        if not self.slug:\n            self.slug = slugify(self.name)\n        super().save(*args, **kwargs)\n```\n\n### QuerySet Best Practices\n\n```python\nfrom django.db import models\n\nclass ProductQuerySet(models.QuerySet):\n    \"\"\"Custom QuerySet for Product model.\"\"\"\n\n    def active(self):\n        \"\"\"Return only active products.\"\"\"\n        return self.filter(is_active=True)\n\n    def with_category(self):\n        \"\"\"Select related category to avoid N+1 queries.\"\"\"\n        return self.select_related('category')\n\n    def with_tags(self):\n        \"\"\"Prefetch tags for many-to-many relationship.\"\"\"\n        return self.prefetch_related('tags')\n\n    def in_stock(self):\n        \"\"\"Return products with stock > 0.\"\"\"\n        return self.filter(stock__gt=0)\n\n    def search(self, query):\n        \"\"\"Search products by name or description.\"\"\"\n        return self.filter(\n            models.Q(name__icontains=query) |\n            models.Q(description__icontains=query)\n        )\n\nclass Product(models.Model):\n    # ... fields ...\n\n    objects = ProductQuerySet.as_manager()  # Use custom QuerySet\n\n# Usage\nProduct.objects.active().with_category().in_stock()\n```\n\n### Manager Methods\n\n```python\nclass ProductManager(models.Manager):\n    \"\"\"Custom manager for complex queries.\"\"\"\n\n    def get_or_none(self, **kwargs):\n        \"\"\"Return object or None instead of DoesNotExist.\"\"\"\n        try:\n            return self.get(**kwargs)\n        except self.model.DoesNotExist:\n            return None\n\n    def create_with_tags(self, name, price, tag_names):\n        \"\"\"Create product with associated tags.\"\"\"\n        product = self.create(name=name, price=price)\n        tags = [Tag.objects.get_or_create(name=name)[0] for name in tag_names]\n        product.tags.set(tags)\n        return product\n\n    def bulk_update_stock(self, product_ids, quantity):\n        \"\"\"Bulk update stock for multiple products.\"\"\"\n        return self.filter(id__in=product_ids).update(stock=quantity)\n\n# In model\nclass Product(models.Model):\n    # ... fields ...\n    custom = ProductManager()\n```\n\n## Django REST Framework Patterns\n\n### Serializer Patterns\n\n```python\nfrom rest_framework import serializers\nfrom django.contrib.auth.password_validation import validate_password\nfrom .models import Product, User\n\nclass ProductSerializer(serializers.ModelSerializer):\n    \"\"\"Serializer for Product model.\"\"\"\n\n    category_name = serializers.CharField(source='category.name', read_only=True)\n    average_rating = serializers.FloatField(read_only=True)\n    discount_price = serializers.SerializerMethodField()\n\n    class Meta:\n        model = Product\n        fields = [\n            'id', 'name', 'slug', 'description', 'price',\n            'discount_price', 'stock', 'category_name',\n            'average_rating', 'created_at'\n        ]\n        read_only_fields = ['id', 'slug', 'created_at']\n\n    def get_discount_price(self, obj):\n        \"\"\"Calculate discount price if applicable.\"\"\"\n        if hasattr(obj, 'discount') and obj.discount:\n            return obj.price * (1 - obj.discount.percent \u002F 100)\n        return obj.price\n\n    def validate_price(self, value):\n        \"\"\"Ensure price is non-negative.\"\"\"\n        if value \u003C 0:\n            raise serializers.ValidationError(\"Price cannot be negative.\")\n        return value\n\nclass ProductCreateSerializer(serializers.ModelSerializer):\n    \"\"\"Serializer for creating products.\"\"\"\n\n    class Meta:\n        model = Product\n        fields = ['name', 'description', 'price', 'stock', 'category']\n\n    def validate(self, data):\n        \"\"\"Custom validation for multiple fields.\"\"\"\n        if data['price'] > 10000 and data['stock'] > 100:\n            raise serializers.ValidationError(\n                \"Cannot have high-value products with large stock.\"\n            )\n        return data\n\nclass UserRegistrationSerializer(serializers.ModelSerializer):\n    \"\"\"Serializer for user registration.\"\"\"\n\n    password = serializers.CharField(\n        write_only=True,\n        required=True,\n        validators=[validate_password],\n        style={'input_type': 'password'}\n    )\n    password_confirm = serializers.CharField(write_only=True, style={'input_type': 'password'})\n\n    class Meta:\n        model = User\n        fields = ['email', 'username', 'password', 'password_confirm']\n\n    def validate(self, data):\n        \"\"\"Validate passwords match.\"\"\"\n        if data['password'] != data['password_confirm']:\n            raise serializers.ValidationError({\n                \"password_confirm\": \"Password fields didn't match.\"\n            })\n        return data\n\n    def create(self, validated_data):\n        \"\"\"Create user with hashed password.\"\"\"\n        validated_data.pop('password_confirm')\n        password = validated_data.pop('password')\n        user = User.objects.create(**validated_data)\n        user.set_password(password)\n        user.save()\n        return user\n```\n\n### ViewSet Patterns\n\n```python\nfrom rest_framework import viewsets, status, filters\nfrom rest_framework.decorators import action\nfrom rest_framework.response import Response\nfrom rest_framework.permissions import IsAuthenticated, IsAdminUser\nfrom django_filters.rest_framework import DjangoFilterBackend\nfrom .models import Product\nfrom .serializers import ProductSerializer, ProductCreateSerializer\nfrom .permissions import IsOwnerOrReadOnly\nfrom .filters import ProductFilter\nfrom .services import ProductService\n\nclass ProductViewSet(viewsets.ModelViewSet):\n    \"\"\"ViewSet for Product model.\"\"\"\n\n    queryset = Product.objects.select_related('category').prefetch_related('tags')\n    permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]\n    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]\n    filterset_class = ProductFilter\n    search_fields = ['name', 'description']\n    ordering_fields = ['price', 'created_at', 'name']\n    ordering = ['-created_at']\n\n    def get_serializer_class(self):\n        \"\"\"Return appropriate serializer based on action.\"\"\"\n        if self.action == 'create':\n            return ProductCreateSerializer\n        return ProductSerializer\n\n    def perform_create(self, serializer):\n        \"\"\"Save with user context.\"\"\"\n        serializer.save(created_by=self.request.user)\n\n    @action(detail=False, methods=['get'])\n    def featured(self, request):\n        \"\"\"Return featured products.\"\"\"\n        featured = self.queryset.filter(is_featured=True)[:10]\n        serializer = self.get_serializer(featured, many=True)\n        return Response(serializer.data)\n\n    @action(detail=True, methods=['post'])\n    def purchase(self, request, pk=None):\n        \"\"\"Purchase a product.\"\"\"\n        product = self.get_object()\n        service = ProductService()\n        result = service.purchase(product, request.user)\n        return Response(result, status=status.HTTP_201_CREATED)\n\n    @action(detail=False, methods=['get'], permission_classes=[IsAuthenticated])\n    def my_products(self, request):\n        \"\"\"Return products created by current user.\"\"\"\n        products = self.queryset.filter(created_by=request.user)\n        page = self.paginate_queryset(products)\n        serializer = self.get_serializer(page, many=True)\n        return self.get_paginated_response(serializer.data)\n```\n\n### Custom Actions\n\n```python\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\n\n@api_view(['POST'])\n@permission_classes([IsAuthenticated])\ndef add_to_cart(request):\n    \"\"\"Add product to user cart.\"\"\"\n    product_id = request.data.get('product_id')\n    quantity = request.data.get('quantity', 1)\n\n    try:\n        product = Product.objects.get(id=product_id)\n    except Product.DoesNotExist:\n        return Response(\n            {'error': 'Product not found'},\n            status=status.HTTP_404_NOT_FOUND\n        )\n\n    cart, _ = Cart.objects.get_or_create(user=request.user)\n    CartItem.objects.create(\n        cart=cart,\n        product=product,\n        quantity=quantity\n    )\n\n    return Response({'message': 'Added to cart'}, status=status.HTTP_201_CREATED)\n```\n\n## Service Layer Pattern\n\n```python\n# apps\u002Forders\u002Fservices.py\nfrom typing import Optional\nfrom django.db import transaction\nfrom .models import Order, OrderItem\n\nclass OrderService:\n    \"\"\"Service layer for order-related business logic.\"\"\"\n\n    @staticmethod\n    @transaction.atomic\n    def create_order(user, cart: Cart) -> Order:\n        \"\"\"Create order from cart.\"\"\"\n        order = Order.objects.create(\n            user=user,\n            total_price=cart.total_price\n        )\n\n        for item in cart.items.all():\n            OrderItem.objects.create(\n                order=order,\n                product=item.product,\n                quantity=item.quantity,\n                price=item.product.price\n            )\n\n        # Clear cart\n        cart.items.all().delete()\n\n        return order\n\n    @staticmethod\n    def process_payment(order: Order, payment_data: dict) -> bool:\n        \"\"\"Process payment for order.\"\"\"\n        # Integration with payment gateway\n        payment = PaymentGateway.charge(\n            amount=order.total_price,\n            token=payment_data['token']\n        )\n\n        if payment.success:\n            order.status = Order.Status.PAID\n            order.save()\n            # Send confirmation email\n            OrderService.send_confirmation_email(order)\n            return True\n\n        return False\n\n    @staticmethod\n    def send_confirmation_email(order: Order):\n        \"\"\"Send order confirmation email.\"\"\"\n        # Email sending logic\n        pass\n```\n\n## Caching Strategies\n\n### View-Level Caching\n\n```python\nfrom django.views.decorators.cache import cache_page\nfrom django.utils.decorators import method_decorator\n\n@method_decorator(cache_page(60 * 15), name='dispatch')  # 15 minutes\nclass ProductListView(generic.ListView):\n    model = Product\n    template_name = 'products\u002Flist.html'\n    context_object_name = 'products'\n```\n\n### Template Fragment Caching\n\n```django\n{% load cache %}\n{% cache 500 sidebar %}\n    ... expensive sidebar content ...\n{% endcache %}\n```\n\n### Low-Level Caching\n\n```python\nfrom django.core.cache import cache\n\ndef get_featured_products():\n    \"\"\"Get featured products with caching.\"\"\"\n    cache_key = 'featured_products'\n    products = cache.get(cache_key)\n\n    if products is None:\n        products = list(Product.objects.filter(is_featured=True))\n        cache.set(cache_key, products, timeout=60 * 15)  # 15 minutes\n\n    return products\n```\n\n### QuerySet Caching\n\n```python\nfrom django.core.cache import cache\n\ndef get_popular_categories():\n    cache_key = 'popular_categories'\n    categories = cache.get(cache_key)\n\n    if categories is None:\n        categories = list(Category.objects.annotate(\n            product_count=Count('products')\n        ).filter(product_count__gt=10).order_by('-product_count')[:20])\n        cache.set(cache_key, categories, timeout=60 * 60)  # 1 hour\n\n    return categories\n```\n\n## Signals\n\n### Signal Patterns\n\n```python\n# apps\u002Fusers\u002Fsignals.py\nfrom django.db.models.signals import post_save\nfrom django.dispatch import receiver\nfrom django.contrib.auth import get_user_model\nfrom .models import Profile\n\nUser = get_user_model()\n\n@receiver(post_save, sender=User)\ndef create_user_profile(sender, instance, created, **kwargs):\n    \"\"\"Create profile when user is created.\"\"\"\n    if created:\n        Profile.objects.create(user=instance)\n\n@receiver(post_save, sender=User)\ndef save_user_profile(sender, instance, **kwargs):\n    \"\"\"Save profile when user is saved.\"\"\"\n    instance.profile.save()\n\n# apps\u002Fusers\u002Fapps.py\nfrom django.apps import AppConfig\n\nclass UsersConfig(AppConfig):\n    default_auto_field = 'django.db.models.BigAutoField'\n    name = 'apps.users'\n\n    def ready(self):\n        \"\"\"Import signals when app is ready.\"\"\"\n        import apps.users.signals\n```\n\n## Middleware\n\n### Custom Middleware\n\n```python\n# middleware\u002Factive_user_middleware.py\nimport time\nfrom django.utils.deprecation import MiddlewareMixin\n\nclass ActiveUserMiddleware(MiddlewareMixin):\n    \"\"\"Middleware to track active users.\"\"\"\n\n    def process_request(self, request):\n        \"\"\"Process incoming request.\"\"\"\n        if request.user.is_authenticated:\n            # Update last active time\n            request.user.last_active = timezone.now()\n            request.user.save(update_fields=['last_active'])\n\nclass RequestLoggingMiddleware(MiddlewareMixin):\n    \"\"\"Middleware for logging requests.\"\"\"\n\n    def process_request(self, request):\n        \"\"\"Log request start time.\"\"\"\n        request.start_time = time.time()\n\n    def process_response(self, request, response):\n        \"\"\"Log request duration.\"\"\"\n        if hasattr(request, 'start_time'):\n            duration = time.time() - request.start_time\n            logger.info(f'{request.method} {request.path} - {response.status_code} - {duration:.3f}s')\n        return response\n```\n\n## Performance Optimization\n\n### N+1 Query Prevention\n\n```python\n# Bad - N+1 queries\nproducts = Product.objects.all()\nfor product in products:\n    print(product.category.name)  # Separate query for each product\n\n# Good - Single query with select_related\nproducts = Product.objects.select_related('category').all()\nfor product in products:\n    print(product.category.name)\n\n# Good - Prefetch for many-to-many\nproducts = Product.objects.prefetch_related('tags').all()\nfor product in products:\n    for tag in product.tags.all():\n        print(tag.name)\n```\n\n### Database Indexing\n\n```python\nclass Product(models.Model):\n    name = models.CharField(max_length=200, db_index=True)\n    slug = models.SlugField(unique=True)\n    category = models.ForeignKey('Category', on_delete=models.CASCADE)\n    created_at = models.DateTimeField(auto_now_add=True)\n\n    class Meta:\n        indexes = [\n            models.Index(fields=['name']),\n            models.Index(fields=['-created_at']),\n            models.Index(fields=['category', 'created_at']),\n        ]\n```\n\n### Bulk Operations\n\n```python\n# Bulk create\nProduct.objects.bulk_create([\n    Product(name=f'Product {i}', price=10.00)\n    for i in range(1000)\n])\n\n# Bulk update\nproducts = Product.objects.all()[:100]\nfor product in products:\n    product.is_active = True\nProduct.objects.bulk_update(products, ['is_active'])\n\n# Bulk delete\nProduct.objects.filter(stock=0).delete()\n```\n\n## Quick Reference\n\n| Pattern | Description |\n|---------|-------------|\n| Split settings | Separate dev\u002Fprod\u002Ftest settings |\n| Custom QuerySet | Reusable query methods |\n| Service Layer | Business logic separation |\n| ViewSet | REST API endpoints |\n| Serializer validation | Request\u002Fresponse transformation |\n| select_related | Foreign key optimization |\n| prefetch_related | Many-to-many optimization |\n| Cache first | Cache expensive operations |\n| Signals | Event-driven actions |\n| Middleware | Request\u002Fresponse processing |\n\nRemember: Django provides many shortcuts, but for production applications, structure and organization matter more than concise code. Build for maintainability.\n","# Django Development Patterns\n\nProduction-grade Django architecture patterns for scalable, maintainable applications.\n\n## When to Activate\n\n- Building Django web applications\n- Designing Django REST Framework APIs\n- Working with Django ORM and models\n- Setting up Django project structure\n- Implementing caching, signals, middleware\n\n## Project Structure\n\n### Recommended Layout\n\n```\nmyproject\u002F\n├── config\u002F\n│   ├── __init__.py\n│   ├── settings\u002F\n│   │   ├── __init__.py\n│   │   ├── base.py          # Base settings\n│   │   ├── development.py   # Dev settings\n│   │   ├── production.py    # Production settings\n│   │   └── test.py          # Test settings\n│   ├── urls.py\n│   ├── wsgi.py\n│   └── asgi.py\n├── manage.py\n└── apps\u002F\n    ├── __init__.py\n    ├── users\u002F\n    │   ├── __init__.py\n    │   ├── models.py\n    │   ├── views.py\n    │   ├── serializers.py\n    │   ├── urls.py\n    │   ├── permissions.py\n    │   ├── filters.py\n    │   ├── services.py\n    │   └── tests\u002F\n    └── products\u002F\n        └── ...\n```\n\n### Split Settings Pattern\n\n```python\n# config\u002Fsettings\u002Fbase.py\nfrom pathlib import Path\n\nBASE_DIR = Path(__file__).resolve().parent.parent.parent\n\nSECRET_KEY = env('DJANGO_SECRET_KEY')\nDEBUG = False\nALLOWED_HOSTS = []\n\nINSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',\n    'rest_framework',\n    'rest_framework.authtoken',\n    'corsheaders',\n    # Local apps\n    'apps.users',\n    'apps.products',\n]\n\nMIDDLEWARE = [\n    'django.middleware.security.SecurityMiddleware',\n    'whitenoise.middleware.WhiteNoiseMiddleware',\n    'django.contrib.sessions.middleware.SessionMiddleware',\n    'corsheaders.middleware.CorsMiddleware',\n    'django.middleware.common.CommonMiddleware',\n    'django.middleware.csrf.CsrfViewMiddleware',\n    'django.contrib.auth.middleware.AuthenticationMiddleware',\n    'django.contrib.messages.middleware.MessageMiddleware',\n    'django.middleware.clickjacking.XFrameOptionsMiddleware',\n]\n\nROOT_URLCONF = 'config.urls'\nWSGI_APPLICATION = 'config.wsgi.application'\n\nDATABASES = {\n    'default': {\n        'ENGINE': 'django.db.backends.postgresql',\n        'NAME': env('DB_NAME'),\n        'USER': env('DB_USER'),\n        'PASSWORD': env('DB_PASSWORD'),\n        'HOST': env('DB_HOST'),\n        'PORT': env('DB_PORT', default='5432'),\n    }\n}\n\n# config\u002Fsettings\u002Fdevelopment.py\nfrom .base import *\n\nDEBUG = True\nALLOWED_HOSTS = ['localhost', '127.0.0.1']\n\nDATABASES['default']['NAME'] = 'myproject_dev'\n\nINSTALLED_APPS += ['debug_toolbar']\n\nMIDDLEWARE += ['debug_toolbar.middleware.DebugToolbarMiddleware']\n\nEMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'\n\n# config\u002Fsettings\u002Fproduction.py\nfrom .base import *\n\nDEBUG = False\nALLOWED_HOSTS = env.list('ALLOWED_HOSTS')\nSECURE_SSL_REDIRECT = True\nSESSION_COOKIE_SECURE = True\nCSRF_COOKIE_SECURE = True\nSECURE_HSTS_SECONDS = 31536000\nSECURE_HSTS_INCLUDE_SUBDOMAINS = True\nSECURE_HSTS_PRELOAD = True\n\n# Logging\nLOGGING = {\n    'version': 1,\n    'disable_existing_loggers': False,\n    'handlers': {\n        'file': {\n            'level': 'WARNING',\n            'class': 'logging.FileHandler',\n            'filename': '\u002Fvar\u002Flog\u002Fdjango\u002Fdjango.log',\n        },\n    },\n    'loggers': {\n        'django': {\n            'handlers': ['file'],\n            'level': 'WARNING',\n            'propagate': True,\n        },\n    },\n}\n```\n\n## Model Design Patterns\n\n### Model Best Practices\n\n```python\nfrom django.db import models\nfrom django.contrib.auth.models import AbstractUser\nfrom django.core.validators import MinValueValidator, MaxValueValidator\n\nclass User(AbstractUser):\n    \"\"\"Custom user model extending AbstractUser.\"\"\"\n    email = models.EmailField(unique=True)\n    phone = models.CharField(max_length=20, blank=True)\n    birth_date = models.DateField(null=True, blank=True)\n\n    USERNAME_FIELD = 'email'\n    REQUIRED_FIELDS = ['username']\n\n    class Meta:\n        db_table = 'users'\n        verbose_name = 'user'\n        verbose_name_plural = 'users'\n        ordering = ['-date_joined']\n\n    def __str__(self):\n        return self.email\n\n    def get_full_name(self):\n        return f\"{self.first_name} {self.last_name}\".strip()\n\nclass Product(models.Model):\n    \"\"\"Product model with proper field configuration.\"\"\"\n    name = models.CharField(max_length=200)\n    slug = models.SlugField(unique=True, max_length=250)\n    description = models.TextField(blank=True)\n    price = models.DecimalField(\n        max_digits=10,\n        decimal_places=2,\n        validators=[MinValueValidator(0)]\n    )\n    stock = models.PositiveIntegerField(default=0)\n    is_active = models.BooleanField(default=True)\n    category = models.ForeignKey(\n        'Category',\n        on_delete=models.CASCADE,\n        related_name='products'\n    )\n    tags = models.ManyToManyField('Tag', blank=True, related_name='products')\n    created_at = models.DateTimeField(auto_now_add=True)\n    updated_at = models.DateTimeField(auto_now=True)\n\n    class Meta:\n        db_table = 'products'\n        ordering = ['-created_at']\n        indexes = [\n            models.Index(fields=['slug']),\n            models.Index(fields=['-created_at']),\n            models.Index(fields=['category', 'is_active']),\n        ]\n        constraints = [\n            models.CheckConstraint(\n                check=models.Q(price__gte=0),\n                name='price_non_negative'\n            )\n        ]\n\n    def __str__(self):\n        return self.name\n\n    def save(self, *args, **kwargs):\n        if not self.slug:\n            self.slug = slugify(self.name)\n        super().save(*args, **kwargs)\n```\n\n### QuerySet Best Practices\n\n```python\nfrom django.db import models\n\nclass ProductQuerySet(models.QuerySet):\n    \"\"\"Custom QuerySet for Product model.\"\"\"\n\n    def active(self):\n        \"\"\"Return only active products.\"\"\"\n        return self.filter(is_active=True)\n\n    def with_category(self):\n        \"\"\"Select related category to avoid N+1 queries.\"\"\"\n        return self.select_related('category')\n\n    def with_tags(self):\n        \"\"\"Prefetch tags for many-to-many relationship.\"\"\"\n        return self.prefetch_related('tags')\n\n    def in_stock(self):\n        \"\"\"Return products with stock > 0.\"\"\"\n        return self.filter(stock__gt=0)\n\n    def search(self, query):\n        \"\"\"Search products by name or description.\"\"\"\n        return self.filter(\n            models.Q(name__icontains=query) |\n            models.Q(description__icontains=query)\n        )\n\nclass Product(models.Model):\n    # ... fields ...\n\n    objects = ProductQuerySet.as_manager()  # Use custom QuerySet\n\n# Usage\nProduct.objects.active().with_category().in_stock()\n```\n\n### Manager Methods\n\n```python\nclass ProductManager(models.Manager):\n    \"\"\"Custom manager for complex queries.\"\"\"\n\n    def get_or_none(self, **kwargs):\n        \"\"\"Return object or None instead of DoesNotExist.\"\"\"\n        try:\n            return self.get(**kwargs)\n        except self.model.DoesNotExist:\n            return None\n\n    def create_with_tags(self, name, price, tag_names):\n        \"\"\"Create product with associated tags.\"\"\"\n        product = self.create(name=name, price=price)\n        tags = [Tag.objects.get_or_create(name=name)[0] for name in tag_names]\n        product.tags.set(tags)\n        return product\n\n    def bulk_update_stock(self, product_ids, quantity):\n        \"\"\"Bulk update stock for multiple products.\"\"\"\n        return self.filter(id__in=product_ids).update(stock=quantity)\n\n# In model\nclass Product(models.Model):\n    # ... fields ...\n    custom = ProductManager()\n```\n\n## Django REST Framework Patterns\n\n### Serializer Patterns\n\n```python\nfrom rest_framework import serializers\nfrom django.contrib.auth.password_validation import validate_password\nfrom .models import Product, User\n\nclass ProductSerializer(serializers.ModelSerializer):\n    \"\"\"Serializer for Product model.\"\"\"\n\n    category_name = serializers.CharField(source='category.name', read_only=True)\n    average_rating = serializers.FloatField(read_only=True)\n    discount_price = serializers.SerializerMethodField()\n\n    class Meta:\n        model = Product\n        fields = [\n            'id', 'name', 'slug', 'description', 'price',\n            'discount_price', 'stock', 'category_name',\n            'average_rating', 'created_at'\n        ]\n        read_only_fields = ['id', 'slug', 'created_at']\n\n    def get_discount_price(self, obj):\n        \"\"\"Calculate discount price if applicable.\"\"\"\n        if hasattr(obj, 'discount') and obj.discount:\n            return obj.price * (1 - obj.discount.percent \u002F 100)\n        return obj.price\n\n    def validate_price(self, value):\n        \"\"\"Ensure price is non-negative.\"\"\"\n        if value \u003C 0:\n            raise serializers.ValidationError(\"Price cannot be negative.\")\n        return value\n\nclass ProductCreateSerializer(serializers.ModelSerializer):\n    \"\"\"Serializer for creating products.\"\"\"\n\n    class Meta:\n        model = Product\n        fields = ['name', 'description', 'price', 'stock', 'category']\n\n    def validate(self, data):\n        \"\"\"Custom validation for multiple fields.\"\"\"\n        if data['price'] > 10000 and data['stock'] > 100:\n            raise serializers.ValidationError(\n                \"Cannot have high-value products with large stock.\"\n            )\n        return data\n\nclass UserRegistrationSerializer(serializers.ModelSerializer):\n    \"\"\"Serializer for user registration.\"\"\"\n\n    password = serializers.CharField(\n        write_only=True,\n        required=True,\n        validators=[validate_password],\n        style={'input_type': 'password'}\n    )\n    password_confirm = serializers.CharField(write_only=True, style={'input_type': 'password'})\n\n    class Meta:\n        model = User\n        fields = ['email', 'username', 'password', 'password_confirm']\n\n    def validate(self, data):\n        \"\"\"Validate passwords match.\"\"\"\n        if data['password'] != data['password_confirm']:\n            raise serializers.ValidationError({\n                \"password_confirm\": \"Password fields didn't match.\"\n            })\n        return data\n\n    def create(self, validated_data):\n        \"\"\"Create user with hashed password.\"\"\"\n        validated_data.pop('password_confirm')\n        password = validated_data.pop('password')\n        user = User.objects.create(**validated_data)\n        user.set_password(password)\n        user.save()\n        return user\n```\n\n### ViewSet Patterns\n\n```python\nfrom rest_framework import viewsets, status, filters\nfrom rest_framework.decorators import action\nfrom rest_framework.response import Response\nfrom rest_framework.permissions import IsAuthenticated, IsAdminUser\nfrom django_filters.rest_framework import DjangoFilterBackend\nfrom .models import Product\nfrom .serializers import ProductSerializer, ProductCreateSerializer\nfrom .permissions import IsOwnerOrReadOnly\nfrom .filters import ProductFilter\nfrom .services import ProductService\n\nclass ProductViewSet(viewsets.ModelViewSet):\n    \"\"\"ViewSet for Product model.\"\"\"\n\n    queryset = Product.objects.select_related('category').prefetch_related('tags')\n    permission_classes = [IsAuthenticated, IsOwnerOrReadOnly]\n    filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]\n    filterset_class = ProductFilter\n    search_fields = ['name', 'description']\n    ordering_fields = ['price', 'created_at', 'name']\n    ordering = ['-created_at']\n\n    def get_serializer_class(self):\n        \"\"\"Return appropriate serializer based on action.\"\"\"\n        if self.action == 'create':\n            return ProductCreateSerializer\n        return ProductSerializer\n\n    def perform_create(self, serializer):\n        \"\"\"Save with user context.\"\"\"\n        serializer.save(created_by=self.request.user)\n\n    @action(detail=False, methods=['get'])\n    def featured(self, request):\n        \"\"\"Return featured products.\"\"\"\n        featured = self.queryset.filter(is_featured=True)[:10]\n        serializer = self.get_serializer(featured, many=True)\n        return Response(serializer.data)\n\n    @action(detail=True, methods=['post'])\n    def purchase(self, request, pk=None):\n        \"\"\"Purchase a product.\"\"\"\n        product = self.get_object()\n        service = ProductService()\n        result = service.purchase(product, request.user)\n        return Response(result, status=status.HTTP_201_CREATED)\n\n    @action(detail=False, methods=['get'], permission_classes=[IsAuthenticated])\n    def my_products(self, request):\n        \"\"\"Return products created by current user.\"\"\"\n        products = self.queryset.filter(created_by=request.user)\n        page = self.paginate_queryset(products)\n        serializer = self.get_serializer(page, many=True)\n        return self.get_paginated_response(serializer.data)\n```\n\n### Custom Actions\n\n```python\nfrom rest_framework.decorators import api_view, permission_classes\nfrom rest_framework.permissions import IsAuthenticated\nfrom rest_framework.response import Response\n\n@api_view(['POST'])\n@permission_classes([IsAuthenticated])\ndef add_to_cart(request):\n    \"\"\"Add product to user cart.\"\"\"\n    product_id = request.data.get('product_id')\n    quantity = request.data.get('quantity', 1)\n\n    try:\n        product = Product.objects.get(id=product_id)\n    except Product.DoesNotExist:\n        return Response(\n            {'error': 'Product not found'},\n            status=status.HTTP_404_NOT_FOUND\n        )\n\n    cart, _ = Cart.objects.get_or_create(user=request.user)\n    CartItem.objects.create(\n        cart=cart,\n        product=product,\n        quantity=quantity\n    )\n\n    return Response({'message': 'Added to cart'}, status=status.HTTP_201_CREATED)\n```\n\n## Service Layer Pattern\n\n```python\n# apps\u002Forders\u002Fservices.py\nfrom typing import Optional\nfrom django.db import transaction\nfrom .models import Order, OrderItem\n\nclass OrderService:\n    \"\"\"Service layer for order-related business logic.\"\"\"\n\n    @staticmethod\n    @transaction.atomic\n    def create_order(user, cart: Cart) -> Order:\n        \"\"\"Create order from cart.\"\"\"\n        order = Order.objects.create(\n            user=user,\n            total_price=cart.total_price\n        )\n\n        for item in cart.items.all():\n            OrderItem.objects.create(\n                order=order,\n                product=item.product,\n                quantity=item.quantity,\n                price=item.product.price\n            )\n\n        # Clear cart\n        cart.items.all().delete()\n\n        return order\n\n    @staticmethod\n    def process_payment(order: Order, payment_data: dict) -> bool:\n        \"\"\"Process payment for order.\"\"\"\n        # Integration with payment gateway\n        payment = PaymentGateway.charge(\n            amount=order.total_price,\n            token=payment_data['token']\n        )\n\n        if payment.success:\n            order.status = Order.Status.PAID\n            order.save()\n            # Send confirmation email\n            OrderService.send_confirmation_email(order)\n            return True\n\n        return False\n\n    @staticmethod\n    def send_confirmation_email(order: Order):\n        \"\"\"Send order confirmation email.\"\"\"\n        # Email sending logic\n        pass\n```\n\n## Caching Strategies\n\n### View-Level Caching\n\n```python\nfrom django.views.decorators.cache import cache_page\nfrom django.utils.decorators import method_decorator\n\n@method_decorator(cache_page(60 * 15), name='dispatch')  # 15 minutes\nclass ProductListView(generic.ListView):\n    model = Product\n    template_name = 'products\u002Flist.html'\n    context_object_name = 'products'\n```\n\n### Template Fragment Caching\n\n```django\n{% load cache %}\n{% cache 500 sidebar %}\n    ... expensive sidebar content ...\n{% endcache %}\n```\n\n### Low-Level Caching\n\n```python\nfrom django.core.cache import cache\n\ndef get_featured_products():\n    \"\"\"Get featured products with caching.\"\"\"\n    cache_key = 'featured_products'\n    products = cache.get(cache_key)\n\n    if products is None:\n        products = list(Product.objects.filter(is_featured=True))\n        cache.set(cache_key, products, timeout=60 * 15)  # 15 minutes\n\n    return products\n```\n\n### QuerySet Caching\n\n```python\nfrom django.core.cache import cache\n\ndef get_popular_categories():\n    cache_key = 'popular_categories'\n    categories = cache.get(cache_key)\n\n    if categories is None:\n        categories = list(Category.objects.annotate(\n            product_count=Count('products')\n        ).filter(product_count__gt=10).order_by('-product_count')[:20])\n        cache.set(cache_key, categories, timeout=60 * 60)  # 1 hour\n\n    return categories\n```\n\n## Signals\n\n### Signal Patterns\n\n```python\n# apps\u002Fusers\u002Fsignals.py\nfrom django.db.models.signals import post_save\nfrom django.dispatch import receiver\nfrom django.contrib.auth import get_user_model\nfrom .models import Profile\n\nUser = get_user_model()\n\n@receiver(post_save, sender=User)\ndef create_user_profile(sender, instance, created, **kwargs):\n    \"\"\"Create profile when user is created.\"\"\"\n    if created:\n        Profile.objects.create(user=instance)\n\n@receiver(post_save, sender=User)\ndef save_user_profile(sender, instance, **kwargs):\n    \"\"\"Save profile when user is saved.\"\"\"\n    instance.profile.save()\n\n# apps\u002Fusers\u002Fapps.py\nfrom django.apps import AppConfig\n\nclass UsersConfig(AppConfig):\n    default_auto_field = 'django.db.models.BigAutoField'\n    name = 'apps.users'\n\n    def ready(self):\n        \"\"\"Import signals when app is ready.\"\"\"\n        import apps.users.signals\n```\n\n## Middleware\n\n### Custom Middleware\n\n```python\n# middleware\u002Factive_user_middleware.py\nimport time\nfrom django.utils.deprecation import MiddlewareMixin\n\nclass ActiveUserMiddleware(MiddlewareMixin):\n    \"\"\"Middleware to track active users.\"\"\"\n\n    def process_request(self, request):\n        \"\"\"Process incoming request.\"\"\"\n        if request.user.is_authenticated:\n            # Update last active time\n            request.user.last_active = timezone.now()\n            request.user.save(update_fields=['last_active'])\n\nclass RequestLoggingMiddleware(MiddlewareMixin):\n    \"\"\"Middleware for logging requests.\"\"\"\n\n    def process_request(self, request):\n        \"\"\"Log request start time.\"\"\"\n        request.start_time = time.time()\n\n    def process_response(self, request, response):\n        \"\"\"Log request duration.\"\"\"\n        if hasattr(request, 'start_time'):\n            duration = time.time() - request.start_time\n            logger.info(f'{request.method} {request.path} - {response.status_code} - {duration:.3f}s')\n        return response\n```\n\n## Performance Optimization\n\n### N+1 Query Prevention\n\n```python\n# Bad - N+1 queries\nproducts = Product.objects.all()\nfor product in products:\n    print(product.category.name)  # Separate query for each product\n\n# Good - Single query with select_related\nproducts = Product.objects.select_related('category').all()\nfor product in products:\n    print(product.category.name)\n\n# Good - Prefetch for many-to-many\nproducts = Product.objects.prefetch_related('tags').all()\nfor product in products:\n    for tag in product.tags.all():\n        print(tag.name)\n```\n\n### Database Indexing\n\n```python\nclass Product(models.Model):\n    name = models.CharField(max_length=200, db_index=True)\n    slug = models.SlugField(unique=True)\n    category = models.ForeignKey('Category', on_delete=models.CASCADE)\n    created_at = models.DateTimeField(auto_now_add=True)\n\n    class Meta:\n        indexes = [\n            models.Index(fields=['name']),\n            models.Index(fields=['-created_at']),\n            models.Index(fields=['category', 'created_at']),\n        ]\n```\n\n### Bulk Operations\n\n```python\n# Bulk create\nProduct.objects.bulk_create([\n    Product(name=f'Product {i}', price=10.00)\n    for i in range(1000)\n])\n\n# Bulk update\nproducts = Product.objects.all()[:100]\nfor product in products:\n    product.is_active = True\nProduct.objects.bulk_update(products, ['is_active'])\n\n# Bulk delete\nProduct.objects.filter(stock=0).delete()\n```\n\n## Quick Reference\n\n| Pattern | Description |\n|---------|-------------|\n| Split settings | Separate dev\u002Fprod\u002Ftest settings |\n| Custom QuerySet | Reusable query methods |\n| Service Layer | Business logic separation |\n| ViewSet | REST API endpoints |\n| Serializer validation | Request\u002Fresponse transformation |\n| select_related | Foreign key optimization |\n| prefetch_related | Many-to-many optimization |\n| Cache first | Cache expensive operations |\n| Signals | Event-driven actions |\n| Middleware | Request\u002Fresponse processing |\n\nRemember: Django provides many shortcuts, but for production applications, structure and organization matter more than concise code. Build for maintainability.\n",{"name":5,"origin":47,"description":7},"ECC","main","a298c929b6cbd662e1fce54302ce520d5ceea1a5",".agents\u002Flibrary\u002Fskills\u002Fdjango-patterns","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain","https:\u002F\u002Fgithub.com\u002FPrekzursil","2026-11-02 14:30:57",{"source":8,"skillName":5,"commands":55,"prompt":65,"zipAvailable":66},[56,59,62],{"tool":57,"command":58},"npx","npx skills add Prekzursil\u002Fagent-skills-toolchain --skill django-patterns",{"tool":60,"command":61},"bunx","bunx skills add Prekzursil\u002Fagent-skills-toolchain --skill django-patterns",{"tool":63,"command":64},"pnpm","pnpm dlx skills add Prekzursil\u002Fagent-skills-toolchain --skill django-patterns","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002F.agents\u002Flibrary\u002Fskills\u002Fdjango-patterns\u002FSKILL.md",true,[],[69,91,120,147,161,177],{"skillNo":70,"name":71,"nameZh":6,"description":72,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":73,"categories":74,"keywords":75,"publishedAt":42},"01M6DF7D7478R55P46REYH4QAC","clarify-requirements","Resolve genuine pre-execution ambiguity by scanning repo context, generating 1-6 grounded options, and asking 1-3 focused questions via AskUserQuestion. NOT for mid-task use (injection risk); NOT when the goal is already unambiguous; use to disambiguate vague prompts before any file edits.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fworkspace-hooks\u002Fskills\u002Fclarify-requirements\u002FSKILL.md",[],[76,77,78,79,80,81,82,83,84,85,86,87,88,89,90],"clarify requirements","clarify","requirements","risk","options","task","prompts","goal","scanning","use","context","repo","injection","execution","file",{"skillNo":92,"name":93,"nameZh":6,"description":94,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":95,"categories":96,"keywords":100,"publishedAt":42},"01M6DF79CA4BHJS66J8EZDBPWJ","openmm-md","Run FREE, open-source, Windows-native GPU molecular dynamics via the openmm-md MCP (OpenMM + CUDA on the local NVIDIA GPU). Use for protein \u002F protein-ligand MD when you want a free stack or are on Windows without a Schrodinger license. Covers the full workflow (prepare, solvate, minimize, equilibrate, production, analyze, mmgbsa) AND an honest decision guide vs Schrodinger Desmond, including how to run Desmond legitimately on Linux or a cloud GPU with a real license. This is a deliberately LESSER free alternative and does NOT replace the schrodinger MCP tools. Do NOT use it to pick a free tool when a validated FEP+, WaterMap, IFD-MD, or Prime MM-GBSA result is actually required.","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Fmcp\u002Fopenmm-md-mcp\u002Fskill\u002Fopenmm-md\u002FSKILL.md",[97],{"categoryNo":98,"categoryName":99,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000023","Skill与智能体开发",[101,102,103,104,105,106,107,108,109,110,111,112,113,114,85,115,116,117,118,119],"openmm md","how","decision","pick","linux","analyze","tool","stack","open","NVIDIA","gpu","license","workflow","windows","free","molecular dynamics","local","do","MCP",{"skillNo":121,"name":122,"nameZh":6,"description":123,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":124,"categories":125,"keywords":132,"publishedAt":42},"01M6DF76C1MG85VEWP8VZCBNMN","visual-review","Take screenshots of web pages and UI using Playwright for visual review and iteration","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fvisual-review\u002FSKILL.md",[126,129],{"categoryNo":127,"categoryName":128,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000003","演示文稿",{"categoryNo":130,"categoryName":131,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000008","测试与质量",[133,134,135,136,137,138,139,140,141,142,102,143,144,145,146],"review","visual","visual review","pages","web","false","iteration","take","check","slides","ui","screenshot","playwright","screenshots",{"skillNo":148,"name":149,"nameZh":6,"description":150,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":151,"categories":152,"keywords":153,"publishedAt":42},"01M6DF73AQVCBZKEN0YXEX9FXP","status","Diagnostic status report — shows metaswarm installation state, project setup, and potential issues","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstatus\u002FSKILL.md",[],[149,154,155,156,157,158,159,160],"setup","report","project","installation","project setup","issues","state",{"skillNo":162,"name":163,"nameZh":6,"description":164,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":165,"categories":166,"keywords":168,"publishedAt":42},"01M6DF6X6C2XB0P6GX76P7TTYV","start","Use when starting work on any task, when the user mentions metaswarm, or when the user wants to begin tracked development work","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fstart\u002FSKILL.md",[167],{"categoryNo":98,"categoryName":99,"taxonomyType":21,"taxonomyTypeDesc":22},[163,169,81,170,171,172,85,173,174,175,176],"start issue","issue","ready","work on issue","user","work","work on","development",{"skillNo":178,"name":154,"nameZh":6,"description":179,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":180,"categories":181,"keywords":182,"publishedAt":42},"01M6DF6QMJ9AJKFKHHKRT005PQ","Interactive project setup — detects your project, configures metaswarm, writes project-local files","https:\u002F\u002Fgithub.com\u002FPrekzursil\u002Fagent-skills-toolchain\u002Fblob\u002Fmain\u002Ftools\u002Feditor\u002Fmetaswarm\u002Fskills\u002Fsetup\u002FSKILL.md",[],[154,156,117,183,158,184],"files","interactive"]