Django+DRF+PostgreSQL+Redis+Celery 后端开发日志
组件介绍
Django
python开发常用的框架有很多,这里推荐两种
- Flask:用于快速开发,比如接受其他平台发送的请求
- Django:用于大型项目的开发,有较为完整的功能,如分页、权限等
本文选择的版本是长期稳定更新的4.2
DRF
这是一个用于前后端分离的组件
目前没有中文文档,并且社区热度一般,如果没有web开发基础建议去学Flask
本文选择的是较新版本3.14.0
PostgreSQL
一个分布式开源的关系型数据库,相较于MySQL在django中支持的字段会更丰富,能够存储Json、list等数据
本文选择的是Docker下的最新版
Redis
非关系型数据库,用于缓存及Celery中的 BROKER配置
windows下安装最新版即可
Celery
用于异步任务、定时任务的组件,本文涉及异步爬虫和开放平台AP调用所有选型了Python作为开发语言
本文选用最新版 5.3.6
开发思路
就像Java 的Spring Boot框架的软件设计模式是MVC(Model View Controller),
在我实际的开发过程中 我也总结出了一种类似的模式 MSFVU(Model Serializer Filter ViewSet Url),这个过程可以大致的表述从数据在前后端的流动过程。
Model
即模型,笼统的说就是一个抽象的类,它拥有属性、方法,在实际开发中常常会和持久化联系密切。
class Category(models.Model):
id = models.AutoField(verbose_name='类目id', primary_key=True)
categoryQuery = models.CharField(max_length=50, verbose_name='查询类目')
categoryMatching = models.CharField(max_length=50, verbose_name='匹配类目')
class Meta:
db_table = 'category'
verbose_name = '类目表'
verbose_name_plural = verbose_name
# 特别情况-父子关系
class Account(MPTTModel):
account_type_choices = (
(0, '总账户'),
(1, '子账户'),
)
id = models.AutoField(primary_key=True)
account_type = models.CharField(choices=account_type_choices, max_length=50,
verbose_name='类型(总账户/子账户)', db_column='account_type')
account_name = models.CharField(max_length=128, verbose_name='账户名称', db_column='account_name',
null=True, blank=True)
account_password = models.CharField(max_length=128, verbose_name='账户密码', db_column='account_password')
account_status = models.BooleanField(default=True, verbose_name="账户状态(启用/禁用)", db_column='account_status')
parent = TreeForeignKey('self', on_delete=models.CASCADE, null=True, blank=True,
related_name='child_accounts', verbose_name='所属总账户', db_column='parent')
objects = TreeQuerySet.as_manager()
class MPTTMeta:
order_insertion_by = ['id']
class Meta:
db_table = 'account'
verbose_name = '账户表'
verbose_name_plural = verbose_name
Serializer
序列化器,就是能将机器编码和人类语言相互转换的中间件,可以完成Java中DTO、VO的功能。这里需要掌握的是什么是序列化,什么是反序列化。
将对象的状态转换为适合存储、传输或展现(如JSON、XML或二进制格式)的数据格式,这个过程被称为序列化。反之,从这样的数据格式还原成对象状态的过程称为反序列化。
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = '__all__'
# 特别情况-父子关系
class AccountSerializer(serializers.ModelSerializer):
account_type_choices = (
(0, '总账户'),
(1, '子账户'),
)
account_type = serializers.ChoiceField(choices=account_type_choices, label='类型(总账户/子账户)')
children = serializers.SerializerMethodField()
def get_children(self, obj):
return self.__class__(obj.get_children(), many=True).data
class Meta:
model = Account
exclude = ['token']
Filter
过滤器,django自带的也有,但是功能不够丰富,drf官方推荐引入组件django-filter,本文选用的版本是23.5,主要是实现时间的区间查询、模糊查询等。
class CategoryFilter(filters.FilterSet):
class Meta:
model = Category
fields = '__all__'
# 模糊查询
class AccountFilter(filters.FilterSet):
account_username = filters.CharFilter(lookup_expr='icontains')
# 如果使用特殊字段类型的如Array、JSON等记得要配置,不然报错
class Meta:
model = Account
fields = '__all__'
filter_overrides = {
JSONField: {
'filter_class': django_filters.CharFilter,
'extra': lambda f: {
'lookup_expr': 'icontains',
},
},
}
# 区间查询
class DjangoCeleryResultsTaskresultFilter(filters.FilterSet):
startTime = django_filters.DateTimeFilter(field_name='date_created__date', lookup_expr='gte')
endTime = django_filters.DateTimeFilter(field_name='date_created__date', lookup_expr='lte')
class Meta:
model = DjangoCeleryResultsTaskresult
fields = '__all__' # 或者指定具体的字段列表
ViewSet
视图集,drf的view层有三种写法,基于方法的视图、基于类的视图、基于视图集。在实际开发中我会以第三种为主,另外两种作为补充。为了更好的集成drf-yasg 我继承并重写了ModelViewSet这个我的utils包下有。
class CategoryViewSet(CustomModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
filterset_class = CategoryFilter
Url
用于向前端暴露接口的,可以分App写,然后在setting同级的url中组合。
如果使用ViewSet则需要用
router = DefaultRouter()
router.register(r'<路径>', <ViewSet>)
core_urls = router.urls
例如:
router.register(r'category', CategoryViewSet)
本文持续更新