为了账号安全,请及时绑定邮箱和手机立即绑定

Python/Django的设计原则

在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 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消