drf序列化器中的read_only和write_only选项
- 参考网址
https://www.cnblogs.com/jx-zzc/p/16522675.html
-
read_only: 表示只读,不能进行修改,也不会存入db(校验过后)
- 使用场景: id 字段
-
write_only: 只能写,不能读,可以存入db,但是返回响应时,不会包含此字段
- 使用场景: password_repeat 字段/sms_code
class RegisterSerializer(serializers.ModelSerializer):
password2 = serializers.CharField(write_only=True, label='重复密码')
sms_code = serializers.CharField(write_only=True, label='短信验证码')
allow = serializers.CharField(write_only=True, label='是否同意协议')
......
Redis配置
- 安装django-redis,并配置
# settings
......
# ------------redis配置:拆分为0/1 号数据库------------------#
CACHES = {
"default": { # 保存 省市区数据
"BACKEND": "django_redis.cache.RedisCache",
# 使用0号数据库
"LOCATION": "redis://192.168.11.38:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
"max_connections": 1000,
"encoding": 'utf-8'
},
# "PASSWORD": "foobared" # redis密码
}
},
"session": { # 保存session数据
"BACKEND": "django_redis.cache.RedisCache",
# 使用1号数据库
"LOCATION": "redis://192.168.11.38:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
"max_connections": 1000,
"encoding": 'utf-8'
},
# "PASSWORD": "foobared" # redis密码
}
},
"verify_codes": { # 保存验证码
"BACKEND": "django_redis.cache.RedisCache",
# 使用2号数据库
"LOCATION": "redis://192.168.11.38:6379/2",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {
"max_connections": 1000,
"encoding": 'utf-8'
},
# "PASSWORD": "foobared" # redis密码
}
},
}
SESSION_ENGINE = "django.contrib.sessions.backends.cache"
SESSION_CACHE_ALIAS = 'session'
.....
'''
- 除了名为default的redis配置外,还补充了其他配置,例如名为session的redis配置,分别使用两个不同的redis库
- 同时修改了Django的Session机制使用redis保存,且使用名为'session'的redis配置
- 此处修改Django的Session机制存储主要是为了给Admin站点使用
- 关于django-redis 的使用,说明文档可见http://django-redis-chs.readthedocs.io/zh_CN/latest/
'''
# views demo演示
import logging
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import status
from django_redis import get_redis_connection
class TestView(APIView):
def get(self,request,*args,**kwargs):
### 搭配 redis 管道和celery异步
# redis_conn = get_redis_connection('default')
# logger.info(sms_code)
# pl = redis_conn.pipeline()
# pl.set(mobile, sms_code, ex=60) # 保存验证码
# pl.set('sms_flag_{}'.format(mobile), 200, ex=60) # 保存发送短信标志
# pl.execute()
# send_sms_code.delay(mobile, sms_code) # 异步耗时任务
### 基础demo
redis_conn = get_redis_connection('default')
mobile = 18106951913
code = 8888
redis_conn.set(mobile,code,ex=60)
return Response({'msg':'redis保存成功'},status=status.HTTP_200_OK)
日志
# settings
......
LOGGING = {
'version': 1,
'disable_existing_loggers': False, # 是否禁用已经存在的日志器
'formatters': { # 日志信息显示的格式
'verbose': {
'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s'
},
'simple': {
'format': '%(levelname)s %(module)s %(lineno)d %(message)s'
},
},
'filters': { # 对日志进行过滤
'require_debug_true': { # django在debug模式下才输出日志
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': { # 日志处理方法
'console': { # 向终端中输出日志
'level': 'INFO',
'filters': ['require_debug_true'],
'class': 'logging.StreamHandler',
'formatter': 'simple'
},
'file': { # 向文件中输出日志
'level': 'INFO',
'class': 'logging.handlers.RotatingFileHandler',
# 'filename': os.path.join(BASE_DIR, 'logs/meiduo.log'), # 日志文件的位置
# 'filename': os.path.join(os.path.dirname(BASE_DIR), 'logs\\meiduo.log'), # 日志文件的位置和manage.py同级
'filename': os.path.join(BASE_DIR, 'logs\\meiduo.log'), # 日志文件的位置和manage.py同级
'maxBytes': 300 * 1024 * 1024,
'backupCount': 10,
'formatter': 'verbose'
},
},
'loggers': { # 日志器
'django': { # 定义了一个名为django的日志器
'handlers': ['console', 'file'], # 可以同时向终端与文件中输出日志
'propagate': True, # 是否继续传递日志信息
'level': 'INFO', # 日志器接收的最低日志级别
},
}
}
向DRF补充异常
- 修改Django REST framework的默认异常处理方法,补充处理数据库异常和Redis异常
### exceptions.py
from rest_framework.views import exception_handler as drf_exception_handler
import logging
from django.db import DatabaseError
from redis.exceptions import RedisError
from rest_framework.response import Response
from rest_framework import status
# 获取在配置文件中定义的logger,用来记录日志
logger = logging.getLogger('django')
def exception_handler(exc, context):
"""
自定义异常处理
:param exc: 异常
:param context: 抛出异常的上下文
:return: Response响应对象
"""
# 调用drf框架原生的异常处理方法
response = drf_exception_handler(exc, context)
if response is None:
view = context['view']
if isinstance(exc, DatabaseError) or isinstance(exc, RedisError):
# 数据库异常
logger.error('[%s] %s' % (view, exc))
response = Response({'message': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
return response
### settings
REST_FRAMEWORK = {
# 异常处理
'EXCEPTION_HANDLER': 'meiduo_mall.utils.exceptions.exception_handler',
}
Source参数的功能
- 参考网址
https://zhuanlan.zhihu.com/p/274507545
- 修改返回到前端的字段名
- 在序列化器参数字段参数设置(source='表模型字段名')
- 修改后的名字不能同字段名一样
### serializer.py
from rest_framework import serializers
from rest_framework.exceptions import ValidationError
from app01 import models
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False, )
res_title = serializers.CharField(max_length=32, min_length=2,source='title') # 修改字段名称
price = serializers.DecimalField(max_digits=6, decimal_places=2)
### models.py
from django.db import models
class Publish_dateils(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=32)
addr = models.CharField(max_length=128)
phone = models.IntegerField(max_length=16)
emali = models.EmailField()
class Book(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=6,decimal_places=2)
# 外键支持
publish = models.ForeignKey(to=Publish_dateils,on_delete=models.CASCADE)
-
如果表模型中有方法,会执行方法,并且把返回值赋值给新变量名
作用: 可以自定义模型方法,修改原字段的值,并响应
### models.py
class Book(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=32)
price = models.DecimalField(max_digits=6,decimal_places=2)
publish = models.ForeignKey(to=Publish_dateils,on_delete=models.CASCADE)
def tesc(self): # 表模型没有这个字段,只是一个方法,重写了title的值
self.res_title = '我被表模型方法改变了'
return self.res_title
### serializers
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False, )
res_title = serializers.CharField(max_length=32, min_length=2, source='tesc') # 这里指向表模型的方法
price = serializers.DecimalField(max_digits=6, decimal_places=2)
- source支持跨表操作
### serializers
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(required=False, )
res_title = serializers.CharField(max_length=32, min_length=2, source='tesc')
price = serializers.DecimalField(max_digits=6, decimal_places=2,)
res_sum = serializers.CharField(source='sum')
# 跨表操作
publish_name = serializers.CharField(source='publish.name')
publish_addr = serializers.CharField(source='publish.addr')
DRF create()
方法返回值解析
- 源码是把数据进行保存以后,序列化返回保存后的数据
# 源码
class CreateModelMixin:
"""
Create a model instance.
"""
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
def perform_create(self, serializer):
serializer.save()
def get_success_headers(self, data):
......
- 实战中,数据保存在哪里,比如
mysql
或者redis
,都是有开发者自己决定 - 该方法返回什么类型的数据,也是由开发者自己决定,这个方法不像
validate_field
强制要求返回value
create()
方法的返回值,就是序列化后的数据
# 注册类
def create(self, validated_data):
......
return user # 返回 用户对象
DRF项目之序列化器和视图重写方法的区别
- 参考网址
https://www.cnblogs.com/chao666/p/12318467.html
- 在视图中重写方法: 接收请求,处理数据(业务逻辑),最后响应JSON数据
- 在序列化器中重写方法: 实现和Model的交互,主要实现对数据库的操作
- 结论
- 如果逻辑是注重与model的交互,就把逻辑放在serilizer;注重响应的数据,就把逻辑放到'视图'
ModelViewSet 实现增
,删
,改
,查
### urls
from django.conf.urls import url
from rest_framework.routers import DefaultRouter
from . import views
urlpatterns = [
......
]
router = DefaultRouter()
......
# 快速完成 增/删/改/查
router.register(r'goods',views.GoodsModelViewSet,basename='goods')
urlpatterns += router.urls
### views
class GoodsModelViewSet(ModelViewSet):
queryset = Goods.objects.get_queryset()
# '增'和'查'需指定不同的序列化器
def get_serializer_class(self):
if self.action == 'create':
return GoodsCreateModelSerilizer
return GoodsModelSerilizer
### serializers
class GoodsModelSerilizer(serializers.ModelSerializer):
class Meta:
model = Goods
fields = '__all__' # depth = 1 新增的时候,序列化器不会收到'外键字段','__all__'就不会包含外键字段
depth = 1
# 新增
class GoodsCreateModelSerilizer(serializers.ModelSerializer):
class Meta:
model = Goods
fields = '__all__'
- 删(是'物理删除',如果换成'逻辑删除'就要重写'delete')和改的逻辑默认即可