Token导航 LogoToken导航TokenDH.com
待分类需要联网github未标认证来源可访问许可证需确认审计通过

servicesservices 命令行

Agent Skill

services 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

267

周安装

11

GitHub Stars

101

下载量

87
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:services(services 命令行)
来源仓库:https://github.com/dvf/opinionated-django
仓库路径:skills/services
安装命令:
npx skills add https://github.com/dvf/opinionated-django --skill services
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/dvf/opinionated-django --skill services

简介

services 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息。

  • 适合在 Codex、Claude、Cursor、Gemini CLI 中围绕仓库状态、代码变更或协作事项进行整理时使用。
  • 可结合来源仓库、安装命令和原始 README 继续核验具体用法。
  • 安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。
  • services 属于待分类类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

Services + svcs Dependency Injection

This project separates Django's framework concerns from business logic using a plain service layer, wired with the svcs service locator. The result:

  • Views are one-liners. They pull a wired service and call a method.
  • Services contain the business logic. They take repositories (and other services) via __init__, call methods on them, and return DTOs.
  • Services never import Django ORM or models. Every test can run without a database.
  • One registry, one get[T]() helper. The same call works in views, tasks, commands, anywhere.

Why svcs Instead of Module-Level Singletons or a Custom Container

  • svcs is a tiny, typed, well-maintained service locator — no metaclasses, no decorators, no framework coupling.
  • Factories are lazy: a service is constructed only when something asks for it.
  • Generic get[T](type[T]) -> T preserves types through IDE/type-checker inference.
  • Swapping an implementation in tests is a one-line factory override.
  • No import-order gymnastics: the registry is populated once at startup and then used by name.

The Registry — src/project/services.py

import svcs

from products.repositories.product import ProductRepository
from products.services.product import ProductService
from orders.repositories.order import OrderRepository
from orders.services.order import OrderService

registry = svcs.Registry()

# --- Repositories ---------------------------------------------------------
registry.register_factory(ProductRepository, ProductRepository)
registry.register_factory(OrderRepository, OrderRepository)

# --- Services (factories pull repos from the container) ------------------
def _product_service_factory(container: svcs.Container) -> ProductService:
    repo = container.get(ProductRepository)
    return ProductService(repo)

def _order_service_factory(container: svcs.Container) -> OrderService:
    repo = container.get(OrderRepository)
    product_repo = container.get(ProductRepository)
    return OrderService(repo, product_repo)

registry.register_factory(ProductService, _product_service_factory)
registry.register_factory(OrderService, _order_service_factory)

def get[T](service_type: type[T]) -> T:
    """Resolve a service from the registry. Works anywhere — views, tasks, commands, tests."""
    return svcs.Container(registry).get(service_type)

Patterns to follow:

  • Repositories register themselves. Use register_factory(Repo, Repo) — the class is its own factory because repositories take no constructor arguments.
  • Services register via a named factory. _<entity>_service_factory(container) resolves every dependency from the container and hands it to the service's __init__. No hidden imports, no module-level singletons.
  • Register in dependency order. Repos before services, lower-level services before higher-level ones. svcs doesn't enforce this, but it keeps the file readable.
  • One registry per project. Don't create ad-hoc registries — everything goes through project.services.registry.

Writing a Service

File: src/<app>/services/<entity>.py

from decimal import Decimal
from typing import List

from ..dtos.product import ProductDTO
from ..repositories.product import ProductRepository

class ProductService:
    def __init__(self, repo: ProductRepository):
        self.repo = repo

    def create_product(self, name: str, price: Decimal, stock: int) -> ProductDTO:
        return self.repo.create(name=name, price=price, stock=stock)

    def get_product(self, product_id: str) -> ProductDTO:
        return self.repo.get_by_id(product_id)

    def list_products(self) -> List[ProductDTO]:
        return self.repo.list_all()

Rules:

  • Dependencies come in through __init__. The service never instantiates its own repositories or services. If a service needs another service, pass it in.
  • Zero ORM. No .objects, no F() / Q(), no model imports, no select_related. All database access goes through a repository.
  • Every public method returns a DTO or list[DTO]. Never a model instance, never a queryset.
  • ID arguments are str. See the prefixed-ulids skill.
  • Business rules live here. Validation, orchestration across repositories, invariant checks, error raising — all of it.
  • Services are stateless. They hold references to their dependencies and nothing else. No caches, no counters, no module-level state.
  • Raise plain exceptions. Use ValueError, PermissionError, domain-specific exceptions — not Http404 or anything Django-flavored. The view layer turns them into HTTP responses.

Cross-Entity Logic

When a service method touches more than one aggregate — e.g. creating an order that decrements product stock — inject both repositories and orchestrate them. Example from OrderService:

