day67
函数与方法的区别
# 函数 def test(a, b): print(a, b) print('我是函数') # 有几个参数就要传几个参数 # test(1, 2) # 方法 class Person(object): # 没有任何装饰器装饰,绑定给对象的方法 # 特殊之处:对象来调用,会自动传值,将对象自己作为第一个参数传进来 def print_name(self): print(self.name) # 绑定给类的方法 # 特殊之处:类来调用,会自动传值,将类自己作为第一个参数传进来 @classmethod def test(cls): print(cls) print('我是类方法') # 静态方法,有几个值传几个值(类可以来调,对象也可以来调) @staticmethod def test1(): print('我是静态方法') # 绑定给对象的方法和静态的方法 # p = Person() # p.name = 'yzq' # p.print_name() # p.test1() # 绑定给类的方法和静态方法 # Person.test() # Person.test1() # 绑定给类的方法对象也可以来调用,会自动把类传入 # p = Person() # p.test() # 绑定给对象的方法,类可以来调,但是方法就变成了普通函数,有几个值(对象),就传几个值 p = Person() p.name = 'yzq' Person.print_name(p) """ 总结: 1、函数是有几个参数传几个参数 2、方法会自动传值 3、方法得看是谁来调用,如果是对象的方法,而类来调,就变成了普通函数 扩展知识: 1、PEP8的规范:在PyCharm编写代码时代码下方会有波浪线,它是由于pycharm内部的PEP8规范不影响代码的运行 2、定义类时没有继承,类名后面的括号可以省略不写,也可以写上(object),不影响 3、python中对于函数以及变量名的命名推荐使用字母加下划线的方式命名,只是推荐(java与go推荐使用驼峰来命名) 4、在给对象绑定方法与给类绑定方法是系统会默认给我们添加一个self/cls形参,这里的self/cls只是表示形参,我们可以随便命名不一定非要是self/cls """
0 什么是函数,什么是方法?
1 cbv源码分析
-IndexView.as_view()---》执行完后,返回View类中as_view()类方法,它执行完会返回一个内层函数view----》内层函数view中执行了self.dispatch()--->View类的dispatch---》代码执行流程:根据用户不同的请求方式去视图类中找到相应的方法,然后执行
2 drf的APIView的执行流程
-APIView中的as_view代码
view = super().as_view(**initkwargs)
return csrf_exempt(view)
-view内部本质执行了self.dispatch()
-执行了APIView的dispatch
-request = self.initialize_request(request, *args, **kwargs)
-self.initial(request, *args, **kwargs)
-处理了异常(包含三大认证和视图类中的方法)
3 drf的Request类的对象
-只要继承了APIView,后续的视图类中使用的request对象,都是drf的Request类的对象
-但是用起来,跟之前django的一样
-多了个request.data,post和put提交的数据,都会在里面,字典形式
-urlencoded编码---》request.data是QueryDict的对象
-formdata编码---》request.data是QueryDict的对象
-json编码---》request.data是dict
-多了:request.query_params---》它就是原来的request.GET
-self._request.GET
今日内容
1 序列化类之Serializer()
1.1 序列化类常用字段
# 重点的:
'''
CharField
IntegerField
DecimalField
DateTimeField
DateField
ListField
DictField
'''
# 其他还有很多但的忽略
## 通用的
read_only 表明该字段仅用于序列化输出,默认False(重点)
write_only 表明该字段仅用于反序列化输入,默认False(重点)
required 表明该字段在反序列化时必须输入,默认True(了解)
default 反序列化时使用的默认值(了解)
allow_null 表明该字段是否允许传入None,默认False(了解)
validators 该字段使用的验证器(写函数的列表,使用这些函数校验该字段)(了解)
error_messages 包含错误编号与错误信息的字典
## 其他的
## CharField
max_length 最大长度
min_lenght 最小长度
allow_blank 是否允许为空
trim_whitespace 是否截断空白字符
# IntegerField
max_value 最小值
min_value 最大值
1.3 反序列化(重写create和update)
# 重点:
-如果想序列化和反序列化都用一个序列化类,可以使用如下俩字段控制
-read_only 表明该字段仅用于序列化输出,默认False(重点)
-write_only 表明该字段仅用于反序列化输入,默认False(重点)
-如果写起来比较麻烦,可以使用两个序列化类,一个序列化,一个反序列化
# source的用法
name1 = serializers.CharField(source='name')--->意思是name1映射成models中的name
# 如果继承Serializer类,要修改和保存,一定要重写update和create
BookSerializer---》Serializer---》BaseSerializer--save的核心代码
if self.instance is not None:
self.instance = self.update(self.instance, validated_data)
else:
self.instance = self.create(validated_data)
#
1.4 SerializerMethodField的使用
class BookSerializer(serializers.Serializer):
price = serializers.IntegerField()
name = serializers.CharField()
# publish = serializers.CharField()
# 显示出版社的详情
## 方式一(在序列化类中写)
# publish_name = serializers.SerializerMethodField(read_only=True) # 只能用来做序列化
# def get_publish_name(self,obj):
# # obj 就是当前要序列化的book对象
# # return obj.publish.name
# return {'name':obj.publish.name,'addr':obj.publish.addr}
# 方式二(在模型类中写方法,方法返回什么,这个字段就是什么)(在表模型中写用的多)
# publish_detail=serializers.CharField()
# publish_detail=serializers.DictField()
## 方式三
publish_detail = serializers.CharField(source='publish.addr')
2 序列化类之ModelSerializer(*****)
from .models import Book, Publish
# class PublishModelSerializer(serializers.ModelSerializer):
# # 指定跟表的对应关系
# class Meta:
# model = Publish # 跟哪个表有关系
# # fields =['name','addr']
# # fields ='__all__' # 所有字段,只序列化字段,不序列化方法
# fields = ['name', 'addr', 'name_detail']
# # 给字段类,传递参数、属性
# extra_kwargs={
# 'addr':{'max_length':8,'min_length':3,'write_only':True},
# # 'name':{'write_only':True}
# }
# # 不重要的
# # exclude=['name'] # 它跟fields 只能由一个
# # depth=1
#
#
# #1 不用重写create和update
#
# #2 在出版社名字后加 _vip
# # 方式一
# # name=serializers.SerializerMethodField()
# # def get_name(self,obj):
# # return obj.name+'_vip'
#
# # 方式二,在表模型中定义一个name_detail,在fields中写一些字段或方法
#
# ## 序列化的时候使用name_detail,反序列化的时候使用name
# # name_detail = serializers.CharField(read_only=True) 如果是个方法,这句可以不写
# name = serializers.CharField(write_only=True)
#
#
#
# #3 限制addr,最大长度8,最小长度3
3 序列化类全局,局部钩子(*****)
# 局部钩子:给某个字段再增加校验(固定用法),定义一个方法,名字为validate_字段名
def validate_addr(self, item):
if item.startswith('sb'):
# 抛异常,不能以sb开头
raise ValidationError('不能以sb开头')
else:
return item
# 全局钩子
# 限制出版社的名字不能等于出版社地址
def validate(self, attrs):
name = attrs.get('name')
addr = attrs.get('addr')
if name == addr:
raise ValidationError('name和addr不能一样')
else:
return attrs
作业
1 定义两个表,图书和出版社表
-出版社的5个接口
-图书的5个接口
-查询的时候,出版社显示详情
-新增和修改带出版社
-价格显示成 xx元
2 新增出版社时候,addr最大8,最小3,不能以sb开头,地址不能包含名字
view.py
from django.shortcuts import render
# Create your views here.
from django.views import View
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request
class IndexView(APIView):
def post(self, request):
print(type(request.data))
return Response('ok')
from .models import Book
from .serializer import BookSerializer,BookModelSerializer
class BookView(APIView):
def get(self, request):
qs = Book.objects.all()
ser = BookModelSerializer(instance=qs, many=True)
return Response(ser.data)
def post(self, request):
# 反序列化
ser = BookSerializer(data=request.data)
if ser.is_valid(): # 校验字段是否合法
ser.save() # 如果是新增,就新增了
return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
else:
return Response({'code': 999, 'msg': ser.errors})
from .models import Publish
from .serializer import PublishModelSerializer
class BookDetailView(APIView):
def get(self, request, pk):
book = Book.objects.all().filter(pk=pk).first()
ser = BookSerializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = Book.objects.all().filter(pk=pk).first()
ser = BookSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save() # 如果是修改,就修改了
return Response({'code': 100, 'msg': '修改成功', 'data': ser.data})
else:
return Response({'code': 999, 'msg': ser.errors})
def delete(self, request, pk):
res = Book.objects.filter(pk=pk).delete()
if res:
return Response({'code': 100, 'msg': '删除成功'})
else:
return Response({'code': 999, 'msg': '数据不存在'})
class PublishView(APIView):
def get(self, request):
qs = Publish.objects.all()
ser = PublishModelSerializer(instance=qs, many=True)
return Response(ser.data)
def post(self, request):
# 反序列化
ser = PublishModelSerializer(data=request.data)
if ser.is_valid(): # 校验字段是否合法
ser.save() # 如果是新增,就新增了
return Response({'code': 100, 'msg': '新增成功', 'data': ser.data})
else:
return Response({'code': 999, 'msg': ser.errors})
class PublishDetailView(APIView):
def get(self, request, pk):
book = Publish.objects.all().filter(pk=pk).first()
ser = PublishModelSerializer(instance=book)
return Response(ser.data)
def put(self, request, pk):
book = Publish.objects.all().filter(pk=pk).first()
ser = PublishModelSerializer(instance=book, data=request.data)
if ser.is_valid():
ser.save() # 如果是修改,就修改了
return Response({'code': 100, 'msg': '修改成功', 'data': ser.data})
else:
return Response({'code': 999, 'msg': ser.errors})
def delete(self, request, pk):
res = Publish.objects.filter(pk=pk).delete()
if res:
return Response({'code': 100, 'msg': '删除成功'})
else:
return Response({'code': 999, 'msg': '数据不存在'})
url.py
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('index/', views.IndexView.as_view()),
path('books/', views.BookView.as_view()),
path('books/<int:pk>', views.BookDetailView.as_view()),
path('publish/', views.PublishView.as_view()),
path('publish/<int:pk>', views.PublishDetailView.as_view()),
]
models.py
from django.db import models
# Create your models here.
class Book(models.Model):
name=models.CharField(max_length=64)
price=models.IntegerField()
# publish=models.ForeignKey(to='Publish',to_field='id')
# django 2.0以后,都要加on_delete
publish=models.ForeignKey(to='Publish',on_delete=models.CASCADE) # 不写默认关联Publish的主键
@property
def publish_detail(self):
return {'name':self.publish.name,'addr':self.publish.addr}
class Publish(models.Model):
name=models.CharField(max_length=64)
addr=models.CharField(max_length=64)
def name_detail(self):
return self.name+'_vip'
serializer.py
from rest_framework import serializers
from .models import Book
# class BookSerializer(serializers.Serializer):
# # 想序列化哪个字段,在这写字段及字段对应的类即可
# # source='name'--->意思是name1映射成models中的name
# name1 = serializers.CharField(min_length=3, max_length=8, error_messages={'min_length': '不够'}, read_only=True,
# source='name')
#
#
#
# price = serializers.IntegerField(min_value=3, max_value=30)
# publish = serializers.CharField()
# ## 只用来反序列化, 序列化的时候,忽略该字段
# name = serializers.CharField(write_only=True)
#
# # def create(self, validated_data):
# # print(validated_data)
# # book = Book.objects.create(**validated_data)
# # return book # 一定要返回
# #
# # def update(self, instance, validated_data):
# # instance.name = validated_data.get('name', instance.name)
# # instance.price = validated_data.get('price', instance.price)
# # instance.publish = validated_data.get('publish', instance.publish)
# # instance.save()
# # return instance # 一定要返回
#
# # 重点的:
# '''
# CharField
# IntegerField
# DecimalField
# DateTimeField
# DateField
#
#
#
#
# ListField
# DictField
# '''
#
# # 其他还有很多但的忽略
class BookSerializer(serializers.Serializer):
price = serializers.IntegerField()
name = serializers.CharField()
# publish = serializers.CharField()
# 显示出版社的详情
## 方式一(在序列化类中写)
# publish_name = serializers.SerializerMethodField(read_only=True) # 只能用来做序列化
# def get_publish_name(self,obj):
# # obj 就是当前要序列化的book对象
# # return obj.publish.name
# return {'name':obj.publish.name,'addr':obj.publish.addr}
# 方式二(在模型类中写方法,方法返回什么,这个字段就是什么)(在表模型中写用的多)
# publish_detail=serializers.CharField()
# publish_detail=serializers.DictField()
## 方式三
publish_detail = serializers.CharField(source='publish.addr')
from .models import Book, Publish
# class PublishModelSerializer(serializers.ModelSerializer):
# # 指定跟表的对应关系
# class Meta:
# model = Publish # 跟哪个表有关系
# # fields =['name','addr']
# # fields ='__all__' # 所有字段,只序列化字段,不序列化方法
# fields = ['name', 'addr', 'name_detail']
# # 给字段类,传递参数、属性
# extra_kwargs={
# 'addr':{'max_length':8,'min_length':3,'write_only':True},
# # 'name':{'write_only':True}
# }
# # 不重要的
# # exclude=['name'] # 它跟fields 只能由一个
# # depth=1
#
#
# #1 不用重写create和update
#
# #2 在出版社名字后加 _vip
# # 方式一
# # name=serializers.SerializerMethodField()
# # def get_name(self,obj):
# # return obj.name+'_vip'
#
# # 方式二,在表模型中定义一个name_detail,在fields中写一些字段或方法
#
# ## 序列化的时候使用name_detail,反序列化的时候使用name
# # name_detail = serializers.CharField(read_only=True) 如果是个方法,这句可以不写
# name = serializers.CharField(write_only=True)
#
#
#
# #3 限制addr,最大长度8,最小长度3
class BookModelSerializer(serializers.ModelSerializer):
# 指定跟表的对应关系
class Meta:
model = Book # 跟哪个表有关系
fields = "__all__"
# depth=1 # 不建议用
### 局部和全局钩子
from rest_framework.exceptions import ValidationError
class PublishModelSerializer(serializers.ModelSerializer):
class Meta:
model = Publish
fields = '__all__'
extra_kwargs = {
'addr': {'max_length': 8, 'min_length': 3}
}
## 限制addr,最短3,最长8,不能以sb开头
# 局部钩子:给某个字段再增加校验(固定用法),定义一个方法,名字为validate_字段名
def validate_addr(self, item):
if item.startswith('sb'):
# 抛异常,不能以sb开头
raise ValidationError('不能以sb开头')
else:
return item
# 全局钩子
# 限制出版社的名字不能等于出版社地址
def validate(self, attrs):
name = attrs.get('name')
addr = attrs.get('addr')
if name == addr:
raise ValidationError('name和addr不能一样')
else:
return attrs
扩展
propert装饰器
@property装饰器将方法包装成数据属性(前提是方法没有传除self的其他参数),使用起来不用加括号调用,比较方便(主要看个人习惯)
国际化:在settings文件中修改配置
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai' # 上海的s要大写,小写的在windows上没问题,linux上会报错
USE_I18N = True
USE_L10N = True
USE_TZ = False
什么是鸭子类型(面试题)
其实编程语言有一个接口的概念,Python不需要有一个父类或接口来约束我子类,如果我子类有你们这些方法,那我就认定你们是同一类,这就叫鸭子类型,当我们在实际编码的时候不采用作者的这种鸭子类型,我们还是想来做一个约束,通过abc模块或是通过父类进行抛异常的这种方式来进行约束。

浙公网安备 33010602011771号