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
为者常成,行者常至
自由转载-非商用-非衍生-保持署名(创意共享3.0许可证)