参考:
---------------------------------------------------------------------------------------------------------------------------------
py 写抽象方法的技巧:方法抛异常,(子类实现就使用会报异常)或者用@abstractmethod
coreapi 在新文档 【DRF配置管理】如何建立coreapi风格接口文档-CSDN博客
fbv cbv GenericAPIView (通用视图) ViewSet ,装饰器
---------------------------------------------------------------------------------------------------------------------------------
一,View类
django 自带的类,自带crud操作(rest风格) ,只能接受urlencoded 传参。
二,ApiView类
1,介绍
drf 里的类,继承View 类,改写了as_view() 和 dispatch() 方法,可以接受json传参,(可以配置认证,鉴权)。
a,xxxView :get() 列表查询,post() 新增;
b,xxxDetailView:get() 单记录查询,delete() 删除单条,put() 单条更新
c,简单序列器:serialiazers.serialiazer :
要自己写属性,重写create、update() 方法才能save()。
d,增强序列化器 serialiazers.ModelSerialiazer
作用: 序列化(instance)和反序列化(data),校验属性(序列化类的属性参数)
不用自已写属性,create,update()方法
2,路由和接口:
a, path ("api/xxx",views.xxxView.as_view())
b, re_path("api/xxx/(\d+)",views.xxxDetailView.as_view())
c, 取参:request.data
d, 序列化:xxxSerialiazers (instance=)
e, 校验:xxxSerialiazers.is_vaild()
f, 业务逻辑:
g,返回:respose() ,respose(serialiazer.data),respose(serialiazer.errers)
三,GenericAPIView 通用试图类
1,介绍
只需改变 querySet 和 serializer_class 属性 ,方法所有view,detailView 通用(方法与变量解耦了)。因为GenericAPIView 继承APIView ,增加了querySet ,serializer_class ,调度的4个相关方法。
2,路由和接口:
a,路由:
path ("api/xxx",views.xxxView.as_view())
re_path("api/xxx/(?P<pk>\d+)",views.xxxDetailView.as_view())
b,属性:
querySet = xxx.Objects.all()
serializer_class = xxxSerializers
class xxxSerialiazers(serialiazers.ModelSerialiazer):
class Meta:
model = xxx;
fields = "__all__"
c,接口类
class xxxView(GenericAPIView):
def get(self,request):
pass
def pust(self,request):
pass
class xxxDetailView(GenericAPIView):
def delete(self,request):
pass
def put(self,request):
pass
def get(self,request):
pass
四,ViewSet
1 .介绍,
yyyyMixin 5个混合类
ViewSet主要通过继承ViewSetMixin来实现在调用as_view()时传入字典{“http请求”:“视图方法”}的映射处理工作,如{‘get’:’list’},重写as_view(),可以传参数了。
(view,APIView,Generic,混合类, 按请求方法get,put,post..自动路由)
2,路由和接口:
a,路由
from django.urls import path, re_path
from vset.views import BookView
urlpatterns = [
# path("set", views.BookView.as_view({"http请求":"视图方法"})),
path("books/", BookView.as_view({
"get": "get_all_book",
"post": "add_book"
})),
re_path("^books/(?P<pk>\d+)$", BookView.as_view({
"get": "get_one_book",
"put": "edit_book",
"delete": "delete",
})),
]
b,视图类
from rest_framework import serializers
from rest_framework import status
from rest_framework.response import Response
from rest_framework.viewsets import ViewSet
from sers.models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = "__all__"
class BookView(ViewSet):
def get_all_book(self, request):
books = Book.objects.all()
bs = BookSerializer(instance=books, many=True)
return Response(bs.data)
def add_book(self, request):
bs = BookSerializer(data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def get_one_book(self, request, pk):
book = Book.objects.get(pk=pk)
bs = BookSerializer(instance=book)
return Response(bs.data)
def edit_book(self, request, pk):
instance = Book.objects.get(pk=pk)
bs = BookSerializer(instance=instance, data=request.data)
if bs.is_valid():
bs.save()
return Response(bs.data)
else:
return Response(bs.errors)
def delete(self, request, pk):
Book.objects.get(pk=pk).delete()
return Response(status=status.HTTP_204_NO_CONTENT)
五,GenericViewSet 分发逻辑
class xxxView(GenericViewSet, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin):
from django.urls import path, re_path
from vset.views import BookView
urlpatterns = [
# path("set", views.BookView.as_view({"http请求":"视图方法"})),
path("books/", BookView.as_view({
"get": "list",
"post": "create"
})),
re_path("^books/(?P<pk>\d+)$", BookView.as_view({
"get": "retrieve",
"put": "update",
"delete": "delete",
})),
]
GenericViewSet ,分发逻辑
不带pk:
ListModelMixin,列表查询 get
CreateModelMixin:单条新增 post
带pk:
RetrieveModelMixin:单条查询 get
UpdateModelMixin :单条更新 put
DestroyModelMixin:单条删除 delete
六,ModelViewSet() 终极版
继承 GenericViewSet, ListModelMixin, CreateModelMixin, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin,
七,注册路由
参考:自动生成路由_router.register_GG_Bonin的博客-CSDN博客
router.register('book', BookView, base_name='book')
detail: pk有关,默认是False, 控制生成的路由是:/user/login还是/user/pk/login
代替
path("books/", BookView.as_view({
"get": "list",
"post": "create"
})),
re_path("^books/(?P<pk>\d+)$", BookView.as_view({
"get": "retrieve",
"put": "update",
"delete": "delete",
})),
八,查询:
在Django中,Q对象用于构建复杂的查询条件,可以处理多个查询条件的组合和嵌套。Q对象可以使用位运算符(&、|、~)来表示逻辑运算符(AND、OR、NOT)。
1,django orm 的查询
下面是一些常见的Q对象的用法:
-
导入Q对象:
python复制代码
from django.db.models import Q |
-
使用Q对象构建查询条件:
python复制代码
# 单个查询条件 | |
query = Q(name='John') | |
# 多个查询条件的组合 | |
query = Q(name='John') & Q(age__gt=20) | |
# 嵌套查询条件 | |
query = Q(name='John') | (Q(age__gt=20) & Q(gender='M')) |
-
在查询中使用Q对象:
python复制代码
from django.db.models import Q | |
from myapp.models import MyModel | |
# 构建查询条件 | |
query = Q(name='John') | (Q(age__gt=20) & Q(gender='M')) | |
# 使用查询条件进行过滤 | |
results = MyModel.objects.filter(query) |
上述示例中,我们导入了Q对象,并使用它来构建了一个复杂的查询条件。我们将Q对象传递给filter()
方法,它将返回满足条件的模型实例列表。
2,原生查询
参考:百度安全验证
在Django执行原生SQL有以下三种方式
a,extra:Entry.objects.extra(select={'is_recent': "pub_date > '2006-01-01'"})
django ORM之 extra() 函数 - 简书 Django不通过外键实现多表关联查询-阿里云开发者社区
'''
需求
不通过外键,使用django orm语法实现多个表之间的关联查询,类似如下sql的查询效果:
SELECT tb_project_version.*, tb_sprint.name, tb_project.name
FROM tb_project_version
JOIN tb_sprint ON tb_sprint.id=tb_project_version.sprint_id
JOIN tb_project ON tb_project.id=tb_project_version.project_id
'''
#数据表Model设计
class Sprint(models.Model):
id = models.AutoField(primary_key=True, verbose_name='自增id')
name = models.CharField(max_length=50, verbose_name='迭代名称')
...略
class Meta:
db_table = 'tb_sprint'
verbose_name = '产品迭代表'
verbose_name_plural = verbose_name
class Project(models.Model):
id = models.AutoField(primary_key=True, verbose_name='自增id')
name = models.CharField(max_length=50, verbose_name='项目名称')
...略
class Meta:
db_table = 'tb_project'
verbose_name = '项目表'
verbose_name_plural = verbose_name
class ProjectVersion(models.Model):
id = models.AutoField(primary_key=True, verbose_name='自增id')
name = models.CharField(max_length=50, verbose_name='版本名称')
project_id = models.IntegerField(verbose_name='关联的项目ID')
sprint_id = models.IntegerField(verbose_name='关联的迭代ID')
...略
class Meta:
db_table = 'tb_project_version'
verbose_name = '项目版本表'
verbose_name_plural = verbose_name
class ProjectVersionListAPIView(APIView):
'''
项目视图-版本管理
'''
# 查询列表数据
def get(self, request, format=None):
result = {}
try:
params = request.GET
page_size = int(params.get('pageSize'))
page_no = int(params.get('pageNo'))
name = params.get('name')
project_id = params.get('projectId')
sort = params.get('sort')
if sort:
sort_list = sort.split(',')
else:
sort_list = ['-id']
startIndex = (page_no - 1) * page_size
endIndex = startIndex + page_size
filters = {'is_delete':0}
if name:
filters['name__startswith'] = name
if project_id:
filters['project_id'] = project_id
projectVersions = Project.objects.filter(**filters).extra(
select={'project:'tb_project.name',
'sprint':' tb_sprint.name',
tables=['tb_project', 'tb_sprint'],
where=['tb_project.id=tb_project_version.project_id', 'tb_sprint.id =tb_project_version.sprint_id']),
rows = projectVersions.order_by(*sort_list)[startIndex:endIndex]
rows = ProjectVersionSerializer(rows, many=True).data
total = projectVersions.count()
projectVersions.order_by(*sort_list)[startIndex:endIndex]
rows = ProjectVersionSerializer(rows, many=True).data
total = projectVersions.count()
result['msg'] = '获取成功'
result['success'] = True
result['data'] = {}
result['data']['rows'] = rows
result['data']['total'] = total
return Response(result, status.HTTP_200_OK)
except Exception as e:
result['msg'] = '%s' % e
result['success'] = False
return Response(result, status.HTTP_500_INTERNAL_SERVER_ERROR)
b,raw :返回模型对象
c,django connection 返回 【精选】django使用原生SQL查询数据库_django 原生sql-CSDN博客
# 工具类
def dictfetchall(cursor):
"Return all rows from a cursor as a dict"
columns = [col[0] for col in cursor.description]
return [
dict(zip(columns, row))
for row in cursor.fetchall()
]
sql = "select * from student "
from django.db import connection
from common.utils import dictfetchall
cursor = connection.cursor()
cursor.execute(sql)
results = dictfetchall(cursor) # 列表套字典
更新
@action(methods=['post'], detail=False, permission_classes=[IsPermittedOperator])
def get_rec_total(self, request):
keyword = request.data.get('keyword')
in_start_at = request.data.get('in_start_at')
in_end_at = request.data.get('in_end_at')
out_start_at = request.data.get('out_start_at')
out_end_at = request.data.get('out_end_at')
pay_start_at = request.data.get('pay_start_at')
pay_end_at = request.data.get('pay_end_at')
color = request.data.get('color')
pay_type = request.data.get('pay_type')
operator_id = request.data.get('operator_id')
from lt_finance.models import AmountOrder
queryset = AmountOrder.objects.all()
if keyword:
queryset = queryset.filter(
Q(vehicle_no__contains=keyword) | Q(out_trade_no__contains=keyword) | Q(parking_info__contains=keyword))
if in_start_at:
queryset = queryset.filter(start_at__gte=in_start_at)
if out_start_at:
queryset = queryset.filter(start_at__lte=out_start_at)
if in_end_at:
queryset = queryset.filter(end_at__gte=in_end_at)
if out_end_at:
queryset = queryset.filter(end_at__lte=out_end_at)
if pay_start_at:
queryset = queryset.filter(pay_at__gte=pay_start_at)
if pay_end_at:
queryset = queryset.filter(pay_at__lte=pay_end_at)
if color:
queryset = queryset.filter(color=int(color))
if pay_type:
queryset = queryset.filter(pay_type=int(pay_type))
if operator_id:
queryset = queryset.filter(operator_id=int(operator_id))
if not request.user.is_superuser:
queryset = queryset.filter(operator_id=request.user.account.operator_id)
amount = queryset.aggregate(sum=Sum('amount'))['sum'] or 0
return Response(data=amount)
九,更新
1 单条更新
#获取要更新的对象
obj = MyModel.objects.get(id=1)
# 更新数据
obj.field1 = 'new value'
obj.field2 = 'another value'
obj.save()
2 单条更新
批量更新数据
MyModel.objects.filter(name='John').update(status='active')
3 使用原始SQL更新数据
Django的ORM框架提供了`raw()`方法来执行原始SQL语句。例如:
from django.db import connection
# 执行原始SQL更新数据
with connection.cursor() as cursor:
cursor.execute("UPDATE myapp_mymodel SET field1='new value' WHERE id=1")
```
这段代码使用`connection.cursor()`方法获取数据库连接的游标对象,然后执行原始SQL语句来更新`MyModel`模型类中`id`为1的对象的`field1`字段。
4. 使用表单更新数据
在Django中,我们还可以使用表单来更新数据库中的数据。表单可以提供一个用户友好的界面来输入数据