django ninja api 简明教程
https://eadwincode.github.io/django-ninja-jwt/
https://pypi.org/project/django-ninja-jwt/
中文博客简明教程:https://blog.csdn.net/qq_43373298/article/details/121384656
官网教程(读一遍不费劲,很舒服): https://django-ninja.rest-framework.com/
动手实践了2类api
genera.url.py
from appninja.api import api urlpatterns = [ path('admin/xxzx/', admin.site.urls), path('api/', api.urls),
appninja.api.py
from ninja import NinjaAPI from ninja import Schema api = NinjaAPI() from appninja.api1 import router as router1 from appninja.api2 import router as router2 from appninja.api3 import router as router3 from appninja.api_tree import router as router_tree api.add_router("/api1/", router1) api.add_router("/api2/", router2) api.add_router("/api3/", router3) api.add_router("/apitree/", router_tree) #http://127.0.0.1:8000/api/add?a=1&b=2 @api.get("/add") def add(request, a: int, b: int): return {"result": a + b}
api_tree.py
from ninja import NinjaAPI from ninja import Schema from ninja import Router from django.shortcuts import render, get_object_or_404, redirect from appninja.models import Testig router = Router() api = NinjaAPI() class JgOut(Schema): id: int name: str pid: int class JgIn(Schema): name: str pid: int class Jginout(Schema): id: int =None name: str =None pid: int =None @router.post("/ins_or_upd") def create_employee(request, payload: Jginout): print(payload) if payload.id: testjg = get_object_or_404(Testig, id=payload.id) for attr, value in payload.dict().items(): setattr(testjg, attr, value) testjg.save() else: payload.id=None testjg = Testig.objects.create(**payload.dict()) return {'result': testjg.id } @router.post("/post_del") def post_del_Testig(request, plyload: Jginout): person = get_object_or_404(Testig, id=plyload.id) person.delete() return {"result": 'Success'} #参数必须是pId ,注意大小写,pid不可以形成tree @router.get('/treedict_good') def treedict_good(request): dictdata=Testig.objects.annotate(pId=F('pid')).values('id','pId','name') return list(dictdata)
api_crud.py
from ninja import NinjaAPI api = NinjaAPI() from appninja.models import Employee,Department from datetime import date from ninja import Field, Schema from ninja import UploadedFile, File from django.shortcuts import render, get_object_or_404, redirect class EmployeeIn(Schema): first_name: str last_name: str department_id: int = None birthdate: date = None @api.post("/employees") def create_employee(request, payload: EmployeeIn): employee = Employee.objects.create(**payload.dict()) return {"id": employee.id} @api.post("/employees") def create_employee(request, payload: EmployeeIn, cv: UploadedFile = File(...)): payload_dict = payload.dict() employee = Employee(**payload_dict) employee.cv.save(cv.name, cv) # will save model instance as well return {"id": employee.id} from django.core.files.storage import FileSystemStorage from ninja import UploadedFile, File STORAGE = FileSystemStorage() @api.post("/upload") def create_upload(request, cv: UploadedFile = File(...)): filename = STORAGE.save(cv.name, cv) # Handle things further class EmployeeOut(Schema): id: int first_name: str last_name: str department_id: int = None #None is default,it can display the actual value birthdate: date = None @api.get("/employees/{employee_id}", response=EmployeeOut) def get_employee(request, employee_id: int): employee = get_object_or_404(Employee, id=employee_id) return employee #如果不用employOut,则会 TypeError: Object of type Employee is not JSON serializable 错误 #EmployeeOut自动把object转变为json,并且validate from typing import List #List和list区别不大,主要用于类型注解 @api.get("/employees", response=List[EmployeeOut]) def list_employees(request): qs = Employee.objects.all() return qs #put用于更新 @api.put("/employees/{employee_id}") def update_employee(request, employee_id: int, payload: EmployeeIn): employee = get_object_or_404(Employee, id=employee_id) for attr, value in payload.dict().items(): setattr(employee, attr, value) employee.save() return {"success": True} @api.delete("/employees/{employee_id}") def delete_employee(request, employee_id: int): employee = get_object_or_404(Employee, id=employee_id) employee.delete() return {"success": True} class TaskSchema(Schema): id: int title: str # The first Field param is the default, use ... for required fields. completed: bool = Field(..., alias="is_completed") owner_first_name: str = Field(None, alias="owner.first_name") #It is also possible to return regular django http responses: from django.http import HttpResponse from django.shortcuts import redirect @api.get("/http") def result_django(request): return HttpResponse('some data') # !!!! @api.get("/something") def some_redirect(request): return redirect("/some-path") # !!!!
效果1 api_tree
效果2 api_crud
特点总结:
1、遇到问题,看 http://127.0.0.1:8000/api/docs ,查看api是否存在
2、遇到api错误 不要慌,基本就是以下原因
(1)api的methon错误,如get api,html端用post请求
(2)请求端的参数,与api参数不匹配,建议用schema
(3)路径错误,api找不到
(4)api逻辑端,queryset错误,如get_object_or_404返回404错误
3、建议使用router,不论多简单,可以划分文件 api1.py, api2.py,可以划分请求路径, 用不用router的特殊区别 注意以下红字
#不用route
@api.get("/add") def add(request, a: int, b: int): return {"result": a + b} #用route @router.get('/treedict_good') def treedict_good(request): dictdata=Testig.objects.annotate(pId=F('pid')).values('id','pId','name') return list(dictdata)
4、一切都可以用get+post搞定,不用路径参数,post提交必须用schema
(1) crud例子:参考了官网crud的例子,提现了resuful : 用put \delete\get\post等各种method,还用了路径参数 delete/{id}
缺点:不统一,容易引发错误
(2)tree的例子:一切用get+post搞定,传递参数就用schema,(in、out、inout )
优点:统一、代码容易复制,方便记忆