diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..13566b81b018ad684f3a35fee301741b2734c8f4
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/django-restframework-test.iml b/.idea/django-restframework-test.iml
new file mode 100644
index 0000000000000000000000000000000000000000..9323314a763a36a1e6146a1ee5ac93c282f36ce7
--- /dev/null
+++ b/.idea/django-restframework-test.iml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cdff312489065acd641e40eeb4d258720859beb3
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000000000000000000000000000000000000..105ce2da2d6447d11dfe32bfb846c3d5b199fc99
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d1e22ecb89619a9c2dcf51a28d891a196d2462a0
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1889bab237d621b9c36a18b3e1e08de49494f49b
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000000000000000000000000000000000000..94a25f7f4cb416c083d265558da75d457237d671
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/db.sqlite3 b/db.sqlite3
index 42db1a76d95f421c660bd03c45f143554cb13386..023472b73a4bf841f92489ca058819f38c0c1bde 100644
Binary files a/db.sqlite3 and b/db.sqlite3 differ
diff --git a/django_rest_sample/urls.py b/django_rest_sample/urls.py
index 05fb841da371ccc55cbe81f3dacc6687bba81312..3e454f858e6730799a9b42bb264a9ad5af7748c5 100644
--- a/django_rest_sample/urls.py
+++ b/django_rest_sample/urls.py
@@ -17,12 +17,13 @@ from django.contrib import admin
from django.urls import path
from rest_framework import routers
-from library_app.views import BookViewSet, CategoryViewSet, AuthorViewSet
+from library_app.views import BookViewSet, CategoryViewSet, AuthorViewSet, SummaryViewSet
router = routers.DefaultRouter()
router.register(r'books', BookViewSet)
router.register(r'categories', CategoryViewSet)
router.register(r'authors', AuthorViewSet)
+router.register(r'summary', SummaryViewSet)
urlpatterns = router.urls
urlpatterns += [
diff --git a/img.png b/img.png
new file mode 100644
index 0000000000000000000000000000000000000000..25125ab5323237be2c8be95dacdc828b880a9701
Binary files /dev/null and b/img.png differ
diff --git a/img_1.png b/img_1.png
new file mode 100644
index 0000000000000000000000000000000000000000..29d232c2998895ca26506176b3e12d0d0733cc6d
Binary files /dev/null and b/img_1.png differ
diff --git a/img_2.png b/img_2.png
new file mode 100644
index 0000000000000000000000000000000000000000..ab5087c8bca17f4ce7163d3eabbd8b4a2942522e
Binary files /dev/null and b/img_2.png differ
diff --git a/img_3.png b/img_3.png
new file mode 100644
index 0000000000000000000000000000000000000000..5098e2127e794343d1b7ef6d287cca4069eb7ef2
Binary files /dev/null and b/img_3.png differ
diff --git a/img_4.png b/img_4.png
new file mode 100644
index 0000000000000000000000000000000000000000..53856486c9939bb734822823d843555c1ba89021
Binary files /dev/null and b/img_4.png differ
diff --git a/img_5.png b/img_5.png
new file mode 100644
index 0000000000000000000000000000000000000000..53856486c9939bb734822823d843555c1ba89021
Binary files /dev/null and b/img_5.png differ
diff --git a/img_6.png b/img_6.png
new file mode 100644
index 0000000000000000000000000000000000000000..320f1e61be722d4c3966b709a3756556614687fc
Binary files /dev/null and b/img_6.png differ
diff --git a/img_7.png b/img_7.png
new file mode 100644
index 0000000000000000000000000000000000000000..2498415007e4de90fe34e38342ff11420b654246
Binary files /dev/null and b/img_7.png differ
diff --git a/library_app/migrations/0002_summary.py b/library_app/migrations/0002_summary.py
new file mode 100644
index 0000000000000000000000000000000000000000..6db5e5725acf1fa9b71ccaadc2168583b2fd0a37
--- /dev/null
+++ b/library_app/migrations/0002_summary.py
@@ -0,0 +1,23 @@
+# Generated by Django 2.2.5 on 2022-06-19 07:02
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('library_app', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Summary',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('sum_price', models.DecimalField(decimal_places=2, max_digits=20, verbose_name='书本总价')),
+ ('sum_owned', models.IntegerField(verbose_name='书本总数')),
+ ('most_author', models.ManyToManyField(to='library_app.Author', verbose_name='最多书作者')),
+ ('most_category', models.ManyToManyField(to='library_app.Category', verbose_name='最多书种类')),
+ ],
+ ),
+ ]
diff --git a/library_app/migrations/0003_auto_20220620_1043.py b/library_app/migrations/0003_auto_20220620_1043.py
new file mode 100644
index 0000000000000000000000000000000000000000..bfcfe967589cd6f3bf2937101cb8138fd6412b08
--- /dev/null
+++ b/library_app/migrations/0003_auto_20220620_1043.py
@@ -0,0 +1,33 @@
+# Generated by Django 2.2.5 on 2022-06-20 02:43
+
+from django.db import migrations
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('library_app', '0002_summary'),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name='summary',
+ old_name='most_author',
+ new_name='mostauthor',
+ ),
+ migrations.RenameField(
+ model_name='summary',
+ old_name='most_category',
+ new_name='mostcategory',
+ ),
+ migrations.RenameField(
+ model_name='summary',
+ old_name='sum_owned',
+ new_name='sumowned',
+ ),
+ migrations.RenameField(
+ model_name='summary',
+ old_name='sum_price',
+ new_name='sumprice',
+ ),
+ ]
diff --git a/library_app/models.py b/library_app/models.py
index 4efae69f4620109b96b6cacc7c3809592f8bbc5c..8c5f317679cfaba3fde2d16d3514af1301274e5b 100644
--- a/library_app/models.py
+++ b/library_app/models.py
@@ -4,7 +4,7 @@ from django.db import models
class Book(models.Model):
title = models.CharField(max_length=255, null=True, blank=True)
category = models.ForeignKey('Category', on_delete=models.CASCADE)
- author = models.ForeignKey('Author', on_delete=models.CASCADE)
+ author = models.ForeignKey('Author', on_delete=models.CASCADE)
owned = models.IntegerField()
price = models.FloatField()
publish_date = models.DateField()
@@ -12,15 +12,23 @@ class Book(models.Model):
def __str__(self):
return self.title
+
class Author(models.Model):
name = models.CharField(max_length=255, null=True, blank=True)
def __str__(self):
- return self.name
+ return self.name if self.name else "null"
+
-class Category(models.Model):
+class Category(models.Model):
title = models.CharField(max_length=100, null=True, blank=True)
def __str__(self):
return self.title
+
+class Summary(models.Model):
+ sumprice = models.DecimalField(max_digits=20, verbose_name='书本总价', decimal_places=2)
+ sumowned = models.IntegerField(verbose_name='书本总数')
+ mostauthor = models.ManyToManyField(Author, verbose_name='最多书作者')
+ mostcategory = models.ManyToManyField(Category, verbose_name='最多书种类')
diff --git a/library_app/serializers.py b/library_app/serializers.py
index 849aea1f7cfdf51d36afe7743319ac57b0688bc5..45ddf242a0e99d2671353f12835bf95b66d5a78b 100644
--- a/library_app/serializers.py
+++ b/library_app/serializers.py
@@ -1,7 +1,7 @@
+from django.db.models import Count, Sum, F, DecimalField
from rest_framework import serializers
-from library_app.models import Category, Book, Author
-
+from library_app.models import Category, Book, Author, Summary
class AuthorSerializer(serializers.ModelSerializer):
@@ -9,20 +9,46 @@ class AuthorSerializer(serializers.ModelSerializer):
model = Author
fields = "__all__"
-class BookReadSerializer(serializers.ModelSerializer):
- category = CategorySerializer()
- author = AuthorSerializer()
-
- class Meta:
- model = Book
- fields = '__all__'
class BookWriteSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
+
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = "__all__"
+
+
+class BookReadSerializer(serializers.ModelSerializer):
+ category = CategorySerializer()
+ author = AuthorSerializer()
+
+ class Meta:
+ model = Book
+ fields = '__all__'
+
+
+class SummarySerializer(serializers.ModelSerializer):
+ sumprice = serializers.SerializerMethodField()
+ sumowned = serializers.SerializerMethodField()
+ mostauthor = serializers.SerializerMethodField()
+ mostcategory = serializers.SerializerMethodField()
+ def get_sumprice(self, obj):
+ my_dict1 = Book.objects.aggregate(sum_price=Sum(F('price') * F('owned'), output_field=DecimalField()))
+ return my_dict1.get('sum_price')
+ # return Book.objects.aggregate(sum_price=Sum(F('price') * F('owned'), output_field=DecimalField()))
+ def get_sumowned(self, obj):
+ my_dict2 = Book.objects.aggregate(sum_owned=Sum(F('owned'), output_field=DecimalField()))
+ return my_dict2.get('sum_owned')
+ def get_mostauthor(self, obj):
+ my_list1 = Book.objects.values('author').annotate(total=Count('author'))
+ return Author.objects.get(id=int(my_list1[0]['author'])).name
+ def get_mostcategory(self, obj):
+ my_list2 = Book.objects.values('category').annotate(total=Count('category'))
+ return Category.objects.get(id=int(my_list2[0]['category'])).title
+ class Meta:
+ model = Summary
+ fields = ['sumprice', 'sumowned', 'mostauthor', 'mostcategory']
diff --git a/library_app/views.py b/library_app/views.py
index da56ab7fe376dc3d778ee7e3d280b4971270631d..dae38c521e6575d38914e45660fc75ca4f29ba61 100644
--- a/library_app/views.py
+++ b/library_app/views.py
@@ -1,7 +1,8 @@
from rest_framework import viewsets
-from library_app.models import Category, Author, Book
-from library_app.serializers import CategorySerializer, AuthorSerializer, BookReadSerializer, BookWriteSerializer
+from library_app.models import Category, Author, Book, Summary
+from library_app.serializers import CategorySerializer, AuthorSerializer, BookReadSerializer, BookWriteSerializer, \
+ SummarySerializer
class BookViewSet(viewsets.ModelViewSet):
@@ -13,11 +14,17 @@ class BookViewSet(viewsets.ModelViewSet):
else:
return BookWriteSerializer
+
class CategoryViewSet(viewsets.ModelViewSet):
queryset = Category.objects.all()
serializer_class = CategorySerializer
-
+
class AuthorViewSet(viewsets.ModelViewSet):
queryset = Author.objects.all()
serializer_class = AuthorSerializer
+
+
+class SummaryViewSet(viewsets.ModelViewSet):
+ queryset = Summary.objects.all()
+ serializer_class = SummarySerializer
diff --git "a/\345\274\200\345\217\221\347\254\224\350\256\260.md" "b/\345\274\200\345\217\221\347\254\224\350\256\260.md"
new file mode 100644
index 0000000000000000000000000000000000000000..d98df5ab4e83bb012cc2e69cfad8521646c2df54
--- /dev/null
+++ "b/\345\274\200\345\217\221\347\254\224\350\256\260.md"
@@ -0,0 +1,115 @@
+# Django
+[Django官方文档](https://docs.djangoproject.com/zh-hans/4.0/contents/)
+
+[Django菜鸟教程](https://www.runoob.com/django/django-tutorial.html)
+
+[Django B站教程](https://www.bilibili.com/video/BV1pX4y1F7oz?spm_id_from=333.337.search-card.all.click&vd_source=7c5f5a3ed2bc9ce87a5ea92d9baf1c25)
+
+Django 是一个开放源代码的 Web 应用框架,采用了 MVT 的软件设计模式,即模型(Model),视图(View)和模板(Template),由Python写成。
+
+```python
+View:视图是一个请求处理函数,它接收HTTP请求并返回HTTP响应。视图通过模型访问满足请求所需的数据,并将响应的格式委托给模板。
+Model:模型是定义应用程序数据结构的Python对象,并提供在数据库中管理(添加、修改、删除)和查询记录的机制。
+Templates:模板是定义文件(例如HTML页面)的结构或布局的文本文件,用于表示实际内容的占位符。一个视图可以使用HTML模板,从数据填充它动态地创建一个HTML页面模型。可以使用模板来定义任何类型的文件结构,不一定是HTML。
+```
+![img.png](img.png)
+# Django REST framework
+[Django REST framework官方文档(英)](https://www.django-rest-framework.org/)
+
+[Django REST framework官方文档(中)](https://q1mi.github.io/Django-REST-framework-documentation/)
+
+[Django REST framework B站教程](https://www.bilibili.com/video/BV1XR4y157rk?p=1&vd_source=7c5f5a3ed2bc9ce87a5ea92d9baf1c25)
+
+Django REST framework是基于Django实现的一个RESTful风格API框架,能够帮助我们快速开发RESTful风格的API。
+```python
+API是一个明确定义的接口,可以为其他软件提供特定服务。
+API是一个个具体的函数,一个确定的功能,一个获取后端数据的通道。
+API可以小到只包含一个单独的函数,也可以大到包含数以百计的类、方法、全局函数、数据类型、枚举类型和常量等。
+```
+# 修复错误
+## 错误①
+```
+> pip install -r requirements.txt # 导入程序所需的依赖包
+> python manage.py makemigrations # 根据检测到的模型创建新的迁移
+> python manage.py migrate # 使数据库状态与当前模型集和迁移集同步
+> python manage.py runserver # 启用服务器
+ -- server will be run on 127.0.0.1:8000
+```
+首先将代码clone到pycharm,在Terminal执行第二条语句后便发现第一条错误。
+![CategorySerializer没有定义就使用](img_1.png)
+
+未定义名称CategorySerializer。
+![代码爆红位置](img_2.png)
+
+观察错误处的上下代码,只需将`class BookReadSerializer(serializers.ModelSerializer)`的代码挪动到`class CategorySerializer(serializers.ModelSerializer)`后即可修复,先定义CategorySerializer()再使用。
+## 错误②
+运行代码后发现API无法正确打开,返回类型错误。
+![__str__ 返回非字符串](img_3.png)
+
+仔细观察`model.py`和其余两个API后发现,在中存在空值,不能作为返回。
+![img_4.png](img_4.png)
+
+所以可将返回值作修改,不为空返回真实值,为空则返回字符串`null`
+![img_6.png](img_6.png)
+# 使用Django REST framework实现RESTful API
+本次开发中共有四个需求:
+```python
+1、书本总价
+2、书本总数
+3、最多书作者
+4、最多书种类
+```
+解决思路:
+```python
+1、新建一个表存储需求数据
+2、利用ORM聚合查询出相应数据
+3、新建API将数据呈现
+```
+## 一、在models.py中新建模型
+```python
+class Summary(models.Model):
+ sumprice = models.DecimalField(max_digits=20, verbose_name='书本总价', decimal_places=2)
+ sumowned = models.IntegerField(verbose_name='书本总数')
+ mostauthor = models.ManyToManyField(Author, verbose_name='最多书作者')
+ mostcategory = models.ManyToManyField(Category, verbose_name='最多书种类')
+```
+迁移模型:
+```python
+python manage.py makemigrations
+python manage.py migrate
+```
+## 二、在serializers.py中创建序列化器
+```python
+class SummarySerializer(serializers.ModelSerializer):
+ sumprice = serializers.SerializerMethodField()
+ sumowned = serializers.SerializerMethodField()
+ mostauthor = serializers.SerializerMethodField()
+ mostcategory = serializers.SerializerMethodField()
+ def get_sumprice(self, obj):
+ my_dict1 = Book.objects.aggregate(sum_price=Sum(F('price') * F('owned'), output_field=DecimalField()))
+ return my_dict1.get('sum_price')
+ def get_sumowned(self, obj):
+ my_dict2 = Book.objects.aggregate(sum_owned=Sum(F('owned'), output_field=DecimalField()))
+ return my_dict2.get('sum_owned')
+ def get_mostauthor(self, obj):
+ my_list1 = Book.objects.values('author').annotate(total=Count('author'))
+ return Author.objects.get(id=int(my_list1[0]['author'])).name
+ def get_mostcategory(self, obj):
+ my_list2 = Book.objects.values('category').annotate(total=Count('category'))
+ return Category.objects.get(id=int(my_list2[0]['category'])).title
+ class Meta:
+ model = Summary
+ fields = ['sumprice', 'sumowned', 'mostauthor', 'mostcategory']
+```
+## 三、在views.py中创建视图聚合
+```python
+class SummaryViewSet(viewsets.ModelViewSet):
+ queryset = Summary.objects.all()
+ serializer_class = SummarySerializer
+```
+## 四、在urls.py中添加API
+```python
+router.register(r'summary', SummaryViewSet)
+```
+## 五、启动项目
+![img_7.png](img_7.png)
\ No newline at end of file