django 之(一) --- DjangoRestFormwork
接口概念
IOP:面向接口编程,不再关注具体的实现;只关注输入、输出。
http://www.ruanyifeng.com/blog/2018/10/restful-api-best-practices.html
服务器返回数据类型:
网页数据html,为浏览器使用
Json数据,ajax javascript发请求的一种方式;也可以使用request的python请求方式
为移动端编写接口关注:
接口地址是什么:/xxx/yyy/zzz
接口需要什么参数:参数根据业务场景
返回什么格式的数据:大多数是json数据
RestfulAPI:
一种软件架构风格、设计风格、而不是标准,只是提供了一组设计原则和约束条件。它主要用户客户端和服务器交互类的软件。
基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存机制等。REST全程是Representational State Transfer,表征性状态转移。
首次在2000年Roy Thomas Fielding的博士论文中出现,Fielding是一个非常重要的人,他是HTTP协议(1.0版和1.1版)的主要设计者,
Apache服务器软件的作者之一,Apache基金会的第一任主席。所以,他的这篇论文一经发表,就引起了广泛的关注。
理解Rest-Formwork
介绍:https://github.com/RockTeach/PythonCourse/blob/master/web/flask/restful.md
要理解RESTful架构,最好的就是去理解它的单词 Representational State Transfer 到底是什么意思,它的每一个词到底要表达什么。
REST的释义,"(资源的)表现层状态转化",其实这省略了主语。“表现层”其实指的是“资源(Resource)”的“表现层”。
状态码
服务器向用户返回的状态码和提示信息,常见的有以下一些地方
- 200:OK - [GET]:服务器成功返回用户请求的数据
- 201:CREATED -[POST/PUT/PATCH]:用户新建或修改数据成功
- 202:Accepted - [*] :表示一个请求已经进入后台排队(异步任务)
- 204:NO CONTENT - [DELETE]:表示数据删除成功
- 400:INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误
- 401:Unauthorized - [*] :表示用户没有权限(令牌,用户名,密码错误)
- 403:Forbidden - [*]:表示用户得到授权,但是访问是被禁止的
- 404:NOT FOUND - [*]:用户发出的请求针对的是不存在的记录
- 406:Not Acceptable - [*]:用户请求格式不可得
- 410:Gone - [GET] :用户请求的资源被永久移除,且不会再得到的
- 422:Unprocesable entity -[POST/PUT/PATCH]:当创建一个对象时,发生一个验证错误
- 500:INTERNAL SERVER EROR - [*] :服务器内部发生错误
资源(Resource)
所谓“资源”,就是网络上的一个实体,或者说是网络上的一个具体信息。它可以是一段文本,一张图片,一首歌曲,一种服务,总之就是一个具体的实例。
你可以使用一个URI(统一资源定位符)指向它,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以了,因此URI就成了每一个资源的地址或独一无二的识别符。
所谓“上网”就是与互联网上一系列的“资源”互动,调用它们的URI。
表现层(Representation)
“资源”是一种信息实体,它可以有多种外在表现形式。我们把“资源”具体呈现出来的形式,叫做它的”表现层“(Representation)。
URI只代表资源的实体,不代表它的形式。严格地说,有些网站最后的”.html“后缀名是不必要的,因为这个后缀表示格式,属于”表现层“范畴,而URI应该只代表”资源“的位置。
它的具体表现形式,应该在HTTP请求头的信息中使用Accept和Content-Type字段指定。
状态转换(State Transfer)
访问一个网站,就代表客户端和服务端的一个互动过程。在这个过程中,势必涉及到数据和状态的变化。
互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务端。
因此,如果客户端想要操作服务器,就必须通过某种手段,让服务器端发生”状态转换(State Transfer)“。
而这种转换是建立在表现层之上的,所以就是”表现层状态转化“。
客户端用到的手段,只能是HTTP协议。具体来说,就是HTTP协议中,四个表示操作方式的动词:GET,POST,PUT,DELETE。
它们分别对应四种基本操作:GET用来获取资源,POST用来新建资源(也可用于更新资源),PUT用来更新资源,DELETE用来删除资源
总结 :
- 每一个URI代表一种资源
- 客户端和服务器之间,传递这种资源的某种表现层
- 客户端通过四个HTTP动词,对服务端资源进行操作,实现”表现层状态转换“
- 同一个url针对用户的不同的请求操作,表现出来的状态是不同的。表现出来的多种形式,就是表现层状态转换。
RESTful是软件架构设计思想。使用在CS,客户端和服务端这种架构模型中。
表现层状态转换
主语 (资源)
URI 每个URI代表一种资源
资源展现给我们的形式就叫做表现层
通过HTTP的请求谓词来实现表现层转换
重要概念
URI、HTTP请求谓词、JSON
注意:
postman/前端 在向服务器提交json数据时,需要声明提交的类型。
在postman的请求的headers增加content-type:application/json。
flask 在确认请求数据是通过json提交后,会将json字符产转换成 字典。保存在request.json中
函数视图:FBV(function base views); 类视图:CBV(class base views)
图示:
- 前后端统一开发
- 前后端分离开发
FBV简单体验:由源码中的dispatch进行各请求分发
- api/urls.py
from django.conf.urls import url
from API import views urlpatterns = [
url(r'^books/$', views.books, name='books'),
url(r'^books/(?P<bookid>\d+)/', views.book, name='book'),
]
- api/models.py
from django.db import models class Book(models.Model):
b_name = models.CharField(max_length=32)
b_price = models.FloatField(default=1) def to_dict(self):
return {'id': self.id, 'b_name': self.b_name, 'b_price': self.b_price}
- api/views.py [选中此文件,右键--> Refactor-->Convert To Python Package 将其变成一个包文件] [from .BookModel import Book 导入到在此包文件中的init.py文件]
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from API.models import Book @csrf_exempt # 进行csrf豁免
def books(request):
# get 获取书
if request.method == "GET":
book_list = Book.objects.all()
book_list_json = []
for book in book_list:
book_list_json.append(book.to_dict())
data = {
'status': 200,
'msg': 'ok',
'data': book_list_json
}
return JsonResponse(data=data)
# post 创建书
elif request.method == "POST":
b_name = request.POST.get('b_name')
b_price = request.POST.get('b_price')
book = Book()
book.b_name = b_name
book.b_price = b_price
book.save()
data = {
'status': 201,
'msg': 'add success',
'data': book.to_dict()
}
return JsonResponse(data=data, status=201) # 注意: 在pycahrm工具栏:Tools ---> HTTP Client ---> Test RESTful web server 进行模拟请求。亦可HTTPie和Postman @csrf_exempt
def book(request, bookid):
# get 带参数获取某一本书
if request.method == "GET":
book_obj = Book.objects.get(pk=bookid)
data = {
'msg': 'ok',
'status': 200,
'data': book_obj.to_dict()
}
return JsonResponse(data=data)
# delete 带参数删除某一个书
elif request.method == "DELETE":
book_obj = Book.objects.get(pk=bookid)
book_obj.delete()
data = {
'msg': 'delete success',
'status': 204, # 前端看到的状态码
# 'data': {} 如果某个对象删除后没有数据了,有默认值就返回对应的数据类型格式,否则前端不知如何解析
}
return JsonResponse(data=data, # status=204) # status=204 设置真正的网络传输状态码204,舍弃响应体中的内容
- books.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>BookList</title>
<script type="text/javascript" src="/static/js/jquery.js"></script>
<script type="text/javascript">
$(function () {
// $("button").click(function () {
$.getJSON("/api/books/", function (data) {
console.log(data);
if (data['status'] === 200){
var $ul = $("ul");
var books = data['data'];
for(var i=0; i < books.length; i++){
var $li = $("<li></li>");
$li.html(books[i]['b_name']);
$li.appendTo($ul);
}
}
})
// })
}) </script>
</head>
CBV简单体验:由源码中的dispatch进行各请求分发
- urls.py
from django.contrib import admin
from django.urls import path
from user.views import UserView, RegisterView urlpatterns = [
path('admin/', admin.site.urls),
path('register/', RegisterView.as_view(), name='register'),
path('user/<int:uid>', UserView.as_view(), name='user'),
]
- views.py
# Create your views here.
from django.http import HttpResponse
from django.views import View 6 # 用FBV
7 def indexs(request):
8 return HttpResponse('基础流程') # 用CRF: 实现登陆注册
class RegisterView(View):
# 用户登陆
def get(self, request):
pass
# 用户注册
def post(self, request):
pass # 用CRF: get post put patch delete
class UserView(View):
# 请求get,获取信息
def get(self, request, uid):
pass
# 提交post,添加信息
def post(self, request, uid):
pass
# 修改put,全部修改
def put(self, request, uid):
pass
# 修改patch,差量修改
def patch(self, request, uid):
pass
# 删除delete,删除操作
def delete(self, request, uid):
pass
使用:
- urls.py 只能接收已经存在的属性作为参数
from django.conf.urls import url
from CBV import views urlpatterns = [
url(r'^hello/', views.HelloCBV.as_view(msg='Sleeping'), name='hello'),
# as_view(msg)中的参数msg(变量名),只能接收此路由对应的类视图中已经存在的属性作为参数
]
- views.py
from django.http import HttpResponse
from django.views import View class HelloCBV(View): msg = None # 类视图中只有设置了此msg属性,路由中as_view(msg)中的变量名msg才能接收到并生效(名字要对应好)
def get(self, request):
return HttpResponse("hahaha %s" % self.msg)
def post(self, request):
return HttpResponse("POST 666")
def put(self, request):
return HttpResponse("PUT 666")
Api接口 CBV方式 利用在模型中定义[对象转字典]的类方法 来简单实现
- urls.py
from django.contrib import admin
from django.urls import path
from user.views import UserView urlpatterns = [
path('user/<int:uid>', UserView.as_view(), name='user'),
]
- models.py
from django.db import models class User(models.Model):
username = models.CharField(max_length=20, unique=True, verbose_name='用户名')
password = models.CharField(max_length=128, verbose_name='密码') class Meta:
db_table = 'user'
verbose_name = '用户表'
verbose_name_plural = verbose_name def __str__(self):
return self.username
def to_dict(self): # 在模型中定义类方法,实现模型对象的序列化,转为字典形式
return {'id': self.id, 'username': self.username, 'password': self.password}
- views.py
from django.http import JsonResponse
from django.views import View
from user.models import User class UserView(View):
def get(self, request, uid):
user = User.objects.get(pk=uid)
return JsonResponse({'status': 200, 'user': user.to_dict()})
# 在模型中定义类方法,实现模型对象的序列化,转为字典形式 def post(self, request, uid):
username = request.POST.get('username')
password = request.POST.get('password')
repassword = request.POST.get('repassword')
if password == repassword:
user = User.objects.create(username=username, password=password)
if user:
return JsonResponse({'status': 200, 'msg': '注册成功'})
return JsonResponse({'status': 200, 'msg': '注册失败'})
Django-Rest-Formwork
安装配置:
- pip install djangorestframework 若使用序列化和类视图继承view或APIView,必须安装此行
- 添加:INSTALLED_APPS = ['user.apps.UserConfig', 'rest_framework', ]在settings.py文件中
初步体验:
- urls.py 请求:某个http://127.0.0.1:8000/groups/2/ 或 某组http://127.0.0.1:8000/groups
from django.conf.urls import url, include
from rest_framework.routers import DefaultRouter
from drf.views import UserViewSet, GroupViewSet # router做了路由注册
router = DefaultRouter()
router.register(r'users',UserViewSet)
router.register(r'groups',GroupViewSet) urlpatterns = [
url(r'^',include(router.urls)),
]
- drf/serializers.py
from django.contrib.auth.models import User, Group
from rest_framework import serializers # HyperlinkedModelSerializer 实现超链接
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User # 系统自带的user
fields = ('url', 'username', 'email', 'groups')
# HyperlinkedModelSerializer 实现超链接
class GroupSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Group # 系统自带的group
fields = ('url', 'name')
- drf/views.py
from django.contrib.auth.models import User, Group
from rest_framework import viewsets
from drf.serializers import UserSerializer, GroupSerializer # 继承自:viewsets.ModelViewSet。对数据集合实现了:get、post
# 本身是一个CBV,也是一个视图集合。 对单个集合实现了:get、post、delete、put、patch封装
class UserViewSet(viewsets.ModelViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer # 继承自:viewsets.ModelViewSet。对数据集合实现了:get、post
# 本身是一个CBV,也是一个视图集合。 对单个集合实现了:get、post、delete、put、patch封装
class GroupViewSet(viewsets.ModelViewSet):
queryset = Group.objects.all()
serializer_class = GroupSerializer
注意:一般不会用这种继承方式,不灵活
序列化器:
- 序列化: 表示将对象转换成可以在IO[网络]中传输的格式如json
- 反序列化:将在IO[网络]中传输的格式[如json]转化为对象的形式。
基本使用1:
- urls.py
from django.conf.urls import url, include urlpatterns = [
url(r'^ser/', include('RestSerializers.urls')),
]
- RestSerializers/urls.py
from django.conf.urls import url
from RestSerializers import views urlpatterns = [
url(r'^persons/', views.PersonView.as_view()),
url(r'^students/', views.StudentView.as_view()),
url(r'^books/', views.books), # FBV
]
- RestSerializers/models.py
from django.db import models class Person(models.Model):
p_name = models.CharField(max_length=32)
p_age = models.IntegerField(default=1)
p_sex = models.BooleanField(default=False) class Student(models.Model):
s_name = models.CharField(max_length=32)
s_age = models.IntegerField(default=1)
- RestSerializers/serializers.py
from rest_framework import serializers
from RestSerializers.models import Person, Student, Book # serialization的子类
"""
模块serializers中
1。Serializer: 手动原生序列化。有创建和更新两个功能
2。ModelSerializer:模型序列化。
3。HyperLinkedModelSerializer:带超链接的模型序列化工具
"""
class PersonSerializer(serializers.Serializer):
# 手动设置需要序列还的字段
id = serializers.IntegerField(read_only=True)
p_name = serializers.CharField(max_length=32)
p_age = serializers.IntegerField(default=1)
p_sex = serializers.BooleanField(default=False) # 实现抽象方法,手动创建对象。validated_data验证过的数据
def create(self, validated_data):
return Person.objects.create(**validated_data) # 实现抽象方法,手动更新对象。validated_data验证过的数据,instance实例
def update(self, instance, validated_data):
instance.p_name = validated_data.get('p_name', instance.p_name) # 没有获取到,给其原有值
instance.p_age = validated_data.get('p_age', instance.p_age)
instance.p_sex = validated_data.get('p_sex', instance.p_sex)
instance.save()
return instance class StudentSerializer(serializers.ModelSerializer):
class Meta:
model = Student
fields = ('s_name', 's_age')
# fields:包含什么字段;exclude:不包含什么字段
- RestSerializers/views.py
from django.http import JsonResponse
from django.views import View
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.views import APIView
from RestSerializers.models import Person, Student
from RestSerializers.serializers import PersonSerializer, StudentSerializer, class PersonView(View): def get(self, request):
persons = Person.objects.all()
# many=True 表示有多个需要序列化转化
person_serializer = PersonSerializer(persons, many=True)
return JsonResponse(person_serializer.data, safe=False) def post(self, request):
p_name = request.POST.get("p_name")
p_age = request.POST.get("p_age")
person = Person()
person.p_name = p_name
person.p_age = p_age
person.save()
person_serializer = PersonSerializer(person)
return JsonResponse(person_serializer.data) class StudentView(APIView): def post(self, request):
s_name = request.POST.get('s_name')
s_age = request.POST.get('s_age')
student = Student()
student.s_name = s_name
student.s_age = s_age
student.save()
student_serializer = StudentSerializer(student)
# 只要类视图继承自APIView,request类型就变成了<class 'rest_framework.request.Request'>
print(type(request))
return JsonResponse(student_serializer.data)
基本使用2:
- urls.py
from django.contrib import admin
from django.urls import path
from user import views urlpatterns = [
path('admin/', admin.site.urls),
path('oneuser/', views.UserViews.as_view(), name='user'),
path('twouser/', views.UserViewsSimple.as_view(), name='user'),
]
- user/models.py
from django.db import models class User(models.Model):
username = models.CharField(max_length=20, unique=True)
password = models.CharField(max_length=128)
phone = models.CharField(max_length=11)
add_time = models.DateTimeField(auto_now=True) class Meta:
db_table = 'user' # 数据库中此模型的表名称 def __str__(self):
return self.username
- user/serializers.py 在此文件内构件序列化类。继承自serializers.Serializer 和 继承自serializers.ModelSerializer
from django.contrib.auth.hashers import make_password
from rest_framework import serializers
from user.models import User # UserSerializer class中的第一部分定义了有哪些字段需要被序列化/反序列化。
# 方法create()和方法update()部分定义了当调用serializer.save()方法时,serializer应该怎样构造实例 # 基础写法。建序列化类,继承自serializers.Serializer
class UserSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True) # read_only=True 只读,不可修改
username = serializers.CharField(max_length=20, min_length=6, required=True) # required=True 必填项
password = serializers.CharField(max_length=128, required=True) # max_lenth = 128 最长是128
phone = serializers.CharField(max_length=11, min_length=11) # min_lenth = 11 最短是11
# -------------------------------------------------------------------------------------------------------#
# UserSerializerSimple继承自ModelSerializer;
# ModelSerializer继承自Serializer;ModelSerializer中重写了BaseSerializer父类中的create()方法
# Serializer继承自BaseSerializer。
# BaseSerializer有save()方法和create()方法。所以UserSerializerSimple就可以调用save()方法 # 简化写法。建序列化类,继承自serializers.ModelSerializer
class UserSerializerSimple(serializers.ModelSerializer):
# 新增需要验证的字段,且数据库中没有此字段。需要write_only=True表示只是在前端验证,不会进到模型中去
repassword = serializers.CharField(max_length=128, write_only=True) class Meta:
model = User
# fields = '__all__' 对所有字段进行校验
# exclude = ('id') 排除不想校验的字段
fields = ['id', 'username', 'password', 'phone','repassword'] # 需要序列化的字段有哪些 # 重写父类方法 验证密码一致。重写父类中的validate进行全局验证。
# attrs是传递来的所有参数的字典形式。如果只验证一个参数,如验证密码长度可以直接把password当作参数
def validate(self, attrs):
if attrs['password'] != attrs['repassword']:
raise serializers.ValidationError('两次密码不相等')
return attrs # 重写父类方法 实现密码加密。重写父类中的create方法。validated_data是
def create(self, validated_data):
username = validated_data['username'] # validated_data父类中的
password = validated_data['password']
phone = validated_data['phone']
password = make_password(password) # 密码加密
user = User.objects.create(username=username, password=password, phone=phone) return user
- user/views.py
from django.contrib.auth.hashers import make_password
from django.http import JsonResponse
from rest_framework.views import APIView
from user.models import User
from user.serializers import UserSerializer, UserSerializerSimple # 基本实现 序列化
class UserViews(APIView): # APIView是View的子类
# get请求
def get(self, request):
pass # post请求 用户注册。http://127.0.0.1:8000/oneuser/
def post(self, request):
username = request.POST.get('username')
password = request.POST.get('password')
phone = request.POST.get('phone') password = make_password(password) # 密码加密
# 1。创建并得到一个用户对象
user = User.objects.create(username=username, password=password, phone=phone)
# 2。放到UserSerializer类中得到一个用户序列化对象。
user_serializer = UserSerializer(user)
# 3。将序列化的数据(json)返回出去。获取序列化中的数据的方法是:序列化类对象名.data(得到序列化之后的数据,打印是字典类型)
return JsonResponse({'status': 200, 'user': user_serializer.data}) #----------------------------------------------------------------------------------------------------------------#
# 简化实现 序列化
class UserViewsSimple(APIView): # APIView是View的子类
# get请求
def get(self, request):
pass
# post请求 用户注册。http://127.0.0.1:8000/twouser/
def post(self, request):
# 1。将前端传递的数据送到Serializer中验证,获取序列化对象。只有在继承自APIView中的子类才可以使用request.data
user_serializer = UserSerializerSimple(data=request.data)
# 2。# 判断前端传来的数据时候是否符合models.py中定义的数据格式要求
if user_serializer.is_valid():
user_serializer.save()
return JsonResponse({'status': 200, 'user': user_serializer.data})
return JsonResponse({'status':400})
总结:
方法:
- user_serializer.is_valid( )
- 序列化类对象.is_valid() :此方法功能是判断传入的数据是否符合models中定义的数据格式要求
- user_serializer.data
- 序列化类对象.data :此方法功能是 将序列化后的数据获取出来
- user_serializer.save()
- 序列化类对象.save() : 此方法功能是 将验证通过的数据存到数据库中
user_serializer.save() 底层save()两个动作create,update
- request.data
- request.data :此方法功能是 获取前端传递来的所有数据。只有类视图继承自APIView父类,才会有此方法
data = JSONParser().parse(request)
注意:
- ModelSerializer需要解决的两个问题:
- 某个字段不属于指定model,它是write_only,需要用户传进来,但我们不能对它进行save( ),因为ModelSerializer是基于Model,这个字段在Model中没有对应属性字段,这个时候我们需要重载validate!write_only与read_only对应。就是用户post过来的数据,后台服务器处理后不会再经过序列化后返回给客户端;最常见的就是我们在使用手机注册的验证码和填写的密码。required: 顾名思义,就是这个字段是否必填,例如要求:用户名,密码等是必须填写的;不填写就直接报错 allow_null/allow_blank:是否允许为NULL/空 。 error_messages:出错时,信息提示。
- 某个字段属于指定model,它是read_only,read_only:True表示不允许用户自己上传,只能用于api的输出。如果某个字段设置了read_only=True,那么就不需要进行数据验证,只会在返回时,将这个字段序列化后返回,举个简单的例子:在用户进行购物的时候,用户post订单时,肯定会产生一个订单号,而这个订单号应该由后台逻辑完成,而不应该由用户post过来,如果不设置read_only=True,那么验证的时候就会报错。再例如,我们在网上购物时,支付时通常会产生支付状态,交易号,订单号,支付时间等字段,这些字段都应该设置为read_only=True,即这些字段都应该由后台产生然后返回给客户端;
- write_only:前端必须传递过来,但是序列化时不被序列化
- read_only: 前端必须传递过来,但是序列化的时候会自动给出
补充:
- 新建的app包文件,需要调用models.py,生成迁移文件时,必须要将app包文件注册到settings.py文件中。
- 如果只是调用路由和视图函数文件,不需要models文件时,不注册新建的app包文件在settings.py也没关系
django 之(一) --- DjangoRestFormwork的更多相关文章
- 异步任务队列Celery在Django中的使用
前段时间在Django Web平台开发中,碰到一些请求执行的任务时间较长(几分钟),为了加快用户的响应时间,因此决定采用异步任务的方式在后台执行这些任务.在同事的指引下接触了Celery这个异步任务队 ...
- 《Django By Example》第四章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:祝大家新年快乐,这次带来<D ...
- django server之间通过remote user 相互调用
首先,场景是这样的:存在两个django web应用,并且两个应用存在一定的联系.某些情况下彼此需要获取对方的数据. 但是我们的应用肯经都会有对应的鉴权机制.不会让人家随随便便就访问的对吧.好比上车要 ...
- Mysql事务探索及其在Django中的实践(二)
继上一篇<Mysql事务探索及其在Django中的实践(一)>交代完问题的背景和Mysql事务基础后,这一篇主要想介绍一下事务在Django中的使用以及实际应用给我们带来的效率提升. 首先 ...
- Mysql事务探索及其在Django中的实践(一)
前言 很早就有想开始写博客的想法,一方面是对自己近期所学知识的一些总结.沉淀,方便以后对过去的知识进行梳理.追溯,一方面也希望能通过博客来认识更多相同技术圈的朋友.所幸近期通过了博客园的申请,那么今天 ...
- 《Django By Example》第三章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:第三章滚烫出炉,大家请不要吐槽文中 ...
- 《Django By Example》第二章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:翻译完第一章后,发现翻译第二章的速 ...
- 《Django By Example》第一章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:本人目前在杭州某家互联网公司工作, ...
- Django
一.Django 简介 Django 是一个由 Python 写成的开放源代码的 Web 应用框架.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是 CMS(内容管理系统) ...
随机推荐
- 05—动态sql
1.创建表 CREATE TABLE tb_employee ( ID INT(11) PRIMARY KEY AUTO_INCREMENT, loginname VARCHAR(18), PASSW ...
- [唐胡璐]Selenium技巧- ReportNG替换TestNG默认结果报告
TestNG默认的报告虽然内容挺全,但是展现效果却不太理想,不易阅读。因此我们想利用ReportNG来替代TestNG默认的report。 什么是ReportNG呢?这里不多说,请直接参见:http: ...
- Java8-Stream-No.09
import java.util.Arrays; public class Streams9 { public static void main(String[] args) { Arrays.asL ...
- Qt 窗体增加滚动条
//滚动区域 m_ScrollArea = new QScrollArea(parentWidget()); m_ScrollArea->setGeometry(, , , ); //垂直滚动条 ...
- jmeter结果树乱码的解决方案
- 几个不同的关键XPath概念
几个不同的关键XPath概念...... 绝对vs相对XPath(/vs .) / 引入绝对位置路径,从文档的根开始. . 从上下文节点开始引入相对位置路径. 命名元素vs任何元素(enamevs * ...
- OSError: cannot open resource(pillow错误处理)
https://www.jianshu.com/p/c64ae3e9b196 pillow使用备忘之OSError: cannot open resource错误处理 在使用pillow过程中,Pyt ...
- hdu 5187 zhx's contest (快速幂+快速乘)
zhx's contest Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) To ...
- OpenGL 开发环境配置:Visual Studio 2017 + GLFW + GLEW
Step1:Visual Studio 2017 Why 开发环境,后面编译GLFW 和 GLEW也要用 How 这里使用的是Visual Studio 2017的 Community 版本,直接官网 ...
- 2016 Multi-University Training Contest 1 部分题解
第一场多校,出了一题,,没有挂零还算欣慰. 1001,求最小生成树和,确定了最小生成树后任意两点间的距离的最小数学期望.当时就有点矛盾,为什么是求最小的数学期望以及为什么题目给了每条边都不相等的条件. ...