orm无关联连表操作
# models.py class User(models.Model): user = models.CharField(max_length=32) pwd = models.CharField(max_length=32) # 1)db_constraint=False:断开外键关联,数据库操作效率提高 # 2)避免脏数据的参数,要允许外键可为null # 3)on_delete=models.SET_NULL与2)协同在外键关联的数据删除掉会自动置空 user_detail = models.OneToOneField(to='UserDetail', null=True, on_delete=models.SET_NULL, db_constraint=False) class UserDetail(models.Model): phone_num = models.CharField(max_length=11) info = models.TextField() # views.py from app import models def test(request): # models.UserDetail.objects.filter(id=1).delete() user = models.User.objects.first() # type: models.User return HttpResponse(user.user_detail.phone_num)
连表序列化
# models.py class User(models.Model): user = models.CharField(max_length=32) pwd = models.CharField(max_length=32) user_detail = models.OneToOneField(to='UserDetail', null=True, on_delete=models.SET_NULL, db_constraint=False) # 在model中产生的全局空间名字,都可以被序列化 def account(self): return self.user + ":" + self.pwd class UserDetail(models.Model): phone_num = models.CharField(max_length=11) info = models.TextField()
序列化方式1
# app/objson.py (序列化层) class UserJson(serializers.Serializer): # 不序列化的字段不对外提供 # id = serializers.IntegerField() name = serializers.CharField(source='user') password = serializers.CharField(source='pwd') # 对指定的名字序列化(名字可以为普通对象、函数对象、类对象) account = serializers.CharField() # 在同一层产生数据 # user_phone = serializers.CharField(source='user_detail.phone_num') # user_info = serializers.CharField(source='user_detail.info') # 产生一个序列化的字段(detail) => 可以通过get_字段名(get_detail)完成ORM的连表操作,完成序列化 detail = serializers.SerializerMethodField() # 本质:改字段的值由方法提供 def get_detail(self, obj): # 该方法的命名规范必须是 get_字段名(self, obj) # obj就是序列化类的对象(models.User类的对象) # 对象就可以利用ORM完成连表操作 phone_num = obj.user_detail.phone_num info = obj.user_detail.info # 连表得到结果后自己封装对外的结果 return {'phone': phone_num, 'info': info}
序列化方式2
class UserDetailJson(serializers.Serializer): phone_num = serializers.CharField() info = serializers.CharField() class UserJson(serializers.Serializer): name = serializers.CharField(source='user') password = serializers.CharField(source='pwd') account = serializers.CharField() detail = serializers.SerializerMethodField() def get_detail(self, obj): # 拿到UserDetail类的连表对象 detail_obj = obj.user_detail # 完成序列化 detail_data = UserDetailJson(detail_obj).data # 返回序列化后的数据 return detail_data
基于Model的序列化
数据层:models.py
class Book(models.Model): name = models.CharField(max_length=20) price = models.DecimalField(max_digits=5, decimal_places=2) # 多对多存在第三张表,只需要断开关联即可 author = models.ManyToManyField(to='Author', db_constraint=False) class Author(models.Model): name = models.CharField(max_length=20) author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.SET_NULL, null=True, db_constraint=False) class AuthorDetail(models.Model): age = models.IntegerField() telephone = models.BigIntegerField() # objson.py
序列化层:objson.py
""" 1) 用Meta的model来绑定序列化的类 2) fields = '__all__': 序列化所有字段 3) fields = ['字段1', ..., '字段2']:指定序列化的字段 4) exclude = ['字段1', ..., '字段2']:排除序列化的字段 5) depth = 1:来表的深度 """
from app import models class AuthorDetailJson(serializers.ModelSerializer): class Meta: model = models.AuthorDetail exclude = ['id'] class AuthorJson(serializers.ModelSerializer): class Meta: model = models.Author # fields = '__all__' exclude = ['id'] # 如果名字是原来某字段的名字相同,会覆盖,否则就是新建:此处是覆盖 detail = serializers.SerializerMethodField() def get_detail(self, obj): detail_data = AuthorDetailJson(obj.author_detail).data return detail_data class BookJson(serializers.ModelSerializer): class Meta: model = models.Book # 1.对所有字段序列化 fields = '__all__' # 2.对指定字段序列化 # fields = ['id', 'name', 'price'] # 3.刨除指定字段序列化剩下的字段 # exclude = ['id'] # 4.连表操作的深度 # depth = 1 # 自定义深度 # 如果名字是原来某字段的名字相同,会覆盖,否则就是新建:此处是新建 authors = serializers.SerializerMethodField() def get_authors(self, obj): # 1.通过序列化方式 author_list = obj.author.all() author_data = AuthorJson(author_list, many=True).data return author_data # 2.通过手撸ORM查询,自定义封装返回字段 *****
视图层views.py
class Books(APIView): def get(self, request): book_list = models.Book.objects.all() book_data = objson.BookJson(book_list, many=True).data return Response({ 'status': 0, 'msg': 'ok', 'results': book_data })
路由层urls.py
url(r'^books/', views.Books.as_view()),
单条数据的增删改查
# 前提: # 1)序列化类中不能修改原字段的深度 # 2)通过 data=请求数据包 得到可以操作orm的序列化对象,instance来明确修改的对象,校验成功后还是走save()来更新 # 3)必须先校验,才能保存或更新 # 增 class Books(APIView): """ { "name":"水浒传", "price":"88.88", "author":[1, 2, 3 ] } """ def post(self, request): book_dic = request.data book_json = objson.BookJson(data=book_dic) # 数据的校验 if book_json.is_valid(): book_json.save() # 不涉及跨表操作 return Response({ 'status': 0, 'msg': 'ok', 'results': book_json.data }) # 查改删 class Book(APIView): def get(self, request, id): book_obj = models.Book.objects.filter(pk=id).first() book_data = objson.BookJson(book_obj).data return Response({ 'status': 0, 'msg': 'ok', 'results': book_data }) def put(self, request, id): book_obj = models.Book.objects.filter(pk=id).first() # instance来明确修改的对象,校验成功后还是走save()来保存 book_json = objson.BookJson(data=request.data, instance=book_obj) if book_json.is_valid(): book_json.save() return Response({ 'status': 0, 'msg': 'ok', 'results': book_json.data }) def delete(self, request, id): models.Book.objects.filter(pk=id).delete() return Response({ 'status': 2, 'msg': 'delete success', })
数据的校验
# views.py class Books(APIView): def post(self, request): book_dic = request.data book_json = objson.BookJson(data=book_dic) # 数据的校验 if book_json.is_valid(): # book_json.save() # 不涉及跨表操作 return Response({ 'status': 0, 'msg': 'ok', 'results': book_json.data }) return Response({ 'status': 0, 'msg': book_json.errors, }) # objson.py class BookJson(serializers.ModelSerializer): class Meta: model = models.Book fields = '__all__' # 认证 name = serializers.CharField( max_length=5, min_length=1, error_messages={ "max_length": "太长了", "min_length": "太短了", } ) # 局部钩子 def validate_name(self, value): from rest_framework.exceptions import ValidationError if 'sb' in value: raise ValidationError("出现了敏感词汇") return value # def validate_price(self, value): # from rest_framework.exceptions import ValidationError # if float(value) < 0: # raise ValidationError("价格不合理") # return # 了解:如果多个字段直接协同校验,采用全局钩子 def validate(self, attrs): from rest_framework.exceptions import ValidationError pwd = attrs.get('pwd') re_pwd = attrs.get('re_pwd') if pwd == re_pwd: return attrs else: raise ValidationError('密码校验失败')
跨域问题
# 跨越:当有下列三种情况是,ajax请求数据,获得非本服务器本应用的数据完成自身的局部刷新,很可能不被请求的服务器的应用提供数据,该种情况就称之为 跨越问题 (CORS) ''' 1.协议不同:http 与 https间进行交互 2.端口不同:不同端口代表不同应用,直接进行交互 3.ip不同:ip地址不同,代表主机不同,不同服务器进行交互 ''' # 解决跨越 ''' 安装django-cors-headers模块 在settings.py中配置 # 注册app INSTALLED_APPS = [ ... 'corsheaders' ] # 添加中间件 MIDDLEWARE = [ ... 'corsheaders.middleware.CorsMiddleware' ] # 允许跨域源 CORS_ORIGIN_ALLOW_ALL = True '''
认证源码流程
""" 1.views.Books.as_view() 2.view = super(APIView, cls).as_view(**initkwargs) 分发给dispatch 3.def dispatch(self, request, *args, **kwargs): 4. request = self.initialize_request(request, *args, **kwargs) 封装request self.initial(request, *args, **kwargs) 三大认证 5.self.perform_authentication(request) 转向Request类的user 6.request.py的Request的user self._authenticate() 7.self.authenticators self是drf的request对象 8.drf的request对象的init方法 authenticators是初始化参数 9.在哪初始化的: request = def initialize_request(self, request, *args, **kwargs) 10.self.get_authenticators() 需要 self.authentication_classes 11.self代表APIView类或子类对象,在自定义Books(APIView)中提供 """ class Auth: def authenticate(self, request): print(request) # 完成具体认证功能,拿到的就是drf的request对象,对其内容做认证 # eg:登录认证,就是判断request中的数据是否有token,并做token校验 pass class Books(APIView): authentication_classes = [Auth, ] # 请求的业务处理,都要晚于authenticate的执行