Django 基类方法再优化

一、基于工厂方法

from typing import Type, TypeVar
from django.db.models import Model, QuerySet

T = TypeVar('T', bound=Model)

class BaseService:
    def __init__(self, model: Type[T]) -> None:
        self.model = model

    def create(self, **kwargs) -> T:
        return self.model.objects.create(**kwargs)

    # 其他方法...

class ServiceFactory:
    service_mapping = {}

    @classmethod
    def register(cls, model: Type[T], service: BaseService):
        cls.service_mapping[model] = service

    @classmethod
    def get_service(cls, model: Type[T]) -> BaseService:
        service = cls.service_mapping.get(model)
        if service is None:
            raise ValueError(f"No service found for model {model}")
        return service(model)

# 在UserService类中定义User模型特定的行为
class UserService(BaseService):
    # 重写或新增方法...

    def get_admin_users(self):
        return self.model.objects.filter(is_staff=True)

# 注册服务
ServiceFactory.register(User, UserService)

# 使用服务
user_service = ServiceFactory.get_service(User)
admin_users = user_service.get_admin_users()

二、静态方法改为实例方式

在需要访问实例属性的情况下,我们需要创建具体的服务对象。这种情况下,我们会将模型类作为实例属性存储,然后在实例方法中使用这个属性。以下是一个简单的示例:

from typing import Type, TypeVar
from django.db import models
from django.core.paginator import Paginator

T = TypeVar('T', bound=models.Model)

class BaseService:
    def __init__(self, model: Type[T]) -> None:
        self.model = model

    def create(self, **kwargs) -> T:
        return self.model.objects.create(**kwargs)

    def get(self, *args, **kwargs) -> T:
        return self.model.objects.get(*args, **kwargs)

    def filter(self, *args, **kwargs) -> models.QuerySet:
        return self.model.objects.filter(*args, **kwargs)

    def paginate(self, queryset: models.QuerySet, page: int, items_per_page: int):
        paginator = Paginator(queryset, items_per_page)
        return paginator.get_page(page)

现在,你可以创建特定模型的服务实例,并在该实例上调用方法:

from myapp.models import User

# 创建服务实例
user_service = BaseService(User)

# 使用服务实例创建用户
user = user_service.create(username='test', password='test')

# 获取用户
user = user_service.get(username='test')

# 过滤用户
users = user_service.filter(is_staff=True)

# 分页
page = user_service.paginate(users, 1, 10)

在这种设计中,你可以在子类中覆盖和扩展基类的方法,同时还可以访问实例属性。例如,你可以在 UserService 子类中添加一个方法,该方法返回所有管理员用户:

class UserService(BaseService):
    def get_admin_users(self) -> models.QuerySet:
        return self.filter(is_staff=True)

这种设计提供了很大的灵活性,允许你为每个模型定制特定的行为,同时保持了代码的清晰和模块化。

二、实例类

from typing import Type, TypeVar, Optional
from django.db import models, DatabaseError
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

T = TypeVar('T', bound=models.Model)

class BaseService:
    """
    面向 Django 模型的服务基类

    该类为给定的 Django 模型定义了常见操作,如:创建(create)、获取(get)、更新(update)、删除(delete)、
    过滤(filter)、列表(list)和分页(paginate)等。

    属性:
        model: 该服务操作的 Django 模型。
    """

    def __init__(self, model: Type[T]) -> None:
        """
         使用给定的模型初始化服务

        参数:
            model: Django 模型类
        """
        self.model = model

    def create(self, **kwargs) -> Optional[T]:
        """
        使用给定的 kwargs 创建模型的新实例

        Args:
            **kwargs: 用于新模型实例的属性字典。

        Returns:
            返回创建的新模型实例。
        """
        return self.model.objects.create(**kwargs)

    def get(self, *args, **kwargs) -> Optional[T]:
        """
        获取符合给定查找参数的模型的单个实例。

        参数:
            *args: Django 查询集 `.get()` 方法的位置参数。
            **kwargs: Django 查询集 `.get()` 方法的关键字参数。

        返回:
            符合给定查找参数的模型实例。

        异常:
            model.DoesNotExist: 如果没有实例匹配给定的查找参数。
            model.MultipleObjectsReturned: 如果多个实例匹配给定的查找参数。
        """
        return self.model.objects.get(*args, **kwargs)

    def update(self, obj: T, **kwargs) -> bool:
        """
        更新给定的模型实例。

        参数:
            obj: 需要更新的模型实例。
            kwargs: 用于更新模型实例的属性字典。

        返回:
            更新成功返回 True,否则返回 False。
        """
        try:
            for key, value in kwargs.items():
                setattr(obj, key, value)
            obj.save()
            return True
        except DatabaseError:
            # TODO::在这里可以记录日志,或者将错误抛出
            return False

    def filter(self, *args, **kwargs) -> models.QuerySet:
        """
        获取符合给定查找参数的模型实例的查询集。

        参数:
            args: Django 查询集 `.filter()` 方法的位置参数。
            kwargs: Django 查询集 `.filter()` 方法的关键字参数。

        返回:
            符合给定查找参数的模型实例的查询集。
        """
        return self.model.objects.filter(*args, **kwargs)

    def all(self, *args, **kwargs) -> models.QuerySet:
        """
        获取所有模型实例的查询集。

        参数:
            args: Django 查询集 `.all()` 方法的位置参数。
            kwargs: Django 查询集 `.all()` 方法的关键字参数。

        返回:
            所有模型实例的查询集。
        """
        return self.model.objects.all(*args, **kwargs)

    def delete(self, obj: T) -> bool:
        """
        删除给定的模型实例。

        参数:
            obj: 需要删除的模型实例。

        返回:
            删除成功返回 True,否则返回 False。
        """
        try:
            obj.delete()
            return True
        except DatabaseError:
            # 在这里可以记录日志,或者将错误抛出,根据实际项目需要决定
            return False

    def paginate(self, queryset: models.QuerySet, page: int, items_per_page: int) -> Optional[models.QuerySet]:
        """
        对查询集进行分页。

        参数:
            queryset: 需要进行分页的查询集。
            page: 需要获取的页码。
            items_per_page: 每页的项数。

        返回:
            分页后的查询集的对应页,如果分页失败则返回 None。
        """
        paginator = Paginator(queryset, items_per_page)
        try:
            return paginator.get_page(page)
        except (EmptyPage, PageNotAnInteger):
            # TODO::这里可以记录日志,或者将错误抛出,待处理
            return None

为者常成,行者常至