宇宙安全声明:
纯小白摸索,欢迎大佬指正,但不要批评的太狠(qwq)
Task01:环境搭建与项目配置
...相较于示例教程,推荐看官方文档...
...前提是安装好了python...
...命令行还是用不习惯,所以就直接在Pycharm里创建Django项目了...
演示
1.建Django项目
选择新建项目中的Django项目,选择之前配置的python解释器,效果如图:
2.检验Django是否安装
若未安装:python install django
3.新建项目
注意这里要进入manage.py文件所在目录,两者语句均能建立新项目,如图:
...myproject 与 my_2 都是自定义的项目名字...
4.检验项目创建
输入 python manage.py runserver,如下:
...这里输入ctrl+c是可以退出的,不行的话多试两次(电脑不同可能按键不同)...
访问这个域名出现下图说明创建成功:
5.新建APP
这里依旧是在Django项目中建立app,myapp会建立在Django的子目录,框架如下:
6.保存APP修改
由于新建了app,后期如果需要使用该app,则需要在与项目同名目录中settings.py中进行添加路径,如下:
这里是myapp\apps.py的函数,所以应做如下添加:
7.启动项目
通过运行 makemigrations
命令,Django 会检测你对模型文件的修改(在这种情况下,你已经取得了新的),并且把修改的部分储存为一次迁移。由于这里没有对myapp内的models文件修改,所以显示no changes
输入 python manage.py migrate 命令后:(不是很懂这里not found的意思,但问题应该不大..吧)
再次运行 python manage.py runserver 命令,在给出的域名后加上/admin,我这里就是127.0.0.1:8000/admin,访问该url出现登录界面。
Task02:数据表构建与数据迁移与管理--models.py的应用
数据表构建
from django.db import models
class GoodsCategory(models.Model):
name = models.CharField(max_length=64, verbose_name='名称')
remark = models.CharField(max_length=256, null=True, blank=True, verbose_name='备注')
class Goods(models.Model):
number = models.CharField(max_length=32, verbose_name='编号')
name = models.CharField(max_length=64, verbose_name='名称')
barcode = models.CharField(max_length=32, null=True, blank=True, verbose_name='条码')
category = models.ForeignKey('myapp.GoodsCategory', on_delete=models.SET_NULL, null=True, related_name='goods_set',
verbose_name='产品分类')
spec = models.CharField(max_length=64, null=True, blank=True, verbose_name='规格')
shelf_life_days = models.IntegerField(null=True, verbose_name='保质期天数')
purchase_price = models.FloatField(default=0, verbose_name='采购价')
retail_price = models.FloatField(default=0, verbose_name='零售价')
remark = models.CharField(max_length=256, null=True, blank=True, verbose_name='备注')
注意这里的'myapp.GoodsCategory',是自定义的app名称
合并数据库
- python manage.py makemigrations
- python manage.py migrate
常用字段
CharField
用于存储字符串类型,有最大长度限制
IntegerField
用于存储整数类型
FloatField
用于存储浮点数类型
BooleanField
用于存储布尔类型
DateField
用于存储日期类型
DateTimeField
用于存储日期和时间类型
ImageField
用于存储图片类型
FileField
用于存储文件类型
ForeignKey
外键 用于表示数据库表之间的关联关系
OneToOneField
一对一 用于表示一对一的关联关系
ManyToManyField
多对多 用于表示多对多的关联关系
字段选项
max_length
字段的最大长度限制,可以应用于多种不同的字段类型。
verbose_name
字段的友好名称,便于在管理员后台可视化操作时使用。
default
指定字段的默认值。
null
指定字段是否可以为空。
null=True
设置允许该字段为 NULL 值
blank
指定在表单中输入时是否可以为空白。
choices
用于指定字段的可选值枚举列表,在最上面定义
创建管理员
输入 python manage.py createsuperuser
(虽然要求八个字符的密码,实际上更少也是可以的)
输入 python manage.py runserver,在给出域名后加上/admin进行访问,输入设置的用户名和密码
配置admin.py
刷新刚访问的网页,会发现如下更新:
构建数据表
views.py
from django.shortcuts import render
from rest_framework.response import Response
from .models import *
from rest_framework.decorators import api_view
from django.shortcuts import get_object_or_404
# Create your views here.
# GET
# POST
# 函数式编程
@api_view(['POST', 'GET'])
def InsertGoodsCategory(request):
category_name = request.data.get('分类名字')
# 获取分类对象或创建新的分类对象
category, created = GoodsCategory.objects.get_or_create(name=category_name)
# 判断是否已存在分类
if not created:
return Response({"status": "已存在", "goods_category": category_name}, status=200)
else:
return Response({"message": f"Successfully inserted category '{category_name}'."})
@api_view(['POST','GET'])
def FilterGoodsCategory(request):
data = request.data.get('分类名字')
goods = GoodsCategory.objects.filter(name=data)
if goods.exists():
return Response({"status": "已存在", "goods_category": data}, status=200)
else:
return Response({"status": "不存在" ,"goods_category": data}, status=404)
urls.py
from django.contrib import admin
from django.urls import path
from apps.erp_test.views import *
urlpatterns = [
path('admin/', admin.site.urls),
path('filtergoodscategory/', FilterGoodsCategory),
path('insertgoodscategory/', InsertGoodsCategory),
]
接口测试
这里我是下载的Apifox-->个人项目-->快捷请求
修改:
在urls.py文件中将访问路径最后的斜杠改掉了,舍友说前端处理不好的话访问可能会出问题 ,同时注意在Apifox中访问时去掉末尾斜杠
Task03:QuerySet 和 Instance应用
QuerySet
QuerySet是存储从数据库查询的结果的集合
all()
:返回模型的所有对象
values()
:显示详细信息
可以加入参数限制显示参数的种类
create()
是 save()
方法的快捷方式,用于创建并保存一个新的对象
这是save()创建方法,这里的ID是3可能是我中途删除了一些对象
这是create()方法,需要用**将字典解包传入,当然也可以从网页直接添加
count()
:返回符合条件的对象数量
filter()(**kwargs)
用于返回符合条件的所有数据
注意是否是字符串的区别
get()
方法与 filter()
的作用类似,用于返回符合条件的单个对象但是可能会返回多个值
exclude():排除符合条件的对象
update()
:将符合条件的所有对象的某个字段值进行更新
只返回是否成功更新
delete()
:可以删除符合条件的所有对象
不能放在value()方法后,返回是否成功删除
order_by()
:对返回的对象进行排序,默认为升序。降序则在字段名前面加负号
Instance
Instance指的是一个 Django 模型的单个实例,也就是数据库中的一行数据。相比于 QuerySet(查询集合),它是针对单个对象的操作,用于创建、更新或者删除单个模型实例。
QuerySet 适用于需要查找多个对象或进行聚合操作的场景,而 Instance 适用于单独对象的创建、修改和删除操作。
增
同上,这里直接在网页修改,加粗的条目是必填的
查、删
同queryset
改
Task04:Django Serialization(序列化)及API View模式的编程实现
Django Serialization(序列化)
序列化将
queryset
和instance
转换为json/xml/yaml
返回给前端
反序列化与序列化则相反
常见方法
1.使用 Django
内置的 serializers
模块进行序列化和反序列化
from django.core import serializers
# 序列化 QuerySet 为 JSON
data = serializers.serialize('json', MyModel.objects.all())
# 反序列化 JSON 数据并保存到数据库
for obj in serializers.deserialize('json', data):
obj.save()
2.使用 Django
的 JsonResponse
来将模型数据作为 JSON
响应返回给客户端
from django.http import JsonResponse
def get_data(request):
data = list(MyModel.objects.values())
return JsonResponse(data, safe=False)
3.使用第三方库如 Django Rest Framework(DRF)
来构建 RESTful API
并进行序列化。DRF
提供了强大的序列化和反序列化功能,以及视图、路由和其他 API
开发工具
from rest_framework import serializers
class MyModelSerializer(serializers.ModelSerializer):
class Meta:
model = MyModel
fields = '__all__'
定义序列化器
在myapp中新建serializer.py文件,这里采用DRF定义
# 定义产品序列化器
from rest_framework.serializers import *
from .models import *
# 产品分类序列化器
class GoodsCategorySerializer(ModelSerializer):
class Meta:
model = GoodsCategory
fields = ('name', 'remark')
# 产品序列化器
class GoodsSerializer(ModelSerializer):
# 外键字段相关的数据 需要单独序列化
category = GoodsCategorySerializer()
class Meta:
# 指定 model
model = Goods
# 序列化单个字段
fields = ('name',)
# 序列化多个字段
fields = ('name','number',)
# 序列化所有字段
fields = '__all__'
序列化对象
单个对象序列化
# 获取对象
data = Goods.objects.get(id=1)
# 创建序列化器
serializer = GoodsSerializer(instance=data)
# 转换数据
print(serializer.data)
"""instance 是一个参数,用于指定要序列化或反序列化的 Python 对象。具体来说,它是一个类实例 (Class Instance),通常是指一个从数据库或其他数据源中检索出来的模型实例 (Model Instance)。
当我们需要将一个模型实例转换为 JSON 或其他格式时,可以使用 Django 的序列化器 (Serializer) 来实现。"""
多个对象序列化
# 获取对象
data = Goods.objects.all()
# 创建序列化器,many表示序列化多个对象,默认为单个
serializer = GoodsSerializer(instance=data,many=True)
# 转换数据
print(serializer.data)
APIView
APIview 是 Django REST Framework 提供的一个视图类。它和 Django 中的 view 类有些相似,但是又有一些不同之处。APIview 可以处理基于 HTTP 协议的请求,并返回基于内容协商的响应,它旨在提供一个易于使用且灵活的方式来构建 API 视图。
views.py
# 面向对象编程
from django.shortcuts import render
from rest_framework.decorators import api_view
from .models import *
from rest_framework.response import Response
from rest_framework.views import APIView
#### APIView
class GetGoods(APIView):
def get(self, request):
data = Goods.objects.all()
serializer = GoodsSerializer(instance=data, many=True)
print(serializer.data)
return Response(serializer.data)
def post(self, request):
# 从请求数据中提取字段
request_data = {
"category": request.data.get("Goodscategory"),
"number": request.data.get("number"),
"name": request.data.get("name"),
"barcode": request.data.get("barcode"),
"spec": request.data.get("spec"),
"shelf_life_days": request.data.get("shelf_life_days"),
"purchase_price": request.data.get("purchase_price"),
"retail_price": request.data.get("retail_price"),
"remark": request.data.get("remark"),
}
# 使用 create() 方法创建新的商品对象
new_goods = Goods.objects.create(**request_data)
# 对创建的对象进行序列化,并作为响应返回
serializer = GoodsSerializer(instance=new_goods)
return Response(serializer.data)
# 面向对象编程
class FilterGoodsCategoryAPI(APIView):
# request 表示当前的请求对象
# self 表示当前实例对象
def get(self, request, format=None):
print(request.method)
return Response('ok')
def post(self, request, format=None):
print(request.method)
return Response('ok')
def put(self, request, format=None):
print(request.method)
return Response('ok')
urls.py
from apps.erp_test.views import *
urlpatterns = [
path('admin/', admin.site.urls),
...
path('filtergoodscategoryapi', FilterGoodsCategoryAPI.as_view()),
path('getgoods', GetGoods.as_view()),
]
Task05:Django-DRF(ModelViewSet)及自定义函数的使用 && Task06: DefaultRouter 的使用
ModelViewSet
ModelViewSet 是 Django REST framework 提供的一个视图集类,它封装了常见的模型操作方法。
它继承自
GenericViewSet
、ListModelMixin
、RetrieveModelMixin
、CreateModelMixin
、UpdateModelMixin
、DestoryModelMixin
。视图集类不再实现get()、post()、put()、delete()方法,而是实现动作 action。 如 list()、retrieve()、create()、update()、destory()
创建 ModelViewSet
from rest_framework.viewsets import ModelViewSet
from .serializer import *
class GoodsCategoryViewSet(ModelViewSet):
# 指定查询集(用到的数据)
queryset = GoodsCategory.objects.all()
# 指定查询集用到的序列化容器
serializer_class = GoodsCategorySerializer
在views.py文件中添加代码,这样我们就创建好了API视图集,这个GoodsCategoryViewSet
将提供 list
,create
,retrieve
,update
和 destroy
操作。
Django-DRF 路由组件
DefaultRouter
是Django REST framework中提供的一个路由器类,用于自动生成URL路由。路由器是将URL与视图函数或视图集关联起来的一种机制。Django REST framework的路由器通过简单的配置可以自动生成标准的URL路由,从而减少了手动编写URL路由的工作量。
如何使用
在urls.py文件添加代码,设置路由
from rest_framework import routers
from django.urls import include
# 创建DefaultRouter对象,用于生成路由
router = routers.DefaultRouter()
# 将视图集注册到路由器上,字符串里的是URL路径的前缀
router.register('GoodsCategory', GoodsCategoryViewSet)
urlpatterns = [
path('', include(router.urls)),
]
在该文件中,我们创建一个默认的Router,然后注册我们的
GoodsCategoryViewSet
。Router负责处理请求转到适当的视图。这样,我们就可以通过API进行查询、创建、更新和删除操作。
使用Apifox测试
启动项目
获取所有对象
获取单个对象
。。。没有则返回not found。。。
创建对象
删除对象
。。。不存在返回not found。。。
这里我第一次没有加末尾斜杠,加上后删除了两次出现这个结果
修改对象
Django-DRF 自定义函数
Django为视图提供了数个装饰器,用以支持相关的HTTP服务。django.views.decorators.http 包里的装饰器可以基于请求的方法来限制对视图的访问。若条件不满足会返回 django.http.HttpResponseNotAllowed
如何使用
导入action
from rest_framework.decorators import action或者
from django.contrib.admin import action
@action
是 Django REST framework 中的一个装饰器,用于将自定义函数转换为视图集的一个动作。视图集中附加action装饰器可接收两个参数:1. methods: 声明该action对应的请求方式。
2. detail:用于指定该操作是否是详情操作。如果设置为
True
,则表示该操作是详情操作(针对某一具体实例的数据进行的操作,例如获取、创建、更新或删除某一对象),即需要提供主键才能访问该操作;如果设置为False
,则表示该操作不是详情操作,即不需要提供主键即可访问该操作,即表示该动作不需要处理单个对象,而是处理整个集合。默认值为False
。
修改views.py中的GoodsCategoryViewSet类:
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("helllo 你调用了自定义的函数")
@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.")
@action(detail=False, methods=['get','post'])
def create_example(self, request):
name = request.data.get('name')
# 使用create()方法创建新的商品分类对象
created_category = GoodsCategory.objects.create(name)
print("Created category:", created_category)
register()
方法
有两个强制参数:
prefix
- 用于此组路由的URL前缀。viewset
- 处理请求的viewset类。
还可以指定一个附加参数(可选):
basename
- 用于创建的URL名称的基本名称。如果不设置该参数,将根据视图集的queryset
属性(如果有)来自动生成基本名称。注意,如果视图集不包括queryset
属性,那么在注册视图集时必须设置basename
。
这里的queryset属性是指queryset = GoodsCategory.objects.all(),设置basename:router.register('GoodsCategory', GoodsCategoryViewSet, 'GoodsCategory')