rest_framework_mongoengine实现后端增删改查
一、增删改查
1. 继承ModelViewSet实现增删改查
- 父urls.py
path("api/testapp/", include("apps.testapp.urls")), # 测试
- 子urls.py
# -*- coding: utf-8 -*-
from django.urls import path
from rest_framework_mongoengine.routers import SimpleRouter
from apps.testapp.views import TestView, ProductViewSet
urlpatterns = [
# 测试接口
...
]
model_mango_url = SimpleRouter()
model_mango_url.register(r'product', ProductViewSet)
urlpatterns += model_mango_url.urls
print("urlpatterns============", urlpatterns)
- models.py
from django.db import models
# Create your models here.
from mongoengine import Document, fields
class Product(Document):
name = fields.StringField(required=True)
description = fields.StringField()
price = fields.StringField()
- serializer.py
from rest_framework import serializers
from rest_framework_mongoengine.serializers import DocumentSerializer
from apps.testapp.models import Product
class ProductSerializer(DocumentSerializer):
# 序列化的是后更改了name字段 required=False
name = serializers.CharField(required=False)
class Meta:
model = Product
fields = '__all__'
- views.py
from django.http import JsonResponse
from django.shortcuts import render
# Create your views here.
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.views import APIView
from rest_framework_mongoengine.viewsets import ModelViewSet
from apps.testapp.models import Product
from apps.testapp.serializers import ProductSerializer
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
1.1 创建(create)
1.新增单个
POST {{ipaddr}}api/testapp/product/
{
"name":"iphone14",
"description":"十分骄傲了就是佛爱事件的发生",
"price":"12"
}
2.批量插入
- urls.py
urlpatterns = [
# 批量插入
path(r'product/create', ProductViewSet.as_view({'post': 'create_many'})),
]
- views.py
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
# 如果重写的是create方法,那么之前的创建单个资源,也会走这个方法,所以为了区分,保留之前的单个字典插入,这里命名craete_many
def create_many(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data, many=True)
if serializer.is_valid():
products = [Product(**item) for item in serializer.validated_data]
Product.objects.insert(products)
return Response(serializer.validated_data, status=201)
return Response(serializer.errors, status=400)
- 测试
POST {{ipaddr}}api/testapp/product/create
[
{
"name": "iphone16",
"description": "十分骄傲了就是佛爱事件的发生",
"price": "12"
},
{
"name": "iphone17",
"description": "十分骄傲了就是佛爱事件的发生",
"price": "12"
},
{
"name": "iphone18",
"description": "十分骄傲了就是佛爱事件的发生",
"price": "12"
}
]
1.2 读取(read)
1.获取所有列表 list
GET {{ipaddr}}api/testapp/product/
说明:底层使用的list方法
2.获取单个详情 retrieve
GET {{ipaddr}}api/testapp/product/660cbeb432362db8ac968ee9/
说明:底层使用的是retrieve
3.分页查询
GET {{ipaddr}}api/testapp/product?page=2&limit=2
- settings.py
REST_FRAMEWORK = {
...
"DEFAULT_PAGINATION_CLASS": "dvadmin.utils.pagination.CustomPagination", # 自定义分页
...
}
- pagination.py
# -*- coding: utf-8 -*-
from collections import OrderedDict
from django.core import paginator
from django.core.paginator import Paginator as DjangoPaginator, InvalidPage
from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response
class CustomPagination(PageNumberPagination):
page_size = 10
page_size_query_param = "limit"
max_page_size = 999
django_paginator_class = DjangoPaginator
def paginate_queryset(self, queryset, request, view=None):
"""
Paginate a queryset if required, either returning a
page object, or `None` if pagination is not configured for this view.
"""
empty = True
page_size = self.get_page_size(request)
if not page_size:
return None
paginator = self.django_paginator_class(queryset, page_size)
page_number = request.query_params.get(self.page_query_param, 1)
if page_number in self.last_page_strings:
page_number = paginator.num_pages
try:
self.page = paginator.page(page_number)
except InvalidPage as exc:
# msg = self.invalid_page_message.format(
# page_number=page_number, message=str(exc)
# )
# raise NotFound(msg)
empty = False
if paginator.num_pages > 1 and self.template is not None:
# The browsable API should display pagination controls.
self.display_page_controls = True
self.request = request
if not empty:
self.page = []
return list(self.page)
def get_paginated_response(self, data):
code = 2000
msg = 'success'
page = int(self.get_page_number(self.request, paginator)) or 1
total = self.page.paginator.count if self.page else 0
limit = int(self.get_page_size(self.request)) or 10
is_next = self.page.has_next() if self.page else False
is_previous = self.page.has_previous() if self.page else False
if not data:
code = 2000
msg = "暂无数据"
data = []
return Response(OrderedDict([
('code', code),
('msg', msg),
('page', page),
('limit', limit),
('total', total),
('is_next', is_next),
('is_previous', is_previous),
('data', data)
]))
4.根据name模糊查询 list
重写list方法,最好不要重写retrieve方法,二者区别如下:
获取所有列表 底层使用list方法:api/product/
获取单个资源 底层使用retrieve:api/product/123456789/ # 数字是id因此,如果重写retrieve方法,那么传递参数的时候如果再拼接api/product/name/ 底层识别路径参数的时候不容易区分是name还是id;
- views.py
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def list(self, request, *args, **kwargs):
"""
重写list方法,根据name字段模糊查询,获取所有列表也是走这个方法
"""
# request.query_params.get('name') 这种方式接受参数 url格式为:/product/?name=apple;
# kwargs.get("name") # 这种方式接受参数 url格式:/product/<str:name>/
name = request.query_params.get('name')
if name:
product = Product.objects.filter(name__icontains=name)
serializer = self.get_serializer(product, many=True)
return Response(serializer.data)
else:
print("list方法 获取所有列表============")
return super().list(request, *args, **kwargs)
- 测试
# 根据name模糊查询
GET {{ipaddr}}api/testapp/product/?name=iphone18
# 查询所有
GET {{ipaddr}}api/testapp/product/
5.多条件查询 list
重写list方法
- views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.views import APIView
from rest_framework_mongoengine.viewsets import ModelViewSet
from apps.testapp.models import Product
from apps.testapp.serializers import ProductSerializer
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def list(self, request, *args, **kwargs):
"""
重写list方法,根据name字段模糊查询,获取所有列表也是走这个方法
"""
# request.query_params.get('name') 这种方式接受参数 url格式为:/product/?name=apple;
# kwargs.get("name") # 这种方式接受参数 url格式:/product/<str:name>/
params = request.query_params
name = params.get('name')
price = params.get('price')
# 根据查询参数过滤 queryset
queryset = Product.objects.all()
if name:
queryset = queryset.filter(name__icontains=name)
if price:
queryset = queryset.filter(price=price)
# 序列化查询结果,并返回响应
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
- 测试
GET {{ipaddr}}api/testapp/product/?name=iphone18&price=136
6.返回部分字段
- views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.views import APIView
from rest_framework_mongoengine.viewsets import ModelViewSet
from apps.testapp.models import Product
from apps.testapp.serializers import ProductSerializer
class TestView(APIView):
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def list(self, request, *args, **kwargs):
"""
重写list方法,根据name字段模糊查询,获取所有列表也是走这个方法
"""
# request.query_params.get('name') 这种方式接受参数 url格式为:/product/?name=apple;
# kwargs.get("name") # 这种方式接受参数 url格式:/product/<str:name>/
params = request.query_params
name = params.get('name')
price = params.get('price')
queryset = Product.objects.all()
if name:
queryset = queryset.filter(name__icontains=name)
if price:
queryset = queryset.filter(price=price)
# 定义一个包含部分字段的新序列化器
class PartialProductSerializer(ProductSerializer):
class Meta(ProductSerializer.Meta):
fields = ('name', 'price')
# 序列化查询结果,并返回响应
serializer = PartialProductSerializer(queryset, many=True)
return Response(serializer.data)
- 测试
GET {{ipaddr}}api/testapp/product/?name=iphone18&price=136
[
{
"name": "iphone18",
"price": "136"
}
]
7.排序查询
- views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from rest_framework.views import APIView
from rest_framework_mongoengine.viewsets import ModelViewSet
from apps.testapp.models import Product
from apps.testapp.serializers import ProductSerializer
class TestView(APIView):
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
def list(self, request, *args, **kwargs):
"""
重写list方法,根据name字段模糊查询,获取所有列表也是走这个方法
"""
# request.query_params.get('name') 这种方式接受参数 url格式为:/product/?name=apple;
# kwargs.get("name") # 这种方式接受参数 url格式:/product/<str:name>/
params = request.query_params
name = params.get('name')
price = params.get('price')
queryset = Product.objects.all()
if name:
queryset = queryset.filter(name__icontains=name)
if price:
queryset = queryset.filter(price=price)
# 定义一个包含部分字段的新序列化器
class PartialProductSerializer(ProductSerializer):
class Meta(ProductSerializer.Meta):
fields = ('name', 'price')
# queryset = queryset.order_by('price') # 按照price字段升序排序
queryset = queryset.order_by('-price') # 按照price字段降序排序
# 序列化查询结果,并返回响应
serializer = PartialProductSerializer(queryset, many=True)
return Response(serializer.data)
- 测试
GET {{ipaddr}}api/testapp/product/?name=iphone18
[
{
"name": "iphone18",
"price": "436"
},
{
"name": "iphone18",
"price": "166"
},
{
"name": "iphone18",
"price": "136"
},
{
"name": "iphone18",
"price": "12"
}
]
1.3 更新(update)
1.修改单个
PUT {{ipaddr}}api/testapp/product/660cc1ce799f2e1df6778875/
{
"price":"15999"
}
2.批量修改
举例:批量修改name="iphone14"的数据,price更新为1300
- views.py
# Create your views here.
from rest_framework.response import Response
from rest_framework.decorators import api_view, action
from rest_framework.views import APIView
from rest_framework_mongoengine.viewsets import ModelViewSet
from apps.testapp.models import Product
from apps.testapp.serializers import ProductSerializer
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
"""
@action说明:
methods:一个列表,包含允许的 HTTP 方法。例如,['get', 'post'] 表示这个动作既允许 GET 请求也允许 POST 请求。
detail:一个布尔值,指示这个动作是否适用于单个实例。如果设置为 True,则动作的 URL 将包含一个实例的主键,例如 /products/1/batch_update/。
如果设置为 False,则动作的 URL 不包含实例的主键,例如 /products/batch_update/。
"""
@action(methods=['post'], detail=False)
def batch_update(self, request):
# 获取请求的数据
data = request.data
# 确保请求的数据中包含了需要更新的名称和价格
if 'name' in data and 'price' in data:
# 获取要更新的名称和价格
name_to_update = data['name']
new_price = data['price']
# 执行批量更新操作
updated_count = Product.objects.filter(name=name_to_update).update(price=new_price)
# 返回更新结果
return Response(
{'message': f'Updated {updated_count} products.', 'name': name_to_update, 'new_price': new_price})
else:
# 如果请求的数据不完整,返回错误信息
return Response({'error': 'Name and price fields are required.'}, status=400)
- 测试
POST {{ipaddr}}api/testapp/product/batch_update/
{
"name":"iphone14",
"price":"1300"
}
1.4 删除(Delete)
1.删除单个资源
DELETE {{ipaddr}}api/testapp/product/660cbeb432362db8ac968ee9/
2.批量删除
- views.py
from django.http import JsonResponse
from django.shortcuts import render
# Create your views here.
from rest_framework.response import Response
from rest_framework.decorators import api_view, action
from rest_framework.views import APIView
from rest_framework_mongoengine.viewsets import ModelViewSet
from apps.testapp.models import Product
from apps.testapp.serializers import ProductSerializer
class ProductViewSet(ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
@action(methods=['post'], detail=False)
def batch_delete(self, request):
# 获取请求的数据
data = request.data
# 确保请求的数据中包含了需要删除的名称
if 'name' in data:
# 获取要删除的名称
name_to_delete = data['name']
# 执行批量删除操作
deleted_count = Product.objects.filter(name=name_to_delete).delete()
# 返回删除结果
return Response({'message': f'Deleted {deleted_count} products.', 'name': name_to_delete})
else:
# 如果请求的数据不完整,返回错误信息
return Response({'error': 'Name field is required.'}, status=400)
- 测试
POST {{ipaddr}}api/testapp/product/batch_delete/
{
"name":"iphone19"
}