# Django入门笔记3-Model 操作与 Serializer 序列化
# 在应用目录编写 Model.py
创建数据模型
"""
用户模块
"""
from django.db import models, transaction
class User(models.Model):
"""
用户信息表
"""
user_id = models.AutoField(primary_key=True, verbose_name='用户id')
user_guid = models.CharField(max_length=150, verbose_name='用户guid')
user_name = models.CharField(
max_length=100, blank=True, null=True, verbose_name='用户名')
real_name = models.CharField(
max_length=50, blank=True, null=True, verbose_name='真实姓名')
avatar = models.CharField(
max_length=250, blank=True, null=True, verbose_name='头像')
mobile = models.CharField(
max_length=50, blank=True, null=True, verbose_name='手机')
balance = models.DecimalField(
max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='账户余额')
available_balance = models.DecimalField(
max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='可用金额')
frozen_balance = models.DecimalField(
max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='冻结金额')
all_balance = models.DecimalField(
max_digits=8, decimal_places=2, blank=True, null=True, verbose_name='累计金额')
wx_open_id = models.CharField(max_length=150, verbose_name='微信OpenID')
wx_union_id = models.CharField(
max_length=150, blank=True, null=True, verbose_name='微信UnionID')
create_date = models.FloatField(blank=True, null=True, verbose_name='创建时间')
last_login_date = models.FloatField(
blank=True, null=True, verbose_name='最后登录时间')
ip_address = models.CharField(
max_length=50, blank=True, null=True, verbose_name='IP地址')
gender = models.IntegerField(blank=True, null=True, verbose_name='性别')
province = models.CharField(
max_length=50, blank=True, null=True, verbose_name='省份')
city = models.CharField(
max_length=50, blank=True, null=True, verbose_name='城市')
session_key = models.CharField(
max_length=150, blank=True, null=True, verbose_name='会话秘钥')
is_notify = models.IntegerField(blank=True, null=True, verbose_name='是否开启打卡通知')
@classmethod
def update_user_balance(cls, user_id, amount):
# 手动让select for update和update语句发生在一个完整的事务里面
with transaction.atomic():
user = (
cls.objects
.select_for_update()
.get(user_id=user_id)
)
user.available_balance += amount
user.balance = user.available_balance + user.frozen_balance
if amount > 0:
user.all_balance += amount
user.save()
return user
class Meta:
managed = False
db_table = 'user'
ordering = ['-create_date']
verbose_name = '用户'
verbose_name_plural = '用户'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
我们还需要为我们的代码段模型创建初始迁移(initial migration),并首次同步数据库(migrate)。
python manage.py makemigrations
python manage.py migrate
1
2
2
# 在应用目录新建Serializer.py
序列化模型
"""
用户模块
"""
from rest_framework import serializers
from apps.user.models import User
from apis.api_v1.enum import ErrorCode
from apis.api_v1.base import BaseApi
class GetUserSerializer(serializers.Serializer):
"""
获取用户信息
"""
token = serializers.CharField(max_length=150)
user_id = serializers.IntegerField()
def get_user(self, validated_data):
result = dict()
base_api = BaseApi()
# 获取用户
try:
user = User.objects.get(user_id=validated_data["user_id"])
except User.DoesNotExist:
result["error_code"] = ErrorCode.用户不存在.value
result["error"] = "用户不存在"
return result
# 认证
if not base_api.authenticate_user(validated_data["token"], user.user_guid):
result["error_code"] = ErrorCode.认证错误.value
result["error"] = "认证错误"
return result
result["nick_name"] = user.user_name
result["avatar"] = user.avatar
result["error_code"] = ErrorCode.正确.value
result["error"] = ""
return result
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
serializer.py
中属性类型与model.py
的属性类型一一对应
# model.py
user_id = models.AutoField(primary_key=True, verbose_name='用户id')
#serializer.py
user_id = serializers.IntegerField()
1
2
3
4
2
3
4
create()
和update()
方法定义了在调用serializer.save()
时如何创建和修改完整的实例。serializer.save()
当实例存在时更新,不存在时创建
使用ModelSerializer
简化编写serializer
简化前
from rest_framework import serializers
from snippets.models import Snippet, LANGUAGE_CHOICES, STYLE_CHOICES
class SnippetSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(required=False, allow_blank=True, max_length=100)
code = serializers.CharField(style={'base_template': 'textarea.html'})
linenos = serializers.BooleanField(required=False)
language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, default='python')
style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly')
def create(self, validated_data):
"""
根据提供的验证过的数据创建并返回一个新的`Snippet`实例。
"""
return Snippet.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
根据提供的验证过的数据更新和返回一个已经存在的`Snippet`实例。
"""
instance.title = validated_data.get('title', instance.title)
instance.code = validated_data.get('code', instance.code)
instance.linenos = validated_data.get('linenos', instance.linenos)
instance.language = validated_data.get('language', instance.language)
instance.style = validated_data.get('style', instance.style)
instance.save()
return instance
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
简化后
class SnippetSerializer(serializers.ModelSerializer):
class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style')
1
2
3
4
2
3
4
重要的是要记住,ModelSerializer
类并不会做任何特别神奇的事情,它们只是创建序列化器类的快捷方式:
- 一组自动确定的字段。
- 默认简单实现的
create()
和update()
方法。
# 应用目录编写view.py
编写Restful API
使用 Django view 编写 Restful API
def __init__(self, data, **kwargs):
content = JSONRenderer().render(data)
kwargs['content_type'] = 'application/json'
super(JSONResponse, self).__init__(content, **kwargs)
@csrf_exempt
def snippet_detail(request, pk):
"""
获取,更新或删除一个 code snippet。
"""
try:
snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
return HttpResponse(status=404)
if request.method == 'GET':
serializer = SnippetSerializer(snippet)
return JSONResponse(serializer.data)
elif request.method == 'PUT':
data = JSONParser().parse(request)
serializer = SnippetSerializer(snippet, data=data)
if serializer.is_valid():
serializer.save()
return JSONResponse(serializer.data)
return JSONResponse(serializer.errors, status=400)
elif request.method == 'DELETE':
snippet.delete()
return HttpResponse(status=204)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
代码如上(部分非关键内容已省略)详情查看官方文档
1 - Serialization - Django REST framework中文站点
REST框架提供了两个可用于编写API视图的包装器(wrappers)。
- 用于基于函数视图的
@api_view
装饰器。 - 用于基于类视图的
APIView
类。
使用 Django Restful Framework view
重构 Restful API
(函数视图)
通过一个函数中通过判断执行不同请求方法实现
@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
"""
获取,更新或删除一个snippet实例。
"""
try:
snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = SnippetSerializer(snippet)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = SnippetSerializer(snippet, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
snippet.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
使用 Django Restful Framework view
重构 Restful API
(类视图CBV)
通过一个类中实现四种请求方法实现
class SnippetDetail(APIView):
"""
检索,更新或删除一个snippet示例。
"""
def get_object(self, pk):
try:
return Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
snippet = self.get_object(pk)
serializer = SnippetSerializer(snippet)
return Response(serializer.data)
def put(self, request, pk, format=None):
snippet = self.get_object(pk)
serializer = SnippetSerializer(snippet, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
snippet = self.get_object(pk)
snippet.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
使用 mixins
通用的基于类的视图
使用 mixin
类可以更少的代码重构这些视图
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
from rest_framework import generics
class SnippetList(generics.ListCreateAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Snippet.objects.all()
serializer_class = SnippetSerializer
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
详细内容参考文档