class OrderService:
    def __init__(self, repo: OrderRepository, product_repo: ProductRepository):
        self.repo = repo
        self.product_repo = product_repo

    def create_order(self, items: List[Dict[str, Any]]) -> OrderDTO:
        for item in items:
            product = self.product_repo.get_by_id(item["product_id"])
            if product.stock < item["quantity"]:
                raise ValueError(
                    f"Insufficient stock for product {product.name}: "
                    f"requested {item['quantity']}, available {product.stock}"
                )

        order = self.repo.create(items=items)

        for item in items:
            self.product_repo.decrement_stock(item["product_id"], item["quantity"])

        return order

Notes:

  • The service orchestrates two repositories but touches zero ORM.
  • If a multi-repo write needs atomicity, wrap it in with transaction.atomic(): — that's one of the very few django.db imports allowed in a service.
  • Never call another service from inside a service unless that service is explicitly injected. No hidden get(...) calls inside service methods.

Resolving a Service

From a view (django-ninja)

from project.services import get
from project.types import AuthedRequest

@products_router.post("/", response={201: ProductDTO})
def create_product(request: AuthedRequest, payload: CreateProductIn):
    service = get(ProductService)
    return Status(201, service.create_product(**payload.dict()))

Annotating request as AuthedRequest (defined in src/project/types.py) makes the auth contract explicit and narrows request.user to a guaranteed-authenticated Django User. This is a typing contract, not runtime enforcement — auth is still expected to be wired via middleware or ninja's auth= parameter.

From a Celery task

from celery import shared_task

from project.services import get
from products.services.product import ProductService

@shared_task
def reprice_product(product_id: str, new_price: str) -> None:
    service = get(ProductService)
    service.update_price(product_id, Decimal(new_price))

From a management command

from django.core.management.base import BaseCommand

from project.services import get
from products.services.product import ProductService

class Command(BaseCommand):
    def handle(self, *args, **options):
        service = get(ProductService)
        for dto in service.list_products():
            self.stdout.write(dto.name)

The same get() call works in all three contexts because the registry is global and the container is cheap to construct.

Testing

Services are tested without a database. Pass in a MagicMock for each repository, configure its return values, and assert on the service's behavior.

from decimal import Decimal
from unittest.mock import MagicMock

import pytest

from products.dtos.product import ProductDTO
from products.services.product import ProductService

def test_create_product_delegates_to_repo():
    repo = MagicMock()
    expected = ProductDTO(id="prd_fake", name="Widget", price=Decimal("9.99"), stock=5)
    repo.create.return_value = expected

    service = ProductService(repo)
    result = service.create_product(name="Widget", price=Decimal("9.99"), stock=5)

    assert result is expected
    repo.create.assert_called_once_with(name="Widget", price=Decimal("9.99"), stock=5)

def test_create_order_rejects_insufficient_stock():
    order_repo = MagicMock()
    product_repo = MagicMock()
    product_repo.get_by_id.return_value = ProductDTO(
        id="prd_fake", name="Widget", price=Decimal("9.99"), stock=1
    )

    service = OrderService(order_repo, product_repo)

    with pytest.raises(ValueError, match="Insufficient stock"):
        service.create_order(items=[{"product_id": "prd_fake", "quantity": 5}])

    order_repo.create.assert_not_called()

This is the most important test layer — it proves the business logic is correct independently of Django, migrations, fixtures, or the database. If a service's tests need @pytest.mark.django_db, something has leaked: find the ORM call and push it back into a repository.

Overriding a Service in Tests

For integration tests that go through the API, override a factory to substitute a fake or a stub:

from project.services import registry
from products.services.product import ProductService

@pytest.fixture
def fake_product_service():
    fake = MagicMock(spec=ProductService)
    registry.register_factory(ProductService, lambda _: fake)
    yield fake
    # svcs re-registers on next call; reset to the real factory if other tests need it.

Common Mistakes

  • Importing models in a service. If you see from app.models import X, the service is doing ORM work. Move it to the repository.
  • Calling SomeRepository() inside a service method. Inject it via __init__ and hold the reference.
  • Returning querysets or model instances from a service. Always return DTOs.
  • Putting business logic in the view. The view should only decode input, call get(SomeService).method(...), and pass the result back.
  • Registering a service with register_factory(Service, Service). That only works for repositories because they take no arguments. Services need a factory that resolves their dependencies.
  • Reaching into request.user from the service. Pass the caller's identity as an explicit argument (user_id: str) so the service stays framework-agnostic.

Verify

  • Every service under src/<app>/services/ has an __init__ that takes its dependencies explicitly.
  • No file under src/<app>/services/ imports from django.db.models, <app>.models, or uses .objects.
  • Every service in the project is registered in src/project/services.py with a factory that resolves its dependencies from the container.
  • Service tests do not use @pytest.mark.django_db.
uv run ruff check src
uv run pyrefly check src
uv run pytest

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

34.69%
按下载量换算30

Claude

30.74%
按下载量换算27

Cursor

19.73%
按下载量换算17

Gemini CLI

10.13%
按下载量换算9

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills