resful 开发规范(10)
参考资料:
RESTful API 设计指南--阮一峰:http://www.ruanyifeng.com/blog/2014/05/restful_api.html
1.协议
https http
.2.域名 api.
3.动作 get put post delete datch
4.状态码 200 400 500
5.返回错误信息处理
6.返回需要的值
7.hybermedia
8.路径是名词
9.version 信息包含在url中
10.url中包含着过滤信息
Djangore sframework 组件(10)
1.路由
2.视图
3.版本
4.序列化
5.认证系统
6.权限
7.评率
8.解析
9.分页
10响应
自定制配置文件
示例,开发一个短信自动发送系统 要求微信, 支付宝,短信可以同时发送
代码如下
# 包中的短信接口 class Msg(): def send(self,msg): print('%s发送了%s'%(self.__class__.__name__,msg)) # 包中的微信接口 class Wechat(): def send(self, msg): print('%s发送了%s'%(self.__class__.__name__,msg)) # 包中的支付宝发送接口 class Zfb(): def send(self, msg): print('%s发送了%s' % (self.__class__.__name__, msg)) # 包中的iniit from importlib import import_module from conf import SETTING def send(msg): for path in SETTING: model_name,class_name = path.rsplit('.',1) module_name = import_module(model_name) print(module_name) api_class = getattr(module_name,class_name) api_class().send(msg) # 配置文件 SETTING = [ 'service.msg.Msg', 'service.wechat.Wechat', 'service.zhifb.Zfb', ] # main 函数 from service import send if __name__ == '__main__': send('xxx')
Content-type
什么是Django ContentTypes?
Django ContentTypes是由Django框架提供的一个核心功能,它对当前项目中所有基于Django驱动的model提供了更高层次的抽象接口。
然而,对于Django ContentTypes不熟悉的人来说,上面这句话说了跟没说一样,因此,笔者将一步一步解释Django ContentTypes在Django框架中做了什么,以及如何使用Django ContentTypes。
当然,如果对于ContentTypes有了初步了解而只是不了解它的应用场景,可以直接查阅以下这两个链接:
- Django official documentation:The contenttypes framework
- stackoverflow: How exactly do Django content types work?
Django ContentTypes做了什么?
当使用django-admin初始化一个django项目的时候,可以看到在默认的INSTALL_APPS已经包含了django.contrib.contenttypes:
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', ]
而且注意django.contrib.contenttypes是在django.contrib.auth之后,这是因为auth中的permission系统是根据contenttypes来实现的。
笔者紧接着查阅了一下django.contrib.contenttypes.models文件:
class ContentType(models.Model): app_label = models.CharField(max_length=100) model = models.CharField(_('python model class name'), max_length=100) objects = ContentTypeManager() class Meta: verbose_name = _('content type') verbose_name_plural = _('content types') db_table = 'django_content_type' unique_together = (('app_label', 'model'),) def __str__(self): return self.name
大家可以看到ContentType就是一个简单的django model,而且它在数据库中的表的名字为django_content_type。
有经验的Django开发者对于这个表的名字一般都不会陌生,在第一次对Django的model进行migrate之后,就可以发现在数据库中出现了一张默认生成的名为django_content_type的表。
如果没有建立任何的model,默认django_content_type是这样的:
sqlite> select * from django_content_type; 1|admin|logentry 2|auth|group 3|auth|user 4|auth|permission 5|contenttypes|contenttype 6|sessions|session
因此,django_content_type记录了当前的Django项目中所有model所属的app(即app_label属性)以及model的名字(即model属性)。
当然,django_content_type并不只是记录属性这么简单,在一开始的时候笔者就提及了contenttypes是对model的一次封装,因此可以通过contenttypes动态的访问model类型,而不需要每次import具体的model类型。
- ContentType实例提供的接口
- ContentType.model_class()
- 获取当前ContentType类型所代表的模型类
- ContentType.get_object_for_this_type()
- 使用当前ContentType类型所代表的模型类做一次get查询
- ContentType.model_class()
- ContentType管理器(manager)提供的接口
- ContentType.objects.get_for_id()
- 通过id寻找ContentType类型,这个跟传统的get方法的区别就是它跟get_for_model共享一个缓存,因此更为推荐。
- ContentType.objects.get_for_model()
- 通过model或者model的实例来寻找ContentType类型
- ContentType.objects.get_for_id()
至于实际的例子可以去参考官方文档。
Django ContentTypes的使用场景
Permission对ContentType的使用
在之前,笔者简单地提及了auth中Permission有涉及到对ContentType的使用,下面来看一下Permission的model源码:
class Permission(models.Model): """ The permissions system provides a way to assign permissions to specific users and groups of users. The permission system is used by the Django admin site, but may also be useful in your own code. The Django admin site uses permissions as follows: - The "add" permission limits the user's ability to view the "add" form and add an object. - The "change" permission limits a user's ability to view the change list, view the "change" form and change an object. - The "delete" permission limits the ability to delete an object. Permissions are set globally per type of object, not per specific object instance. It is possible to say "Mary may change news stories," but it's not currently possible to say "Mary may change news stories, but only the ones she created herself" or "Mary may only change news stories that have a certain status or publication date." Three basic permissions -- add, change and delete -- are automatically created for each Django model. """ name = models.CharField(_('name'), max_length=255) content_type = models.ForeignKey( ContentType, models.CASCADE, verbose_name=_('content type'), ) codename = models.CharField(_('codename'), max_length=100) objects = PermissionManager() class Meta: verbose_name = _('permission') verbose_name_plural = _('permissions') unique_together = (('content_type', 'codename'),) ordering = ('content_type__app_label', 'content_type__model', 'codename')
大家可以看到Permission模型中设置了一个对ContentType的外键,这意味着每一个Permission的实例都具有关于一个ContentType的id作为外键,而ContentType的id恰恰代表着一个Model。
回想Permission模型在初始化的时候发生了什么,它为每个模型设置了三个权限,分别是add,change以及delete,那么它是如何跟每个模型联系起来的呢?就是通过一个到ContentType的外键。
大家可以看一下Permission表,其中第二行就是content_type,然后将主键于django_content_type对比:
sqlite> select * from auth_permission; 1|1|add_logentry|Can add log entry 2|1|change_logentry|Can change log entry 3|1|delete_logentry|Can delete log entry 4|2|add_group|Can add group 5|2|change_group|Can change group 6|2|delete_group|Can delete group 7|3|add_user|Can add user 8|3|change_user|Can change user 9|3|delete_user|Can delete user 10|4|add_permission|Can add permission 11|4|change_permission|Can change permission 12|4|delete_permission|Can delete permission 13|5|add_contenttype|Can add content type 14|5|change_contenttype|Can change content type 15|5|delete_contenttype|Can delete content type 16|6|add_session|Can add session 17|6|change_session|Can change session 18|6|delete_session|Can delete session
如此,Permission模型借助ContentType表达了对一个model的权限操作。
ContentType的通用类型
笔者将引用在顶部的stackoverflow中回答的例子讲述对通用类型的理解。
假设以下的应用场景:
from django.db import models from django.contrib.auth.models import User # Create your models here. class Post(models.Model): author = models.ForeignKey(User) title = models.CharField(max_length=75) slug = models.SlugField(unique=True) body = models.TextField(blank=True) class Picture(models.Model): author = models.ForeignKey(User) image = models.ImageField() caption = models.TextField(blank=True) class Comment(models.Model): author = models.ForeignKey(User) body = models.TextField(blank=True) post = models.ForeignKey(Post, null=True) picture = models.ForeignKey(Picture, null=True)
注意笔者这里跟原回答做了一些更改,在原回答中Comment中没有null的选项,笔者觉得回答者真正要表达的是Comment是分别和Picture或者Post中其中一个对应即可,一个Comment并不既需要Post又需要Picture才能建立,可能是回答者写错没注意的缘故。
当笔者对以上model进行migrate之后,发现Comment表中的foreignkey是可以被设置为null的。
那么,如何通过Contenttype框架对以上代码进行改进呢?
ContentType提供了一种GenericForeignKey的类型,通过这种类型可以实现在Comment对其余所有model的外键关系。
修改后的Comment模型如下:
class Comment(models.Model): author = models.ForeignKey(User) body = models.TextField(blank=True) content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = fields.GenericForeignKey()
在django中,也提供从诸如Post,Picture访问Comment的查询,通过GenericRelation类型。如:
class Post(models.Model): author = models.ForeignKey(User) title = models.CharField(max_length=75) slug = models.SlugField(unique=True) body = models.TextField(blank=True) comment = GenericRelation('Comment')
值得注意的是,如果在Post中定义了GenericRelation,删除了一个实例,在Comment中所有的相关实例也会被删除,GenericForeignKey不支持设置on_delete参数。
因此,如果对级联删除不满意的话就不要设置GenericRelation。
cores跨域请求
之前已经说过了,跨域请求的两种方式1.script标签的src 属性 2 josn p 用于ajax 的get 请求,下面我们就讲一下三种方法cores
CORS
一、简介
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
二、两种请求
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
只要同时满足以下两大条件,就属于简单请求。
(1) 请求方法是以下三种方法之一: HEAD GET POST (2)HTTP的头信息不超出以下几种字段: Accept Accept-Language Content-Language Last-Event-ID Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain
凡是不同时满足上面两个条件,就属于非简单请求。
浏览器对这两种请求的处理,是不一样的。
git
本地git 基本命令
git init # 初始化git 会在进入的目录中创建一个隐藏的文件.git 今后的所有的备份将放在这个文件夹中
git status # git 状态监测 红色的表示没有监测的 绿色代表监测的
git add 单个或者 . #. 添加监测对象 .代表全部
git commit --m 表示保存当前监测文件的修改状态,此处要加一个存储的版本名字,帮助你回滚到这个版本
git log 查看备份版本 一串字符串可以作为回滚的参数
git reset --hard + 参数 把log中的版本状态参数放在命令后边可以实现回滚到指定版本
git reflog 记录所有的版本无论是否回滚过