文章目录
准备一个DRF项目
环境搭建
- IDE推荐使用Pycharm专业版本,专业版相较于免费版本,可以直接连接数据库。学生可以直接申请专业版的使用。
Pycharm官网下载 - 开发环境我是用的Anaconda,需要注意的是安装Django的2.2版本,最新的3.x还属于测试版,与之前的版本使用有着区别,也不稳定。另外需要安装djangoresrframework和mysqlclient等包。
项目配置
- pycharm创建Django项目,使用先前创建的conda环境。
- 在setting.py中如下修改
ALLOWED_HOSTS = ['*']
- 在INSTALLED_APP中添加
INSTALLED_APPS = [
......
'rest_framework'
]
-
- 根据需要修改数据库
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'xxx',
'HOST': '127.0.0.1',
'USER': 'xxx',
'PASSWORD': 'xxx',
'PORT': 3306,
}
}
-
- 修改语言选项和时区
LANGUAGE_CODE = 'zh-hans'
TIME_ZONE = 'Asia/Shanghai'
USE_I18N = True
USE_L10N = True
USE_TZ = False
- 如果设置了数据库,对数据库进行连接,连接数据库的前提是体现创建好了数据库。填写数据库的名称,用户名,密码。填写完毕可以点击测试连接,如果提示TimeZone问题,可以点击立即修复。
测试
pycharm窗口的Terminal命令行下输入python manage.py runserver
,启动测试。出现下面界面表示配置成功。
数据迁移
- 从数据库到models.py
`python manage.py inspectdb > App/models.py`
Serializer序列化
正向序列化
serializer.py
class BookSerializer(serializers.Serializer):
btitle = serializers.CharField(max_length=100, required=False)
bpub_date = serializers.DateField(allow_null=True, required=False)
bread = serializers.IntegerField(min_value=0)
bcomment = serializers.IntegerField(min_value=0)
bimage = serializers.CharField(max_length=300)
views.py
def get(self, request):
# 正向序列化
books = Bookinfo.objects.all()
bs = BookSerializer(instance=books, many=True)
return Response(data=bs.data)
反向序列化
- 使用serializers.Serializer反向序列化,需要重写 create update
- create 是创建新的对象
serializer.py def create(self, validated_data): # book = Bookinfo(btitle=validated_data.get('btitle')) # book.bpub_date = validated_data.get('bpub_date') # book.bread = validated_data.get('bread', 0) # book.bcomment = validated_data.get('bcomment', 0) # book.bimage = validated_data.get('bimage', '') # book.save() # return book # 也可由下面这么写 return Bookinfo.objects.create(**validated_data)
- update 是对对象的更新
def update(self, instance, validated_data): """ :param instance: 要更新的对象 :param validated_data: y要更新的属性字典 :return: 对象 """ print("update") instance.btitle = validated_data.get('btitle') if validated_data.get('btitle') else instance.btitle if validated_data.get('bpub_date'): instance.bpub_date = validated_data.get('bpub_date') else: instance.bpub_date = instance.bpub_date instance.bread = validated_data.get('bread') if validated_data.get('bread') else instance.bread instance.bcomment = validated_data.get('bcomment') if validated_data.get('bcomment') else instance.comment instance.bread = validated_data.get('bimage') if validated_data.get('bimage') else instance.bimage instance.save() return instance
- 在视图函数views.py中实现操作,如果使用序列化器进行验证更新操作,需要讲所有的不允许为空的值指定,然后更新,否则会报错。
# 新增操作 book = {'btitle':'庆余年2','bpub_date':'2020-3-10', 'bread':10,'bcomment':30,'bimage':'static/1.jpg'} bs = BookSerializer(data=book) # 验证 if bs.is_valid(): # 保存到数据库 bs.save() print(bs.data) return Response({'code': 0, 'msg': '保存成功'}) else: print(bs.errors) return Response({'code': 1,'msg': bs.errors}) # 更新操作 data = {'bimage': 'static/0.jpg'} book = Bookinfo.objects.get(pk=3) # 把对象赋值给instance,更新属性字典赋值给data bs = BookSerializer(instance=book, data=data) # 验证 if bs.is_valid(): # 保存到数据库 bs.save() print(bs.data) return Response({'code': 0, 'msg': '保存成功'}) else: print(bs.errors) return Response({'code': 1,'msg': bs.errors})
- 进行序列化验证更新会有些麻烦,可以写成部分更新。
views.py # 部分更新 data = {'bimage': 'static/111.jpg'} book = Bookinfo.objects.get(pk=3) for key, value in data.items(): if hasattr(book, key): setattr(book, key, value) book.save() return Response({'code': 2, 'msg': 'update success'})
自定义验证器
- 单独的函数
def check_data(value):
if value < datetime(2010,1,1).date():
raise serializers.ValidationError("日期不能小于2010-1-1")
bpub_date = serializers.DateField(allow_null=True, required=False, validators=[check_data])
- 使用定义单字段验证,validate_xxx, 验证哪个字段就写对应的名字到xxx,此时的attrs为字符串,不是字典。
def validate_bread(self, attrs):
if attrs > 1000:
raise serializers.ValidationError("阅读数不能大于1000")
- 涉及到多字段验证
def validate(self, attrs):
pass
(推荐使用)使用ModelSerializer进行序列化,自动生成create和update方法
class BookSerializer(serializers.ModelSerializer):
bread = serializers.IntegerField(min_value=0) # 重写验证
class Meta:
model = Bookinfo
fields = ['btitle', 'bpub_date', 'bread', 'bcomment', 'bimage']
# fields = '__all__'
关联对象
1.查询到的字典中只包含关联表的主键
related_name 在表中定义外键时,增加related_name字段指定这个字表在主表中对应的外键属性,
models.py
class Bookinfo(models.Model):
btitle = models.CharField(max_length=200)
bpub_date = models.DateField(blank=True, null=True)
bread = models.IntegerField()
bcomment = models.IntegerField()
bimage = models.CharField(max_length=200, blank=True, null=True)
class Meta:
managed = False
db_table = 'bookinfo'
class Heroinfo(models.Model):
hid = models.AutoField(primary_key=True)
hname = models.CharField(max_length=50)
bid = models.ForeignKey(Bookinfo, models.DO_NOTHING, db_column='bid', blank=True, null=True, related_name='heros')
class Meta:
managed = False
db_table = 'heroinfo'
在models.py里定义了外键,使用了related_name='heros,在序列化器里设置关联对象。
serializer.py
class HeroSerializer(serializers.ModelSerializer):
class Meta:
model = Heroinfo
fields = '__all__'
class BookSerializer(serializers.ModelSerializer):
# 关联对象
heros = PrimaryKeyRelatedField(many=True, read_only=True)
bread = serializers.IntegerField(min_value=0) # 重写验证
class Meta:
model = Bookinfo
fields = '__all__'
最后返回字典为,其中heros下为对应字段的主键
2.使用方法__str__(self),直接返回名字
在models.py里定义模型的同时,重写方法__str__(),序列化器中使用StringRelatedField()方法可以直接返回名字。
models.py
class Heroinfo(models.Model):
hid = models.AutoField(primary_key=True)
hname = models.CharField(max_length=50)
bid = models.ForeignKey(Bookinfo, models.DO_NOTHING, db_column='bid', blank=True, null=True, related_name='heros')
class Meta:
managed = False
db_table = 'heroinfo'
def __str__(self):
return self.hname
serializer.py
class BookSerializer(serializers.ModelSerializer):
# 关联对象
heros = StringRelatedField(many=True, read_only=True)
bread = serializers.IntegerField(min_value=0) # 重写验证
class Meta:
model = Bookinfo
fields = '__all__'
3.获取关联字段的所有信息
HeroSerializer为Heroinfo的序列化器,BookSerializer为Bookinfo的序列化器,直接使用heros = HeroSerializer(many=True, read_only=True)
serializer.py
class HeroSerializer(serializers.ModelSerializer):
class Meta:
model = Heroinfo
fields = '__all__'
class BookSerializer(serializers.ModelSerializer):
# 关联对象
heros = HeroSerializer(many=True, read_only=True)
bread = serializers.IntegerField(min_value=0) # 重写验证
class Meta:
model = Bookinfo
fields = '__all__'