在Python中,设计原则和其他编程语言一样,有助于创建干净、可维护和高效的代码。这里有一些关键的设计原则以及一些示例:
1. DRY (不要重复)要是你喜欢这个,請给我买杯咖啡咖啡! ☕❤️
通过将重复的代码模式抽象出函数或类来避免代码重复。
Django 通过它的 ORM(对象关系映射)、表单和管理界面内在地遵循了 DRY 原则。
使用序列化器的例子一下相比于单独写验证逻辑,DRF 序列化类允许你直接在序列化类中封装这些逻辑。
# serializers.py
from rest_framework import serializers
from .models import 费用, 分类, 余额
class 费用序列化器(serializers.ModelSerializer):
class Meta:
model = 费用
fields = ['id', '用户', '分类', '金额', '描述', '日期']
class 分类序列化器(serializers.ModelSerializer):
class Meta:
model = 分类
fields = ['id', '名称', '描述', '用户']
class 余额序列化器(serializers.ModelSerializer):
class Meta:
model = 余额
fields = ['id', '总余额']
2. K.I.S.S. (保持简单,不要愚蠢)
尽量让你的代码保持简单,避免不必要的复杂。
Django的设计理念侧重简洁明了和易于阅读。
使用Django REST框架的通用视图示例与其编写复杂的视图逻辑,你可以使用 DRF 的通用视图来处理创建、获取和列出对象等常见操作,等。
# views.py
from rest_framework import generics
from .models import 支出, 分类, 余额
from .serializers import 支出序列化器, 分类序列化器, 余额序列化器
class 支出列表视图(generics.ListCreateAPIView):
queryset = 支出.objects.all()
serializer_class = 支出序列化器
class 支出详情视图(generics.RetrieveUpdateDestroyAPIView):
queryset = 支出.objects.all()
serializer_class = 支出序列化器
class 分类列表视图(generics.ListCreateAPIView):
queryset = 分类.objects.all()
serializer_class = 分类序列化器
class 分类详情视图(generics.RetrieveUpdateDestroyAPIView):
queryset = 分类.objects.all()
serializer_class = 分类序列化器
class 余额列表视图(generics.ListCreateAPIView):
queryset = 余额.objects.all()
serializer_class = 余额序列化器
3. YAGNI(你可能用不到它)
不要提前添加不必要的功能。
专注于现在的需求,而不是未来的可能。
示例:简单用户资料先从简单的用户模型入手,只在确实需要的时候再增加复杂性。
# 用户模型定义
# models.py
class User(AbstractUser):
# 名字字段
first_name = models.CharField(max_length=30)
# 姓字段
last_name = models.CharField(max_length=30)
# 唯一电子邮件字段
email = models.EmailField(unique=True)
# 返回用户名
def __str__(self):
return self.username
4. 关注点分离
代码的不同部分应该承担不同的职责。
Django的MVC架构将数据模型、视图层和模板层分离。
示例:分离业务逻辑和视图将业务逻辑放在模型或服务中,而不是放在视图中。
# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class AbstractModel(models.Model):
class Meta:
abstract = True
deleted = models.BooleanField(default=False)
date_created = models.DateTimeField('创建日期', auto_now_add=True)
date_last_updated = models.DateTimeField('最后更新日期', auto_now=True)
def __int__(self) -> int:
return self.id
def delete(self, *args, **kwargs):
self.deleted = True
self.save()
def hard_delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
....
# 视图.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import generics
from django.shortcuts import get_object_or_404
from .models import Expense, Category, Balance, User
from .serializers import ExpenseSerializer, CategorySerializer, BalanceSerializer
class ExpenseListView(generics.ListCreateAPIView):
queryset = Expense.objects.all()
serializer_class = ExpenseSerializer
class ExpenseDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Expense.objects.all()
serializer_class = ExpenseSerializer
class CategoryListView(generics.ListCreateAPIView):
queryset = Category.objects.all()
serializer_class = CategorySerializer
class CategoryDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Category.objects.all()
serializer_class = CategorySerializer
class BalanceListView(generics.ListCreateAPIView):
queryset = Balance.objects.all()
serializer_class = BalanceSerializer
class UserTotalExpensesView(APIView):
def get(self, request, user_id):
user = get_object_or_404(User, id=user_id)
total_expenses = user.get_total_expenses()
return Response({'total_expenses': total_expenses})
# URL.py
from django.urls import path
from .views import ExpenseListView, ExpenseDetailView, CategoryListView, CategoryDetailView, BalanceListView, UserTotalExpensesView
urlpatterns = [
path('expenses/', ExpenseListView.as_view(), name='expense-list'), # 费用列表
path('expenses/<int:pk>/', ExpenseDetailView.as_view(), name='expense-detail'), # 费用详情,pk 是主键
path('categories/', CategoryListView.as_view(), name='category-list'), # 分类列表
path('categories/<int:pk>/', CategoryDetailView.as_view(), name='category-detail'), # 分类详情,pk 是主键
path('balances/', BalanceListView.as_view(), name='balance-list'), # 账户余额列表
path('users/<int:user_id>/total-expenses/', UserTotalExpensesView.as_view(), name='user-total-expenses'), # 用户总费用,user_id 是用户ID
]
5. SOLID
SOLID 是五个设计原则的首字母缩略词,目的是为了让软件设计更加易于理解、灵活和维护。
S: 单一职责原则(SRP)每个类应该只负责一件事。
# model/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class AbstractModel(models.Model):
class Meta:
abstract = True
deleted = models.BooleanField(default=False)
date_created = models.DateTimeField('创建日期', auto_now_add=True)
date_last_updated = models.DateTimeField('最后更新时间', auto_now=True)
def get_id(self) -> int:
return self.id
def delete(self, *args, **kwargs):
self.deleted = True
self.save()
def hard_delete(self, *args, **kwargs):
super().delete(*args, **kwargs)
class User(AbstractUser):
first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30)
email = models.EmailField(unique=True)
def __str__(self):
return self.username
class Category(AbstractModel):
class Meta:
verbose_name = "类别名称"
verbose_name_plural = "类别名称"
db_table = "db_category"
name = models.CharField('名称', max_length=100, unique=True)
description = models.TextField()
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return self.name
class Expense(AbstractModel):
class Meta:
verbose_name = "支出项"
verbose_name_plural = "支出项"
db_table = "db_expense"
user = models.ForeignKey(User, on_delete=models.CASCADE)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
amount = models.DecimalField(max_digits=10, decimal_places=2)
description = models.TextField()
date = models.DateField()
class Balance(models.Model):
class Meta:
verbose_name = "余额记录"
verbose_name_plural = "余额记录"
db_table = "db_balance"
total_balance = models.DecimalField(max_digits=10, decimal_places=2)
O: 开闭性原则:(OCP)
软件组件应该易于扩展但不可修改。
# 中间件.py
from django.http import HttpResponse
class BaseMiddleware:
def process_request(self, request):
raise NotImplementedError
class AuthMiddleware(BaseMiddleware):
def process_request(self, request):
# 如果请求的用户未经过验证:
if not request.user.is_authenticated:
return HttpResponse('未经授权', status=401) # 返回401未授权状态码
L: Liskov 替换原则 (LSP)
超类的对象可以被子类的对象所替代而不影响程序的正确运行。
# models.py
class 通知:
def 发送(self):
raise NotImplementedError
class EmailNotification(通知):
def 发送(self):
print("发送电子邮件")
class SMSNotification(通知):
def 发送(self):
print("发送短信")
def 通知(通知: 通知):
通知.发送()
# 使用示例
email_notification = EmailNotification()
sms_notification = SMSNotification()
通知(email_notification) # 输出: 发送电子邮件
通知(sms_notification) # 输出: 发送短信
界面隔离原则:
用户不应该被强迫依赖于他们不用的接口。
# 接口隔离通过分割较大的视图来实现
from django.views import View
from django.http import JsonResponse
class CreateMixin:
def create(self, request, *args, **kwargs):
return JsonResponse({'message': '创建未实现'}, status=405)
class ReadMixin:
def read(self, request, *args, **kwargs):
return JsonResponse({'message': '读取未实现'}, status=405)
class UpdateMixin:
def update(self, request, *args, **kwargs):
return JsonResponse({'message': '更新未实现'}, status=405)
class DeleteMixin:
def delete(self, request, *args, **kwargs):
return JsonResponse({'message': '删除未实现'}, status=405)
class MyView(CreateMixin, ReadMixin, View):
def read(self, request, *args, **kwargs):
return JsonResponse({'message': '读取数据已完成'})
D: 依赖倒转原则 (DIP,即上层模块不依赖于下层模块)
一般来说,高层模块不应依赖底层模块,两者都应依赖抽象。
class PaymentService:
def process_payment(self):
raise NotImplementedError
class StripePaymentService(PaymentService):
def process_payment(self):
print("正在使用Stripe处理支付")
class PayPalPaymentService(PaymentService):
def process_payment(self):
print("正在使用PayPal处理支付")
# views.py
from .services import PaymentService
class PaymentView(View):
def __init__(self, payment_service: PaymentService):
self.payment_service = payment_service
def post(self, request, *args, **kwargs):
self.payment_service.process_payment()
return JsonResponse({'message': '支付已完成'})
# 用法
stripe_service = StripePaymentService()
paypal_service = PayPalPaymentService()
stripe_payment_view = PaymentView(stripe_service)
paypal_payment_view = PaymentView(paypal_service)
如果你觉得这篇文章有用,别忘了与你的朋友和同事分享! luder 欢迎在下面留言分享你的想法或问题 💬,如果这篇文章让你喜欢,也请给它点个赞! 👍😊
如果你喜欢这个,可以买我一杯咖啡咖啡! ☕💖
点击查看更多内容
为 TA 点赞
评论
共同学习,写下你的评论
评论加载中...
作者其他优质文章
正在加载中
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