教程地址
Day1:启动django项目
创建虚拟环境ybw
启动vscode,进入终端
进入虚拟环境
conda activate ybw
安装包
css
pip install django
pip install django_extensions
pip install django-debug-toolbar
pip install djangorestframework
pip install django-filter
pip install drf_spectacular
搭建和运行项目
进入工作目录,我选择的目录是"D:\星球项目\django后端开发",初始目录为空
新建名为erp的项目
django-admin startproject erp
在apps中,新建名为data和purchase的app
bash
cd .\erp\
python .\manage.py startapp apps
cd .\apps\
django-admin startapp data
django-admin startapp purchase
将data和purchase目录下的apps.py变量name分别修改
创建完成后,目录内容如下
运行项目
bash
cd ..
python .\manage.py makemigrations
python .\manage.py migrate
python .\manage.py runserver
Ctrl点击运行地址,或者在浏览器输入http://127.0.0.1:8000/
Day2: 构建数据表
创建产品分类和产品两个数据表
修改apps目录下modes.py,替换为以下代码
ini
# from django.db import models
from django.db.models import *
# Create your models here.
## 产品分类表
class GoodsCategory(Model):
"""产品分类"""
name = CharField(max_length=64, verbose_name='分类名称')
remark = CharField(max_length=64, null=True, verbose_name='备注', blank=True)
## 产品表
class Goods(Model):
"""产品"""
# 外键
category = ForeignKey(GoodsCategory, on_delete=SET_NULL, related_name='goods_set', null=True, verbose_name='产品分类',
blank=True, )
# on_delete
number = CharField(max_length=32, verbose_name='产品编号')
name = CharField(max_length=64, verbose_name='产品名称')
barcode = CharField(max_length=32, null=True, blank=True, verbose_name='条码')
spec = CharField(max_length=64, null=True, blank=True, verbose_name='规格')
shelf_life_days = IntegerField(null=True, verbose_name='保质期天数')
purchase_price = FloatField(default=0, verbose_name='采购价')
retail_price = FloatField(default=0, verbose_name='零售价')
remark = CharField(max_length=128, null=True, blank=True, verbose_name='备注')
执行生成迁移脚本命令和迁移命令
在erp目录下执行
python manage.py makemigrations
python manage.py migrate
执行效果如下
sql
(ybw) PS D:\星球项目\django后端开发\erp> python .\manage.py makemigrations
Migrations for 'apps':
apps\migrations\0001_initial.py
- Create model GoodsCategory
- Create model Goods
(ybw) PS D:\星球项目\django后端开发\erp> python .\manage.py migrate
Operations to perform:
Apply all migrations: admin, apps, auth, contenttypes, sessions
Running migrations:
Applying apps.0001_initial... OK
数据表常用字段和配置
python
"""
CharField:用于存储字符串类型,有最大长度限制
IntegerField:用于存储整数类型
FloatField:用于存储浮点数类型
BooleanField:用于存储布尔类型
DateField:用于存储日期类型
DateTimeField:用于存储日期和时间类型
ImageField:用于存储图片类型
FileField:用于存储文件类型
ForeignKey:外键 用于表示数据库表之间的关联关系
OneToOneField:一对一 用于表示一对一的关联关系
ManyToManyField:多对多 用于表示多对多的关联关系
max_length:字段的最大长度限制,可以应用于多种不同的字段类型。
verbose_name:字段的友好名称,便于在管理员后台可视化操作时使用。
default:指定字段的默认值。
null:指定字段是否可以为空。null=True 设置允许该字段为 NULL 值
blank:指定在表单中输入时是否可以为空白。
choices:用于指定字段的可选值枚举列表。
related_name:指定在多对多等关系中反向使用的名称。
on_delete:指定如果外键关联的对象被删除时应该采取什么操作。
"""
可以使用字段和配置,增加新的数据字段
Day3:设置admin和使用postman测试api
创建admin后台和 管理员
在终端运行命令
python manage.py createsuperuser
这里要输入用户名,邮箱和密码
在admin.py文件中注册模型:
python
from django.contrib import admin
from .models import * # 引入产品表
# 一定要分开逐个注册,不能放在一起
admin.site.register(Goods)
# 在admin站点中 注册产品表
admin.site.register(GoodsCategory)
# 在admin站点中 注册产品表
登录 admin 后台
http://127.0.0.1:8000/admin
设置后台显示中文
在每个创建的分类下增加class Meta 和 def str(self)
其中verbose_name表示要显示的类的中文名称
ini
## 产品分类表
class GoodsCategory(Model):
"""产品分类"""
name = CharField(max_length=64, verbose_name='分类名称')
remark = CharField(max_length=64, null=True, verbose_name='备注', blank=True)
class Meta:
verbose_name = "产品分类" # 表名改成中文名
verbose_name_plural = verbose_name
def __str__(self):
return self.name
## 产品表
class Goods(Model):
"""产品"""
# 外键
category = ForeignKey(GoodsCategory, on_delete=SET_NULL, related_name='goods_set', null=True, verbose_name='产品分类',
blank=True, )
# on_delete
number = CharField(max_length=32, verbose_name='产品编号')
name = CharField(max_length=64, verbose_name='产品名称')
barcode = CharField(max_length=32, null=True, blank=True, verbose_name='条码')
spec = CharField(max_length=64, null=True, blank=True, verbose_name='规格')
shelf_life_days = IntegerField(null=True, verbose_name='保质期天数')
purchase_price = FloatField(default=0, verbose_name='采购价')
retail_price = FloatField(default=0, verbose_name='零售价')
remark = CharField(max_length=128, null=True, blank=True, verbose_name='备注')
class Meta:
verbose_name = "产品" # 表名改成中文名
verbose_name_plural = verbose_name
def __str__(self):
return self.name
LANGUAGE_CODE 和 TIME_ZONE 变量修改
ini
LANGUAGE_CODE = 'zh-Hans'
TIME_ZONE = 'Asia/Shanghai'
增加数据
进入后台http://127.0.0.1:8000/admin
接下来都类似于网页操作,直接通过鼠标点击就可以增加数据了
根据教程,增加 苹果------水果, 大象------动物 等产品和产品分类数据
使用线上postman调试API
postman网址:www.postman.com/
需要注册登录,然后新建HTTPS测试,注意由于是进行localhost测试,因此需要根据提示安装 Postman Agent
根据教程,测试效果如下
Day4:QuerySet 和 Instance
教程里介绍了QuerySet 和 Instance 的定义
QuerySet实际上是一种灵活的、惰性的查询表达式,可以用于过滤、排序、聚合等操作。
常见的QuerySet操作方法:
filter()、get()、all()、delete()、update()、create()、count()、order_by()
Instance是指Django模型的单个实例,即数据库中的一行数据。它用于对单个模型实例进行创建、更新或删除等操作。
我这里没太搞懂
感觉views.py里,标注出来的2行代码,应该是使用了QuerySet提供的方法
一般的使用方式是 类别名.objects.filter() 之类的
Day5:APIView
使用APIView
修改urls.py,增加path
增加serialize.py,因为views.py里调用了对象序列化
serializer = GoodsSerializer(instance=new_goods)
同时在views.py里 from .serializer import *
runserver启动django,使用postman验证getgoods,得到产品列表
比较 APIView 和 as_view 的区别
APIView是REST framework提供的所有视图的基类,继承自Django的View类
APIView与View的不同点为:
- 传入到视图方法中的是REST framework的Request对象,而不是Django的HttpRequeset对象
- 视图方法可以返回REST framework的Response对象,视图会为响应数据设置(render)符合前端期望要求格式
- 任何APIException异常都会被捕获到,并且处理成合适格式(json)的响应信息返回给客户端
django的类视图拥有自动查找指定方法的功能, 通过调用是通过as_view()
方法实现
调用顺序: as_view --> view --> dispatch
- as_view实际上是一个闭包, 它的作用做一些校验工作, 再返回view方法.
- 而view方法的作用是给请求对象补充三个参数, 并调用 dispatch方法处理
- dispatch方法查找到指定的请求方法, 并执行
可以得出结论: 实际上真正实现查找的方法是 dispatch方法
使用 APIView 的 as_view 方法
这里在urls.py里使用了as_view方法,分别是filtergoodscategoryapi/
和 getgoods/
lua
urlpatterns = [
path('admin/', admin.site.urls),
path('filtergoodscategoryapi/', FilterGoodsCategoryAPI.as_view()),
path('getgoods/', GetGoods.as_view()),
]
Day6:构建序列化
构建序列化
根据教程修改serialize.py,views.py 和 urls.py
使用shell测试序列化
启用shell,使用 python .\manage.py shell
序列化多个对象,测试效果如下
python
(ybw) PS D:\星球项目\django后端开发\erp> python .\manage.py shell
Python 3.11.2 | packaged by Anaconda, Inc. | (main, Mar 27 2023, 23:35:04) [MSC v.1916 64 bit (AMD64)]
Type 'copyright', 'credits' or 'license' for more information
IPython 8.13.2 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from apps.models import *
In [2]: from apps.serializer import *
In [3]: data = Goods.objects.all()
In [4]: serializer = GoodsSerializer(instance=data, many=True)
In [5]: print(serializer.data)
[OrderedDict([('id', 1), ('category', OrderedDict([('name', '水果'), ('remark', '水果')])), ('number', '1'), ('name', '苹果'), ('barcode', None), ('spec', None), ('shelf_life_days', 10), ('purchase_price', 3.0), ('retail_price', 5.0), ('remark', None)]), OrderedDict([('id', 2), ('category', OrderedDict([('name', '水果'), ('remark', '水果')])), ('number', '2'), ('name', '桃子'), ('barcode', None), ('spec', None), ('shelf_life_days', 10), ('purchase_price', 4.0), ('retail_price', 6.0), ('remark', None)]), OrderedDict([('id', 3), ('category', OrderedDict([('name', '动物'), ('remark', '动物')])), ('number', '3'), ('name', '猴子'), ('barcode', None), ('spec', None), ('shelf_life_days', 40), ('purchase_price', 60.0), ('retail_price', 100.0), ('remark', None)]), OrderedDict([('id', 4), ('category', OrderedDict([('name', '动物'), ('remark', '动物')])), ('number', '4'), ('name', '大象'), ('barcode', None), ('spec', None), ('shelf_life_days', 200), ('purchase_price', 100.0), ('retail_price', 200.0), ('remark', None)])]
截图如下
Day7:Django-DRF(ModelViewSet)的使用
创建GoodsCategoryViewSet
ModelViewSet 是 Django REST framework 提供的一个视图集类,它封装了常见的模型操作方法。
使用 ModelViewSet 后,你将自动获得默认的 CRUD 方法。
C:CreateModelMixin,R:RetrieveModelMixin,U:UpdateModelMixin,D:DestroyModelMixin
创建资源,获取单个资源详细信息,更新资源,删除资源。
根据教程P11和P12,修改views.py,urls.py,serializer.py
通过Postman测试
解决Status 500问题
views.py中写自己的ViewSet,注意delete_example
函数和create_example
函数结尾增加Response
python
#### modelviewset
class GoodsCategoryViewSet(ModelViewSet):
# 指定查询集(用到的数据)
queryset = GoodsCategory.objects.all()
# 指定查询集用到的序列化容器
serializer_class = GoodsCategorySerializer
@action(detail=False, methods=['get'])
def latest(self, request):
latest_obj = GoodsCategory.objects.latest('id')
print(latest_obj)
return Response("hello,你调用了latest函数")
@action(detail=False, methods=['get','post'])
def delete_example(self, request):
name = request.data.get('name')
# 删除名称为 'name' 的商品
categories_to_delete = GoodsCategory.objects.filter(name=name)
# 使用delete()方法删除对象
deleted_count= categories_to_delete.delete()
print(f"Deleted {deleted_count} categories.")
return Response("hello,你调用了delete_example函数")
@action(detail=False, methods=['get','post'])
def create_example(self, request):
name = request.data.get('name')
remark = request.data.get('remark')
# 使用create()方法创建新的商品分类对象
created_category = GoodsCategory.objects.create(name=name, remark=remark)
print("Created category:", created_category)
return Response("hello,你调用了create_example函数")
测试create_example
测试GoodsCategory/
Day8:DefaultRouter使用
urls.py中添加
python
from rest_framework import routers
# 创建DefaultRouter对象,用于生成路由
router = routers.DefaultRouter()
# 将视图集注册到路由器上,字符串里的是URL路径的前缀
router.register('GoodsCategory', GoodsCategoryViewSet)
在Day7中,测试DRF已经使用了该功能,并通过action进行数据表的增删改查