
python
部署得过程很简单,部署得核心在于,为什么要这样做,每一个参数代表什么意思,最终的目的是得了解,一些基概念性的东西。 uWsgi简介 说Uwsgi之前,先说一下Wsgi。 什么是Wsgi? WSGI: 是一种Web服务器网关接口,它是一个Web服务器(如Nginx) 与应用服务器(如uWSGI服务器)通信的一种规范。 uWSGI是一个Web服务器,它实现了WSGI协议,uwsgi,http等协议,Nginx中HttpUwsgiModul的作用是与uWSGI服务器进行交换 那么那些框架自带了Wsgi Server呢? 很多框架都自带了WSGI Server, 比如: Flask、 Webpy、 Dajngo、 CherryPy等等。当然性能都不好,自带的Web Server更多的是本地测试用途,发布时则使用生产环境的WSGI Server或者是联合Nginx做Uwsgi。 简单的来讲Wsgi就是,标准, 比如: 一个德国人跟一个法国人聊天,他们要想聊天可以通过一个标准的国际语言: 英语来进行交互。 要注意 WSGI/uWSGI/uwsgi 这三个概念的区分。 WSGI是一种通讯协议 uwsgi同WSGI一样是一种通信协议 而uWSGI是实现了uwsgi和WSGI两种协议的Web服务器。 为什么uWSGI还需要nginx,应为Nginx具备了优秀的静态内容处理能力,然后将动态内容转发给uWSGI服务器,这样就实现了,动静分离。 也可以更好的达到客户端的效果。 常见的Python Http服务器 早期的Web Server 早期的时候,只能访问静态的内容, 在那时Web开发还很简单,开发这经常会去操作Web服务器,并且写一些HTML页面放到服务器指定的文件夹下(www)下,这些Html页面,就在浏览器请求页面时使用, 随着时间的发展,问题就出现了,你只能获取到静态的内容,如果想访问者看到有多少其他访问者访问了这个网站,或者想让访问者提交一些包含邮箱姓名,地址的表单,这个就比较麻烦了。 中期的WebServer 到了中期,就可以访问一些动态的数据了, 当浏览器访问Webserver的时候, 就可以调用后台的一些数据了, 写小程序的人很多,各种人都有,然后统一了一个标准,CGI,随着时间的演变,到了05年左右,进入了Web应用时代, 现在的Web Server 实际部署过程 安装nginx yum install nginx Nginx安装完成之后安装uWsgi。 pip install uwsgi 以上两项安装完成之后,现在开始配置uwsgi, 进入项目的根目录,注意:项目不要放在root目录下。 执行一下命令,来测试项目是否可以被uwsgi启动。 uwsgi --http 192.168.31.123:80 --file teacher/wsgi.py --static-map=/static=static 192.168.31.123: 你的ip地址 启动成功之后 进入项目跟目录之后,在同级目录创建一个空的文件夹: mkdir script 创建完成之后,在目录中创建uwsgi.ini文件。 vim uwsgi.ini 创建ini文件完成之后,将一下内容放进文件夹中。 [uwsgi] # 项目目录 chdir=/opt/project_teacher/teacher/ # 启动uwsgi的用户名和用户组 uid=root gid=root # 指定项目的application module=teacher.wsgi:application # 指定sock的文件路径 socket=/opt/project_teacher/script/uwsgi.sock # sock文件是由uwsgi.ini文件启动之后自动生成 # 启用主进程 master=true # 进程个数 workers=5 pidfile=/opt/project_teacher/script/uwsgi.pid # 自动移除unix Socket和pid文件当服务停止的时候 vacuum=true # 序列化接受的内容,如果可能的话 thunder-lock=true # 启用线程 enable-threads=true # 设置自中断时间 harakiri=30 # 设置缓冲 post-buffering=4096 # 设置日志目录 daemonize=/opt/project_teacher/script/uwsgi.log 以上配置完成之后,启动uwsgi.ini文件,并查看进程。 uwsgi到此为止,那么恭喜你,uwsgi已经配置完成了, 现在开始配置nginx, 进入以下目录修改default.conf文件: cd /etc/nginx/conf.d/ vim default.conf 进入文件之后讲一下,代码,贴近文件中: server { listen 80; server_name 10.129.205.183 ; # 域名 access_log /var/log/nginx/access.log main; charset utf-8; gzip on; gzip_types text/plain application/x-javascript text/css text/javascript application/x-httpd-php application/json text/json image/jpeg image/gif image/png application/octet-stream; error_page 404 /404.html; error_page 500 502 503 504 /50x.html; # 指定项目路径uwsgi location / { include uwsgi_params; uwsgi_connect_timeout 30; uwsgi_pass unix:/opt/project_teacher/script/uwsgi.sock; } # 指定静态文件路径 location /static/ { alias /opt/project_teacher/teacher/static/; index index.html index.htm; } } 启动ngxin 启动nginx之后,在启动uwsgi,此时你打开浏览器,输入你设置的server_name,是不是就可以访问出你的项目了, 项目截图,最近本人想搭建自己的一个简单的博客,基本页面,和功能已经完成,后期还会加一些,高级一点的东西,毕竟现在里边还什me都没有,博客截图如下: 上传博客内容,是集成百度的,Ueditor, 之前是在Django的admin中来集成的Django-Ueditor, 想了想,还是自己写了一个添加文章的地方。 git源码地址: https://github.com/Mrwyc/DjangoBlog
内置函数的基本使用 abs的使用: 取绝对值 1 absprint(abs(123))print(abs(-123))result:123123 all的使用: 循环参数,如果每个元素都为真的情况下,那么all的返回值为True: 假: 0, None, "", [],(), {} ret = all([True, True]) ret1 = all([True, False]) result: True False any的使用: 只要有一个为True,则全部为True ret = any(None, "", []) ret1 = any(None, "", 1) result: False True ascii的使用: 回去对象的类中,找到__repr__方法,找到该方法之后获取返回值 class Foo: def __repr__(self): return "hello" obj = Foo() ret = ascii(obj ) 自动去对象(类)中找到 __repr__方法获取其返回值 bin的使用: 二进制 ret = bin(11) result: 0b1011 oct的使用: 八进制 ret = oct(14) result: 0o16 int的使用: 十进制 ret = int(10) result: 10 hex的使用: 十六进制 ret = hex(14) result: 0xe 0x:表示16进制 e: 表示14 bool的使用: 判断真假, True:真 , False:假, 把一个对象转换成bool值 ret = bool(None) ret = bool(1) result: False True bytearray的使用: 字节列表 列表元素是字节, bytes的使用: 字节 bytes("xxx", encoding="utf-8") callable的使用: 判断对象是否可被调用 class Foo: #定义类 pass foo = Foo() # 生成Foo类实例 print(callable(foo)) # 调用实例 ret = callable(Foo) # 判断Foo类是否可被调用 print(ret) result: False True chr的使用: 给数字找到对应的字符 ret = chr(65) result: A ord的使用: 给字符找到对应的数字 ret = ord("a") result: a classmethod的使用: 修饰符 修饰符对应的函数不需要实例化,不需要self参数,但第一个参数需要时表示自身类的cls参数,可以来调用类的属性,类的方法,实例化对象等。 class A(object): bar = 1 def func(self): print("func") @classmethod def func2(cls): print("func2") print(cls.bar) cls().func() # 调用func方法 A.func2() # 不需要实例化 result: func2 1 func compile的使用: 函数讲一个字符串编译为字节代码 compile(source, filename, mode[, flags[, dont_inherit]]) 参数: source 字符串或者AST(Abstract Syntax Trees对象) filename 代码文件名称,如果不是从文件读取代码则传递一些可辨认的值 mode 指定编译代码的种类,可指定: exec, eval, single flags 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。 flags和dont_inherit是用来控制编译源码时的标志 str_for = "for i in range(1,10): print(i)" c = compile(str_for, '', 'exec') # 编译为字节代码对象 print(c) print(exec(c)) result: 1 2 3 4 5 6 7 8 9 complex的使用: 函数用于创建一个值为 real + image * j 的复数或者转化一个字符串或数为复数,如果第一个参数为字符串,则不需要指定第二个参数。 语法: class complex([real ,[ image]]) 参数说明: real int, long, float或字符串 image int,long,float ret1 = complex(1,2) print(ret1) ret2 = complex(1) print(ret2) ret3 = complex("1") print(ret3) ret4 = complex("1+2j") print(ret4) result:返回一个复数 (1+2j) (1+0j) (1+0j) (1+2j) delattr的使用: 用于删除属性 delattr(x, "foobar") 相等于 del x.foobar 语法: delattr(object, name) 参数: object 对象 name 必须是当前对象的属性 class DelClass: x = 10 y = -5 z = 0 obj = DelClass print("x", obj.x) print("y", obj.y) print("z", obj.z) delattr(DelClass, 'z') print("x", obj.x) print("y", obj.y) print("报错", obj.z) result: x 10 y -5 z 0 x 10 y -5 print("报错", obj.z) AttributeError: type object 'DelClass' has no attribute 'z' dict的使用: 字典的使用方法 new_dict = dict() new_dict['key1'] = "test" print(new_dict) dir的使用: 该方法将最大限制地收集参数信息, 查看当前,变量,方法, 类型的属性以及功能。 print(dir()) list_one = list() print(dir(list_one)) result: ['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__'] ['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort'] divmod的使用: 将除数和余数运算结果结合起来,返回一个包含商和余数的元祖。 ret = divmod(7, 2) print(ret) ret_one = divmod(8, 2) print(ret_one) 参数: 数字 result: (3, 1) (4, 0) enumerate的使用: 用于将一个可遍历的数据对象(list, tuple,str)组合为一个索引序列,同时列出数据,和数据下标。 test_list = [1, 2, 3, 4, 5] for data_index, data in enumerate(test_list): print("下标:{0},数据{1}".format(data_index, data)) 参数: sequence 一个序列,迭代器或其他支持迭代对象 start 下标起始位置 result: 下标:0,数据1 下标:1,数据2 下标:2,数据3 下标:3,数据4 下标:4,数据5 eval的使用: 用来执行一个字符串表达式,并且返回表达式的值 x = 7 ret = eval('x + 3') print(ret) 参数: expression 表达式 globals 变量作用域,全局命名空间 locals 变量作用域,局部命名空间 result: 10 exec的使用: 执行存储在字符串或文件中的python语句,相比eval,exec可以执行更复杂的python代码 import time ret = exec("""for i in range(0,5): time.sleep(1) print(i) """) # 注意代码块中的缩进 result: 0 1 2 3 4 filter的使用: 用于过滤序列,过滤掉不符合条件的元素,返回符合条件元素组成的新list def is_odd(n): return n % 2 == 1 newlist = filter(is_odd, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) print(newlist) 参数: function 判断函数 iterable 可迭代对象 result: [1, 3, 5, 7, 9] float的使用: 将整形转换成小数形 a_int = 10 b_float = float(a_int) print(a_int) print(b_float) result: 10 10.0 format的使用: 字符串序列化,可以序列多种类型 str_format = "Helle World" list_format = ['list hello world'] dict_format = {"key_one":"value_one"} ret_format_one = "{0}".format(str_format) ret_format_two = "{0}".format(list_format) ret_format_three = "{0}".format(dict_format) print(ret_format_one) print(ret_format_two) print(ret_format_three) result: Helle World ['list hello world'] {'key_one': 'value_one'} frozenset的使用: 返回一个冻结集合,集合冻结之后不允许添加,删除任何元素 a = frozenset(range(10)) # 生成一个新的不可变集合 print(a) b = frozenset('wyc') # 创建不可变集合 print(b) result: frozenset({0, 1, 2, 3, 4, 5, 6, 7, 8, 9}) frozenset({'w', 'y', 'c'}) getattr的使用: 用于返回一个对象的属性值 class Foo(object): bar = 1 obj = Foo() print(getattr(obj, 'bar')) # 获取属性bar的默认值 print(getattr(obj, 'bar2')) # 不存在,没设置默认值,则报错 print(getattr(obj, 'bar2', 3)) # 属性2不存在,则设置默认值即可 result: 1 print(getattr(obj, 'bar2')) AttributeError: 'Foo' object has no attribute 'bar2' 3 globals的使用: 会以字典类型返回当前位置的全部全局变量 print(globals()) result: {'__cached__': None, '__name__': '__main__', '__builtins__': <module 'builtins' (built-in)>, '__doc__': None, '__package__': None, '__file__': 'C:/Users/Administrator/PycharmProjects/untitled/day1.py', '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000011E78626B70>, '__spec__': None} hasattr的使用: 用于判断对象是否包含对应的属性 class Foo: x = 10 y = 20 z = 0 obj = Foo() print(hasattr(obj, 'x')) print(hasattr(obj, 'k')) result: True False hash的使用: 用于获取一个对象(字符串或者数值等)的哈希值 str_test = "wyc" int_test = 5 print(hash(str_test)) print(hash(int_test)) result: 1305239878169122869 5 help的使用: 帮助查看类型有什么方法 str_test = "wyc" print(help(str)) result: 结果有点小长,就不粘贴再此了 id的使用: 查看当前类型的存储在计算机内存中的id地址 str_test = "wyc" print(id(str_test)) result: 2376957216616 input的使用: 接受标准数据,返回一个string类型 user_input = input("请输入:") print(user_input) result: 请输入:wyc wyc isinstance的使用: 判断一个对象是否是一个已知的类型,类似type() a = 1 print(isinstance(a, int)) print(isinstance(a, str)) result: True False issubclass的使用: 用于判断参数class是否是类型参数, classinfo的子类 class A: pass class B(A): pass print(issubclass(B, A)) # 判断B是否是A的子类 result: True iter的使用: 用来生成迭代器 lst = [1, 2, 3] for i in iter(lst): print(i) result: 1 2 3 len的使用: 查看当前类型里边有多少个元素 str_one = "hello world" lst = [1, 2, 3] print(len(str_one)) # 空格也会算一个元素 print(len(lst)) result: 11 3 list的使用: 列表 list = [1, 2, 3, 4, 5] 方法: 索引: index 切片: [1:3] 追加: append 删除: pop 长度: len 扩展: extend 插入: insert 移除:remove 反转: reverse 排序:sort locals的使用: 以字典类型返回当前位置的全部,局部变量 def func(arg): z = 1 return locals() ret = func(4) print(ret) result: {'arg': 4, 'z': 1} map的使用: 根据提供的函数对指定序列做映射 def func(list_num): return list_num * 2 print(map(func, [1, 2, 3, 4, 5])) result: [2, 4, 6, 8, 10] max的使用: 返回最大数值 ret = max(1, 10) print(ret) result: 10 memoryview的使用: 返回给定参数的内存查看对象 v = memoryview(bytearray("abc", 'utf-8')) print(v[0]) restlt: 97 min的使用: 取出最小数值 print(min(1, 10)) result: 1 next的使用: 返回迭代器的下一个项目 it = iter([1, 2, 3, 4, 5]) while True: try: x = next(it) print(x) except StopIteration: # 遇到StopIteration就退出循环 break result: 1 2 3 4 5 open的使用: 打开一个文件,创建一个file对象,相关的方法才可以调用它的读写 f = open('test.txt') f.read() f.close() # 文件读写完成之后,一定要关闭 ord的使用: 函数是 chr() 函数(对于8位的ASCII字符串)或 unichr() 函数(对于Unicode对象)的配对函数,它以一个字符(长度为1的字符串)作为参数,返回对应的 ASCII 数值,或者 Unicode 数值,如果所给的 Unicode 字符超出了你的 Python 定义范围,则会引发一个 TypeError 的异常。 ret = ord('a') ret1 = ord('b') ret2 = ord('c') result: 97 98 99 pow的使用: 返回 xy(x的y次方) 的值 import math # 导入 math 模块 print "math.pow(100, 2) : ", math.pow(100, 2) # 使用内置,查看输出结果区别 print "pow(100, 2) : ", pow(100, 2) print "math.pow(100, -2) : ", math.pow(100, -2) print "math.pow(2, 4) : ", math.pow(2, 4) print "math.pow(3, 0) : ", math.pow(3, 0) print的使用: 输出,打印 print('hello world') result: hello world property的使用: 新式类中的返回属性值,python3中是新式类,2中是旧式类 class C(object): def __init__(self): self._x = None def getx(self): return self._x def setx(self, value): self._x = value def delx(self): del self._x x = property(getx, setx, delx, "I'm the 'x' property.") range的使用: 输出范围之内的数值 for i in range(1, 5): print(i) result: 1 2 3 4 5 repr的使用: 函数将对象转化为供解释器读取的形式 s = 'RUNOOB' repr(s) "'RUNOOB'" dict = {'runoob': 'runoob.com', 'google': 'google.com'}; repr(dict) "{'google': 'google.com', 'runoob': 'runoob.com'}" reversed的使用: 返回一个反转的迭代器 # 字符串 seqString = 'Runoob' print(list(reversed(seqString))) # 元组 seqTuple = ('R', 'u', 'n', 'o', 'o', 'b') print(list(reversed(seqTuple))) # range seqRange = range(5, 9) print(list(reversed(seqRange))) # 列表 seqList = [1, 2, 4, 3, 5] print(list(reversed(seqList))) result: ['b', 'o', 'o', 'n', 'u', 'R'] ['b', 'o', 'o', 'n', 'u', 'R'] [8, 7, 6, 5] [5, 3, 4, 2, 1] round的使用: 返回浮点数x的四舍五入值 print "round(80.23456, 2) : ", round(80.23456, 2) print "round(100.000056, 3) : ", round(100.000056, 3) print "round(-100.000056, 3) : ", round(-100.000056, 3) result: round(80.23456, 2) : 80.23 round(100.000056, 3) : 100.0 round(-100.000056, 3) : -100.0 set的使用: 不可重复元素 a=set((1,2,3,"a","b")) setattr的使用: 设置属性值,该属性必须存在 class A(object): bar = 1 a = A() print(getattr(a, 'bar')) # 获取属性 bar 值 1 setattr(a, 'bar', 5) # 设置属性 bar 值 print(a.bar) slice的使用: 实现切片对象,主要用在切片操作函数里的参数传递 myslice = slice(5) # 设置截取5个元素的切片 print(myslice) print(slice(None, 5, None)) arr = range(10) print(arr) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] print(arr[myslice]) # 截取 5 个元素 [0, 1, 2, 3, 4] sorted的使用: 所有可迭代的对象进行排序操作 a = [5,7,6,3,4,1,2] b = sorted(a) # 保留原列表 print(a) [5, 7, 6, 3, 4, 1, 2] print(b) [1, 2, 3, 4, 5, 6, 7] L=[('b',2),('a',1),('c',3),('d',4)] sorted(L, cmp=lambda x,y:cmp(x[1],y[1])) # 利用cmp函数 [('a', 1), ('b', 2), ('c', 3), ('d', 4)] print(sorted(L, key=lambda x:x[1])) # 利用key [('a', 1), ('b', 2), ('c', 3), ('d', 4)] students = [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)] print(sorted(students, key=lambda s: s[2]) ) # 按年龄排序 [('dave', 'B', 10), ('jane', 'B', 12), ('john', 'A', 15)] print(sorted(students, key=lambda s: s[2], reverse=True) ) # 按降序 [('john', 'A', 15), ('jane', 'B', 12), ('dave', 'B', 10)] staticmethod的使用: 返回函数的静态方法 class C(object): @staticmethod def f(): print('runoob'); C.f(); # 静态方法无需实例化 cobj = C() cobj.f() # 也可以实例化后调用 str的使用: 字符串 str = "wyc" 方法: cpitalize 首字母变大写 count 子序列个数 decode 解码 encode 编码针对unicode endswith 是否以xxx结束 find 寻找子序列位置,如果没有找到,返回-1 format 字符串格式化 index 子序列位置,如果没有找到,报错 isalnum 是否是字母数字 isalpha 是否是字母 isdigit 是否是数字 islower 是否小写 join 拼接 lower 变小写 lstrip 移除左侧空白 replace 替换 sum的使用: 求数值整合 print(sum(1+1)) result: 2 super的使用: 用于调用父类(超类)的一个方法 Python3.x 和 Python2.x 的一个区别是: Python 3 可以使用直接使用 super().xxx 代替 super(Class, self).xxx python3 class A: pass class B(A): def add(self, x): super().add(x) python2 class A(object): # Python2.x 记得继承 object pass class B(A): def add(self, x): super(B, self).add(x) tuple的使用: 元祖,元祖是不可修改的 tuple = (1, 2, 3) type的使用: 查看当前类型是什么类型 lst = list() print(type(lst)) result: <class 'list'> vars的使用: 返回对象object的属性和属性值的字典对象 print(vars()) {'__builtins__': <module '__builtin__' (built-in)>, '__name__': '__main__', '__doc__': None, '__package__': None} class Runoob: a = 1 print(vars(Runoob)) {'a': 1, '__module__': '__main__', '__doc__': None} runoob = Runoob() print(vars(runoob)) {} zip的使用: 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。 如果各个迭代器的元素个数不一致,则返回列表长度与最短的对象相同,利用 * 号操作符,可以将元组解压为列表。 a = [1,2,3] b = [4,5,6] c = [4,5,6,7,8] zipped = zip(a,b) # 打包为元组的列表 [(1, 4), (2, 5), (3, 6)] zip(a,c) # 元素个数与最短的列表一致 [(1, 4), (2, 5), (3, 6)] zip(*zipped) # 与 zip 相反,*zipped 可理解为解压,返回二维矩阵式 [(1, 2, 3), (4, 5, 6)] __import__的使用: 函数用于动态加载类和函数 import time, os 扩展进制转换: 二进制转换十进制 int('0b11', base=2) result: 3 八进制转换十进制 int('11', base=8) result: 9 十六进制转换十进制 int('0xe', base=16) result: 14 以上有不足之处,请大神,留下宝贵的建议,本人看到第一时间添加。
1: 更新代码时, 监测到本地代码改变,需要和合并,重启之后才可以, 选择No同时,代码会被冲掉,新增加的文件也会被冲掉, 但是pycharm有一个文件历史记忆,找到之后可以找到丢失的文件。 1: 选择工程跟目录 2: 右键点开 3: 找到 Local History ----- show History 点开之后,就会弹出一个框,左侧是文件名称,你找到相对应的名称之后,打开,赋值代码即可。
解决方案: cd /etc/gitlab vim /gitlab.rb gitlab_rails['rack_attack_git_basic_auth'] = { 'enabled' => true, 'ip_whitelist' => ["127.0.0.1","IP地址"], 'maxretry' => 300, 'findtime' => 5, 'bantime' => 60 } 保存gitlab配置: gitlab-ctl reconfigure 重启-gitlab: gitlab-ctl restart
什么是Autopep8 在python开发中, 大家都知道,python编码规范是PEP8,但是在市级开发中有的公司严格要求PEP8规范开发, 有的公司不会在乎那些,在我的理解中,程序员如果想走的更高,或者更远,干任何事情必须得专业化(本人理解方式), 不要求很多东西都是精通,但最少得有一门精通的语言,小弟在此在大佬面前装逼了, 忘看过的大牛不要揭穿, 留下你懂的我不懂的知识,大家一起学习,一起进步。 谢谢。 Autopep8是一个将python代码自动编排的一个工具,它使用pep8工具来决定代码中的那部分需要被排版,Autopep8可以修复大部分pep8工具中报告的排版问题。很多人都知道 Ctrl+Alt+L 也可以排版, 但是我要告诉你,快捷键只是可以简单的排版。跟Autopep8是无法相比的。 安装Autopep8: pip install autopep8 安装完成之后,import导入一下,测试是否安装成功。 Aytopep8的使用 安装完成之后,打开pycharm,创建一个新的python文件, demo.py 将一下代码放入文件中。 def example1(): some_tuple = (1, 2, 3, 'a') some_variable = { 'long': 'Long code lines should be wrapped within 79 characters.', 'other': [math.pi, 100, 200, 300, 9876543210,'This is a long string that goes on'], 'more': { 'inner': 'This whole logical line should be wrapped.',some_tuple: [ 1,20, 300, 40000,500000000,60000000000000000]}} return (some_tuple, some_variable) def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True}; class Example3(object): def __init__(self, bar): # Comments should have a space after the hash. if bar: bar += 1 bar = bar * bar else: some_string = """ Indentation in multiline strings should not be touched.Only actual code should be reindented. """ 这几行代码看上去是不是很乱, 接下来就要使用:Autopep8模块了 打开cmd找到demo.py的文件的上级目录, 然后输入以下命令: autopep8 --in-place --aggressive --aggressive file.py file.py 是你的demo.py 输入命令,按回车执行成功是不返回的, 执行完成之后就可以了,在次打开文件就可以看到变化了。 import math import sys def example1(): some_tuple = (1, 2, 3, 'a') some_variable = { 'long': 'Long code lines should be wrapped within 79 characters.', 'other': [ math.pi, 100, 200, 300, 9876543210, 'This is a long string that goes on'], 'more': { 'inner': 'This whole logical line should be wrapped.', some_tuple: [ 1, 20, 300, 40000, 500000000, 60000000000000000]}} return (some_tuple, some_variable) def example2(): return ('' in {'f': 2}) in {'has_key() is deprecated': True}; class Example3(object): def __init__(self, bar): # Comments should have a space after the hash. if bar: bar += 1 bar = bar * bar else: some_string = """ Indentation in multiline strings should not be touched.Only actual code should be reindented. """ 执行完Autopep8之后代码是不是看上去简洁多了。 有人会说,没写一个函数就执行一遍命令, 是不是有点麻烦啊, 是的, 有有点麻烦, 但是pycharm是可以配置的, 配置过程如下: 1: File ---> Settings ---> Tools ---> External Tools 打开之后,可以看见窗体左上角有一个 + 号, 点击+号添加。 Name: 名称可以随意 Program: autopep8 # 前提必须先安装 Arguments: --in-place --aggressive --aggressive $FilePath$ Working directory: $ProjectFileDir$ Advanced Options ---- Outputfilters: $FILE_PATH$\:$LINE$\:$COLUMN$\:.* 以上配置完成之后点击 OK 保存即可。 快捷使用: Tools ---> External Tools ---> Autopep8 鼠标点击一下即可。
下载gitlab 亲测: centos6.5 安装依赖包: 1: yum install curl policycoreutils policycoreutils-python openssh-server openssh-clients 依赖包安装完成之后: 1: systemctl enable sshd 2: systemctl start sshd 3: yum install postfix 4: systemctl enable postfix 5: systemctl start postfix 6: firewall-cmd --permanent --add-service=http 7: systemctl reload firewalld 以上依赖安装完之后,下载gitlab: centos 6系统的下载地址:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el6 centos 7系统的下载地址:https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el7 下载相对应系统的rpm包 wget https://mirrors.tuna.tsinghua.edu.cn/gitlab-ce/yum/el6/gitlab-ce-8.0.0-ce.0.el6.x86_64.rpm 安装rpm包 rpm -i gitlab-ce-8.0.0-ce.0.el6.x86_64.rpm 安装完成之后 vim /etc/gitlab/gitlab.rb 修改gitlab配置文件,访问IP:端口, 如果不修改默认80端口,进入文件之后,找到 external_url # 这个变量 修改external_url变量 external_url 'http://ip:端口' 修改完成之后退出并且保存 esc + wq 保存之后需要更新一下修改 gitlab-ctl reconfigure 重启gitlab gitlab-ctl restart # 重启 gitlab-ctl stop # 停止 gitlab-ctl start # 启动 gitlab-ctl status # 查看状态 访问gitlab 输入你在 /etc/gitlab/gitlab.rb文件里定义的 external_url后边跟的ip就可以访问 配置成功之后就会出现这个页面, 默认账号:root, 密码;password, 如果不对的话,请自行修改。 修改gitlab管理员账号密码 gitlab-rails console production # 按下回车之后会出现 Loading production environment (Rails 4.1.1) # 依次输入 irb(main):001:0> user = User.where(id:1).first irb(main):002:0> user.password='66668888' # root密码 irb(main):003:0> user.save! # 返回 true # 表示修改成功 Ctrl+C 可以退出了 到了这里之后,gitlab就配置完成了,接下来就可以使用了。以上所有方法,亲测,全部有效。 # 修改gitlab IP地址 vim /etc/gitlab/gitlab.rb external_url 'ip地址' 配置完成 重置命令: gitlab-ctl reconfigure 重启命令: gitlab-ctl restart
django-debug-toolbar django,web开中,用django-debug-toolbar来调试请求的接口,无疑是完美至极。 可能本人,见识博浅,才说完美至极, 大神,表喷,抱拳了。 第一步: pip install django-debug-toolbar 安装完成之后。就改往下继续配置了。 第二步: 打开项目,找到settings.py 文件。 找到: INSTALLED_APPS--变量 将以下代码,添加进去。 1 'debug_toolbar' 继续添加: 找到放置: 中间件的地方, 将以下代码添加进去。 1 'debug_toolbar.middleware.DebugToolbarMiddleware', 2 3 4 5 # 结尾一定要添加 “ , ” 逗号 中间件添加完成之后,就该添加 django-debug-toolbar的中间件了。 DEBUG_TOOLBAR_PANELS = [ 'debug_toolbar.panels.versions.VersionsPanel', 'debug_toolbar.panels.timer.TimerPanel', 'debug_toolbar.panels.settings.SettingsPanel', 'debug_toolbar.panels.headers.HeadersPanel', 'debug_toolbar.panels.request.RequestPanel', 'debug_toolbar.panels.sql.SQLPanel', 'debug_toolbar.panels.staticfiles.StaticFilesPanel', 'debug_toolbar.panels.templates.TemplatesPanel', 'debug_toolbar.panels.cache.CachePanel', 'debug_toolbar.panels.signals.SignalsPanel', 'debug_toolbar.panels.logging.LoggingPanel', 'debug_toolbar.panels.redirects.RedirectsPanel', ] 添加访问IP INTERNAL_IPS = ('127.0.0.1',) 修改 django-debug-toolbar换下源。 python3 --> Lib ---> site-packages --->settings.py 打开settings文件后找得到(CONFIG_DEFAULTS) 变量 , 修改key: JQUERY_URL的value。 //cdn.bootcss.com/jquery/2.1.4/jquery.min.js 配置到这之后,就ok了, 直接 runserver吧。 运行起来之后,打开浏览器输上IP,就可以看到效果喽, 也有可能中间或许有人会安装出错,。。。不好意思哈, 我安装的时候是一步到位的。 安装出错之后,就请您自行百度一下。 页面效果: 打开网址之后页面就出现上图的效果,走到这里,说明就已经安装完成了, dajngo-debug-toolbar的简单使用 每次请求一个接口,右侧的栏目都会变得, 如图: 我点击的是sql, 就是去数据库查数据需要多长时间,点击sql之后就会看到右侧的数据,Time是毫秒级别的, 下边就是请求数据库需要的时间了。 优化时间慢的地方。 按照表红框的地方,点开,就会看到Connection:default 这个块。 这块的意思就是,那里的代码拖延了时间,或者重复循环,都会提示出来,当你请求的接口没有这个信息了,就说明,你已经优化成功了。 到这里此教程就完了, 如有写的不对的地方,请大神指点出来,或者有别的好用的东西,也请大神留言指点一二。 谢谢
废话不多说,干货直接上。 winserver2012 + django2.0.1 + apache 部署过程 1 ,python ==> 3.4 64位 https://www.python.org/downloads/release/python-353/2 ,django ==> 2.0.1 64位 3 ,apache ==> 2.2.4 64位 https://www.apachehaus.com/cgi-bin/download.plx mod_wsgi 1 , pip install mod_wsgi and http://www.lfd.uci.edu/~gohlke/pythonlibs/#mod_wsgi 安装微软SDK7.1 or vs2010-2018 pip install mod_wsgi需要依赖编译 http://www.lfd.uci.edu/~gohlke/pythonlibs/#mod_wsgi 下载:mod_wsgi‑4.5.24+ap24vc10‑cp34‑cp34m‑win_amd64.whl 以上环境安装完成之后,mod_wsgi.whl文件下载完成之后,放在C盘根目录下, 打开终端,进入C盘根目录, 1, pip install "mod_wsgi‑4.5.24+ap24vc10‑cp34‑cp34m‑win_amd64.whl" pip完成之后,紧接着输入: mod_wsgi-express module-config 输出结果: 1: LoadFile "c:/users/administrator/appdata/local/programs/python/python35/python35.dll" 2: LoadModule wsgi_module "c:/users/administrator/envs/mode_env/lib/site-packages/mod_wsgi/server/mod_wsgi.cp35-win_amd64.pyd" 3: WSGIPythonHome "c:/python34" 之后配置apache 进入apache目录==>bin修改httpd.conf文件 1: Define SRVROOT "C:/pyobj/apache24/apache24" 2: 设置监听得端口号前提端口必须开放 80Listen 0.0.0.0:80 3:设置服务器地址ServerName ***.***.***.***:80 4:在最底部添加如下配置 LoadModule wsgi_module "c:/users/administrator/envs/mode_env/lib/site-packages/mod_wsgi/server/mod_wsgi.cp35-win_amd64.pyd" WSGIPythonHome "c:/users/administrator/envs/mode_env" == >python地址 # django项目中得wsgi.py 路径 (绝对路径) WSGIScriptAlias / C:/pyobj/Apachedemo/Apachedemo/wsgi.py # django项目路径 WSGIPythonPath C:/pyobj/Apachedemo # 配置wsgi权限<Directory C:/pyobj/Apachedemo/Apachedemo><Files wsgi.py>Require all granted</Files></Directory> 配置完成之后打开终端进入apache/bin目录 将apache添加为系统服务 httpd -k install # 启动服务httpd -k start # 停止httpd -k stop # 重启httpd -k restart 安装过程中,如果机器是64位,以上安装包全部都得是64为,不可以64/32混用。
Go的常亮 关键字: Const Go常亮的多个定义: // 定义常亮的关键字 const // 定义多个常亮 const( PI = 3.14 const1 = "1" const2 = 2 const3 = 3 ) 全局变量的声明与赋值: var ( name = "wyc" name1 = 1 name2 = 2 name3 = 3 ) 一般类型声明: type ( newType int type1 float32 type2 string type3 byte ) Go的基本类型: 布尔型: - 长度 1字节 - 取值范围: true、false - 注意事项: 不可以使用数字来代表true或false 整型: int/uint - 根据运行平台可能为32或64位 8位整型: int8/uint8 - 长度: 1字节 - 取值范围: -128~127 / 0~255 字节型: byte(uint8别名) 16位整型: int/uint16 - 长度: 2字节 - 取值范围: -32768~32767 / 0~65535 32位整型: int32(rune) int32/uint32 - 长度: 4字节 - 取值范围: -2^64/2~2^64/2-1/0~2^64-1 64位整型: - 长度 8字节 - 取值范围: -2^64/2~2^64/2-1/0~2^64-1 浮点型: float32 / float64 - 长度: 8/8字符 - 小数位: 精确到7/15小数位 复数类型: complex64/complex128 - 长度: 8/16字节 足够保存指针的32位或64位整数型: uintptr // 其他值类型: - array、 struct、string // 引用类型: - slice、map、chan // 接口函数 : inteface // 函数接口 : func 类型零值: 零值并不等于空值,而是当变量声明为某种来兴后的默认零值,通常情况下默认值为0,bool为false,string为空字符串。 类型别名: type( byte int8 rune int32 文本 string ) 别名: var a 文本 b = "你好中国" 零值: package main import ( "fmt" ) func main() { var a int fmt.Println(a) } // 结果: 0 math包 math包可以检查类型是否超出范围 math.Min 记录了一个最小值和一个最大值 int型的最小值: math.MinInt8 int类型的最小值就会打印出来, -128 类型声明 package main import ( "fmt" ) // 类型的定义 type ( byte int8 rune int32 文本 string ) func main() { var a 文本 a = "你好中国" fmt.Println(a) } // 在实际应用中最好还是不要使用中文,它有可能会引起一些不必要的错误。 单个变量的声明与赋值 and 多个变量的声明与赋值 单个变量: 单个变量的声明格式: var <变量名称> <变量类型> 变量的赋值的格式 : <变量名称> = <表达式> 变量声明的同时赋值 : var <变量名称> <变量类型> = [表达式] 多个变量 : 全局变量的声明格式: var <变量名称> <变量类型> 全局变量的声明不可以省略 var, 但可使用并行方式 所有变量都可以使用类型推断 局部变量不可以使用 var() 的方式简写,只能使用并行方式 var ( // 常规方式 aaa = "hello" // 使用并行方式以及类型推断 w,y,c = 11,22,33 // ccc := 3 // 不可以省略 var ) 多个变量: // 多个变量声明 var a,b,c,d int // 多个变量赋值 a,b,c,d = 1,2,3,4 // 多个变量声明的同时赋值 var w,y,c int = 1,2,3 // 省略变量类型,由系统推断类型 var w,y,c = 1,2,3 // 多个变量的声明与赋值的最简的写法 w,y,c := 11,22,33 package main import ( "fmt" ) func main() { // var w,y,c int // w,y,c = 1,2,3 w,y,c := 11,22,33 fmt.Println(w,y,c) } // 下划线可以表示不需要的元素 package main import ( "fmt" ) func main() { w,_,c := 11,22,33 fmt.Println(w,c) } 变量的类型转换 Go中不存在隐式转换,所有类型转换必须显示声明。 转换只能发生两种相互兼容的类型之间 类型转换的格式: <Value>[:] = <TypeOfValueA> (<ValueB>) package main import ( "fmt" ) func main() { var a float32 = 1.1 b := int(a) fmt.Println(b) }
Go语言的特性 开启了学习新的语言路程,记录每天学习的笔记,与大家一起分享。 ①、自动垃圾回收 ②、更丰富的内置类型 ③、函数多返回值 ④、错误处理 ⑤、匿名函数和闭包 ⑥、类型和接口 ⑦、并发编程 ⑧、反射 ⑨、语言交互性 Go内置的关键字 break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continue for import return var Go的注释方法有以下两种: // 单行注释 /* */ 多行注释 Go程序的一般结构: 1、go程序是通过package 来阻止的。 2、值有package名称为main的包可以包含main函数。 3、一个可执行程序 有且仅有 一个main包。 4、通过import关键字来导入其它非main包。 5、通过const关键字来进行常量的定义。 6、通过在函数体外部使用var来进行全局变量的声明与赋值。 7、通过type关键字来进行结构struct或接口insterface的声明。 8、通过func关键字来进行函数的声明。 Go语言的导包方式 导入单个包 导入多个包 package别名 1、当用第三方包时,包名和包名可能会非常接近或者相同,此时就可以使用别名来进行却别和调用。 上图就是给 “fmt” 包 设置一个新的别名 io 给包名设置别名时不建议使用的名字 (.) Go的可见性规则 Go语言中,使用大小写来决定该, 常量、变量、接口、结构或函数 是否可以被调用。 根据约定,函数名首字母 小写 即为private 函数首字母大写即为public Go基础编程 day1的代码:
Django-Rest-Framework Django-Rest框架是构建Web API强大而灵活的工具包。 简单粗暴,直奔主题。 pip install django pip install djangorestframework pip install pygments # 代码显示高亮 pip安装好需要的工具包之后,我们就开始创建一个框架。 打开终端。 cd ~ 切换到根目录下, (那个目录页可以,看自己想往哪里创建) django-admin.py startproject test_restframework # 创建工程 创建好之后切换进工程里边。 cd test_restframework 工程已经创建好了,需要cd进工程里边,关键是manage.py在工程里边,我们就需要借用manage.py来进行其他的操作了。 给工程添加api python manage.py startapp test_restapi # 创建api 创建好之后,接下来,我们需要对django框架进行一些设置了(settings.py) 进入工程目录(test_restframework)找到settings.py,点开找见(INSTALLD_APPS)这个配置元祖,然后添加 INSTALLD_APPS = ( ... 'rest_framework', 'test_restframework.apps.SnippetsConfig', # 这里需要注意的就是 ,不添加有可能会出错 ) 配置添加完成之后,接下来我们改创建model了。 目录: test_restapi/model.py from django.db import models from pygments.lexers import get_all_lexers from pygments.styles import get_all_stylea LEXERS = [item for item in get_all_lexers() if item[1]] LANGUAGE_CHOICES = sorted([(item[1][0], item[0]) for item in LEXERS]) STYLE_CHOICES = sorted((item, item) for item in get_all_styles()) Class Snippet(models.Model): created = models.DateTimeField(auto_now_add=True) title = models.CharField(max_length=100, blank=True, default='') code = models.TextField() linenos = models.BooleanField(default=False) language = models.CharField(choices=LANGUAGE_CHOICES, default='python', max_length=100) style = models.CharField(choices=STYLE_CHOICES, default='friendly', max_length=100) class Meta: ordering = ('created',) model模型已经建好, 我们还需要模型迁移,并同步数据库。 注意:同步数据库命令是在 test_restframework下执行 python manage.py makemigrations test_restapi python manage.py migrate 数据库已经同步了,我们还需要在Web API 上添加一些序列化和反序列化的实例的方法,例如 json ,我们可以通过声明序列化器来实现这一点,这些序列化器的工作方式与Django的表单相似,在test_restapi目录中创建一个serializer.py文件,添加以下代码。 from rest_framework import serializers from test_restapi.models import Snipper, LANGUAGE_CHOICES, STYLE_CHOICES class SnippetSerialiazer(zerializers.Serializer): id = serializers.IntegerField(read_only=True) title = serializers.CharField(required=False, allow_blank=True, max_length=100) code = serializers.CharField(style={'base_template':'textarea.html'}) linenos = serializers.BooleanField(required=False) language = serializers.ChoiceField(choices=LANGUAGE_CHOICES, DEFAULT='python') style = serializers.ChoiceField(choices=STYLE_CHOICES, default='friendly') def create(self, validated_data): return Snippet.object.create(**validated_data) def update(self, instance, validated_data): instance.title = validated_data.get('title', instance.title) instance.code = validated_data.get('code', instance.code) instance.linenos = validated_data.get('linenos', instance.linenos) instance.language = validated_data.get('language', instance.language) instance.style = validated_data.get('style', instance.style) instance.save() return instance serializer类的第一部分定义了被序列化反序列化的字段,create()和update()方法定义了在调用serializer.save()时如何创建或修改完全成熟的实例, serializer类非常类似于django form类,它包括在不同的字段上的类似验证标志,如required、max_length和default。 字段标志还可以控制在某些情况下序列化程序的显示方式,比如向HTML呈现的情况。 使用序列化器 在使用之前我们需要进入Django-shell。 python manage.py shell 进入shell之后我们需要输入: from test_restapi.models import Snippet from test_restapi.serializers import SnippetSerializer from rest_framework.renders import JSONRenderer from rest_framework.parsers import JSONParser snippet = Snippet(code='foo = "bar"\n') snippet.save() snippet = Snippet(code='print "hello world"\n') snippet.save() 我们已经有了一些可以使用的片段实例,让我们来看看序列化其中的一个实例吧。 serializer = SnippetSerializer(snippet) serializer.data # {'id': 2, 'title': u'', 'code': u'print "hello, world"\n', 'linenos': False, 'language': u'python', 'style': u'friendly' 我们已经将模型实例转化为python原生数据类型,为了完成序列化过程, 我们将数据转化为json。 content = JSONRenderer().render(serializer.data) content # '{"id": 2, "title": "", "code": "print \\"hello, world\\"\\n", "linenos": false, "language": "python", "style": "friendly"}' 反序列化是相似的,首先我们解析一个流到python原生数据类型。 from django.utils.six import BytesIO stream = BytesIO(content) data = JSONParser().parse(stream) 然后我们将这些本机数据类型,还原为一个完全填充的对象实例。 serializer = SnippetSerializer(data=data) serializer.is_valid() # True serializer.validated_data # OrderedDict([('title', ''), ('code', 'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]) serializer.save() # <Snippet: Snippet object> 我们还可以序列化querysets而不是模型实例,为此, 我们只需要在序列化器中添加 many=True的标记。 serializer = SnippetSerializer(Snippet.objects.all(), many=True) serializer.data # [OrderedDict([('id', 1), ('title', u''), ('code', u'foo = "bar"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 2), ('title', u''), ('code', u'print "hello, world"\n'), ('linenos', False), ('language', 'python'), ('style', 'friendly')]), OrderedDict([('id', 3), ('title', u''), ('code', u'print "hello, world"'), ('linenos', False), ('language', 'python'), ('style', 'friendly')])] 使用ModelSerializers 将test_restapi/serializers.py文件里的代码替换为: class SnippetSerializer(serializers.ModelSerializer): class Meta: model = Snippet fields = ('id', 'title', 'code', 'linenos', 'language', 'style') 序列器有一个很好的属性,可以同过它来打印它的表示,来检查序列化器实例中所有的字段,打开 Django shell python manage.py shell from test_restapi.serializers import SnippetSerializer serializer = SnippetSerializer() print(repr(serializer)) 重要的是要记住ModelSerializer类并没有做什么特别神奇的事情,它们只是创建序列化的快捷方式。 使用序列化器编写常规的django视图 目录: test_restapi/views.py from django.http import HttpResponse, JsonResponse from django.views.decorators.csrf import csrf_exempt from rest_framework.renderers import JSONRenderer from rest_framework.parsers import JSONParser from snippets.models import Snippet from snippets.serializers import SnippetSerializer @csrf_exempt def snippet_list(request): """ List all code snippets, or create a new snippet. """ if request.method == 'GET': snippets = Snippet.objects.all() serializer = SnippetSerializer(snippets, many=True) return JsonResponse(serializer.data, safe=False) elif request.method == 'POST': data = JSONParser().parse(request) serializer = SnippetSerializer(data=data) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data, status=201) return JsonResponse(serializer.errors, status=400) @csrf_exempt def snippet_detail(request, pk): """ Retrieve, update or delete a code snippet. """ try: snippet = Snippet.objects.get(pk=pk) except Snippet.DoesNotExist: return HttpResponse(status=404) if request.method == 'GET': serializer = SnippetSerializer(snippet) return JsonResponse(serializer.data) elif request.method == 'PUT': data = JSONParser().parse(request) serializer = SnippetSerializer(snippet, data=data) if serializer.is_valid(): serializer.save() return JsonResponse(serializer.data) return JsonResponse(serializer.errors, status=400) elif request.method == 'DELETE': snippet.delete() return HttpResponse(status=204) 最后定义路由,将视图连接起来。 目录: test_restapi/urls.py from django.conf.urls import url from snippets import views urlpatterns = [ url(r'^snippets/$', views.snippet_list), url(r'^snippets/(?P<pk>[0-9]+)/$', views.snippet_detail), ] 目录: test_restframework/urls.py from django.conf.urls import url, include urlpatterns = [ url(r'^', include('test_resrapi.urls')), ] 安装httpie,我们可以通过curl来测试api,但是httpie也是一种很友好的测试包。 pip install httpie 最后启动工程 python manage.py runserver 工程起来之后,打开浏览器,输入url就可以看到结果了。 ^.^ 以上资料来自官网。如有 不明白之处,可以查询官网示例: http://www.django-rest-framework.org/tutorial/1-serialization/
枚举 枚举指一系列的相关的常量,比如下面关于一个星期的中每天的定义,通过上篇博文,我们可以用在const后跟一对圆括号的方式定义一组常量,这种定义法在go语言中通常用于定义枚举值。go语言并不支持众多其他语言明确支持的enum关键字。 下面是一个常规的枚举表示法,其中定义了一系列整型常量。 const ( Sunday = iota Monday Tuesday Wednesday Thursday Friday Saturday numberOfDays // 这个常量没有导出 ) 同go语言中的其他符号(symbol)一样,以大写字母开头的常量在包外可见。 以上列子中 numberOfDays为包内私有,其他符号则可被其他包访问。 数据基本类型 布尔类型: bool 整数类型: int8、byte、int6、int、uint、uintptr等。 浮点类型: float32、float64。 复数类型:complex64、complex128。 字符串:string。 字符类型:rune。 错误类型:error。 处上之外,go语言还支持一下的复合类型。 指针(pointer) 数组(array) 切片(slice) 字典(map) 通道(chan) 结构体(struct) 接口(interface) 上述类型的特点在于使用方便,但使用者不能对这些类型的长度做任何假设。对于常规的开发来说,用int和uint就可以了,没必要用int8之类明确指定长度的类型 ,以免导致移植困难。 布尔类型 go语言中的布尔类型与其他语言基本一致,关键字也是 bool ,可赋值为预定义的true和false。 var test bool test = true test_two := (1 == 2) // test_two也会被推导为bool类型 PS: 布尔类型不能接受其他类型赋值,不支持自动或强制的类型转换。 下面一些错误的语法: var a bool a = 1 // 语法错误 a = bool(1) // 语法错误 以下的用法才是正确: var one bool one = (1 != 0) // 正确语法 fmt.Println("result:", one) // go的输出 Println 输出结果: result : true 整型: 整型是所有语言里最基础的类型了。 类型 长度 值范围 int8 1 -128 ~ 127 uint8(既byte) 1 0 ~255 int16 2 -32 768 ~ 32 767 uint16 2 0~65 535 int32 4 -2 147 483 648 ~ 2 147 483 647 uint32 4 0 ~ 4 294 967 295 int64 8 -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807 uint64 8 0 ~ 18 446 744 073 709 551 615 int 因平台而定 因平台而定 uint 因平台而定 因平台而定 uintptr 同指针 在32位平台下为4字节,64位平台下为8字节 ①、类型表示 需要注意的是,int和int32在go语言里被认为是两种不同的类型,编译器也不会帮你自动做转换类型,比如以下的列子会有编译错误: var value2 int32 value1 := 64 // value1将会被自动推导为int类型 value2 = value1 // 编译错误 编译错误类似于: cannot use valu1 (type int) as type int32 in assignment。 使用强制类型转换可以解决这个编译错误: value2 = int32 (value1) //编译通过 当然,开发者在做强制类型转换时,需要注意数据长度被截断而发生的数据精度损失(比如将浮点数强制转为整数)和值溢出(值超过转换的目标类型的值范围时)问题。 ②、数值运算 go语言支持下面的常规整数运算: +、-、*、/、和%。加减乘除就不解释了,需要说下的是,%和C语言中一样是求余运算,比如: 5 % 3 // 结果: 2 ③、比较运算 go语言支持以下的几种比较运算符: > 、 < 、 ==、>=、 <=和!=。这一点与其他大多数的语言相通,与C语言完全一致。 ④、运算符 运算 含义 样 列 x << y 左移 124 << 2 // 结果为496 x >> y 右移 124 >> 2 // 结果为31 x ^ y 异或 124 ^ 2 // 结果为126 x & y 与 124 & 2 // 结果为0 x | y 或 124 | 2 // 结果为126 ^x 取反 ^2 // 结果为3 go语言的大多数位运算符与C语言都比较类似,除了取反在C语言中是~x,而在go语言中是^x。 浮点型 浮点型用于表示包含小数点的数据,比如1.234就是一个浮点型数据,在go语言中的浮点类型采用IEEE-754标准的表达方式。 ①、浮点数表示 go语言定义了两个类型float32和float64,其中float32等价于C语言的float类型,float64等价于C语言的double类型。 在go语言中,定义一个浮点数变量的代码如下: var fvalue1 float32 fvalue1 = 12 fvalue2 := 12.0 // 如果不加小数点,fvalue2会被推导为整型而不是浮点型 对于以上列子类型被自动推导的fvalue2,需要注意的是其类型将被自动设为float64,而不管赋给它的数字是否使用32位长度表示的,因此,对于以上列子,下面的赋值将导致编译错误: fvalue1 = fvalue2 而必须使用这样的强制类型转换: fvalue1 = float32(fvalue2) ②、浮点数比较 因为浮点数不是一种精确的表达方式,所以像整型那样直接用==来判断两个浮点数是否相等是不可行的,这可能会导致 不稳定的结果 。 下面是一种推荐的替代方案。import "mat// p为用户自定义的比较精度, 比如:0.00001 func IsEqual(f1, f2, p float64) bool { return math.Fdim(f1, f2) < p } 复数类型 复数实际上由两个实数(在计算机中用浮点数表示)构成,一个表示 实部(real),一个表示虚部(imag),如果了解了数学上的复数是怎么回事,那么go语言的复数就非常容易理解了。 ①、复数表示 复数示例: var value1 complex64 // 由2个float32构成复数类型 value1 = 3.2 + 12i value2 := 3.2 + 12i //value2是complex128类型 value3 := complex(3.2, 12) //value3结果同value2 ②、实部与虚部 对于一个复数z = complex(x, y),就可以通过go语言内置函数real(z)获得该复数的实部,也就是x,通过imag(z)获得该复数的虚部,也就是y。 字符串 在go语言中,字符串也是一种基本类型,相比之下,C/C++语言中并不存在原生的字符串类型,通常使用字符数组来表示,并以字符指针来传递。 go语言中一下是字符串的声明和初始化。 var str string // 声明一个字符串变量 str = "Hello world" // 字符串赋值 ch := str[0] // 取字符串的第一个字符 fmt.Printf("The length of \"%s\" is %d \n", str, len(str)) fmt.Printf("The first character of \" %s\"is %c.\n", str, ch) 输出结果: The length of "Hello world" is 11 The first character of "Helllo world" is H. 字符串的内容看可以用类似于数组下标的方式获取,但与数组不同,字符串的内容不能再初始化后被修改,比如一下列子: str := "Hello world" // 字符串也支持声明时进行初始化的做法 str[0] = "x" // 编译错误 编译器会报类似如下错误: cannot assign to str[0] 字符串的操作 运算 含义 样列 x + y 字符串连接 "Hello" + "123" // hello123 len(str) 字符串长度 len("hello") // 5 s[*] 取字符 "hello" [1] // e 更多方法请参考string标准库包!!! ①字符串遍历 go语言中支持两种遍历方式,一种是以字节数组的方式遍历: str := "Hello,世界" n := len(str) for i := 0; i < n; i++ { ch := str[i] // 依据下标取字符串中的字符,类型为byte fmt.Println(i, ch) } 结果: 0 72 1 101 2 108 3 108 4 111 5 44 6 32 7 228 8 184 9 150 10 231 11 149 12 140 可以看出,这个字符串长度为13,尽管从直观上来说,这个字符串应该只有9个字符,这是因为每个中文字符在UTF-8中占三个字节,而不是壹个字节。 另一种是以Unicode字符遍历: str := "Hello, 世界" for i, ch := range str { fmt.Println(i, ch) // ch的类型为true } 结果: 0 72 1 101 2 108 3 108 4 111 5 44 6 32 7 19990 10 30028 以Unicode字符方式遍历时,每个字符的类型是rune(早期的go语言用int类型表示Unicode字符),而不是byte。 字符类型 在go语言中支持两个字符类型,一个是byte(实际上是uint8的别名),代表UTF-8字符串的单个字节的值,另一个是rune,代表单个Unicode字符。
Go 相信大家,看到这篇文章的时候,已经自己在百度百科了解了go的发展史已经特性,再次我依然。。。。得哔哔叨一会。 ^.^ go语言的特性 go语言作为一门静态类型开发语言,与当前的开发语言想必具备众多 令人兴奋不已的新特性。(具体兴奋不兴奋就不知道了,本人也是第一次看,希望通过博文与大家一起学习,一起探讨)以下的罗列有什么不全的地方,希望大神,积极评论,留下您看出的破绽。^.^ go语言的主要特性: 自动垃圾回收机制 所谓的垃圾回收机制,即所有的内存分配动作都会被在运行时记录,同时任何对该内存的使用也都会被记录,然后垃圾回收器会对 所有已经分配的内存进行跟踪监测,一旦发现有些内存已经不再被任何人使用,就阶段性地回收这些没人用的内存,当然应为需要尽量最小化垃圾回收的性能损耗,以及降低对正常程序执行过程的影响,显示中的垃圾回收算法要比这个复杂的多,比如对象增加年龄属性等,但基本原理 都是如此。 更丰富的内置类型 除了很多语言都支持的内置类型(比如整数,浮点数)等等。go语言也内置了一些比较新的语言中内置的高级类型,比如,数组,字符串,除此之外,go语言还内置了一个对于其他静态类型语言通常用库方式支持的字典类型(map),另外还有一个新增的数据类型,数组切片(slice),我们可以认为数组切片是一种可动态增长的数组,这几种数据结构基本上覆盖了绝大部分的应用场景。 函数多返回值 go语言革命性地在静态开发语言阵营中率先提供了多返回值功能,这个特性让开发者可以从原来用各种比较别扭的方式返回多个值得痛苦中解脱出来,既不用再区分参数列表中那几个用于输入,那几个用于输出,也不用再为返回多个值专门定义一个数据结构。函数的返回值,并不是每个返回值必须得赋值,没有被明确赋值的返回值保持默认的空值。 错误处理 (defer、panic、recover)这三个关键字用于标准的错误处理流程。 go语言的错误处理机制可以大量减少代码量,让开发者也无需仅仅为了程序安全性而添加大量一层套一层的 try - catch语句。 匿名函数和闭包 在go语言中,所有的函数也是值类型,可以作为参数传递。 类型和接口 go语言中的类型定义非常接近于C语言中的结构 (struct),甚至直接沿用了struct关键字,想必而言,go语言并没有直接沿袭C++和Java的传统去设计一个超级复杂的类型系统,不支持继承和重载,而只是支持了最基本的类型组合功能。 并发编程 go语言引入了goroutine概念,它使得并发编程变得非常简单,通过使用goroutine而不是裸用操作系统的并发机制,以及使用消息传递来共享而不是使用共享内存来通信,go语言让并发编程变得 更加轻盈和安全。 反射 反射(reflection)是在java语言出现后迅速流行起来的一种 概念,通过反射,你可以获取对象类型的详细信息,并可动态操作对象,反射是把双刃剑,功能强大但代码可读性并不理想。 语言交互性 由于go语言与C语言之间的天生联系,go语言的设计者们自然不会忽略如何重用现有C模块的这个问题,这个功能直接被 命名为Cgo,Cgo是语言的特性,同时也是一个工具名称。 在go代码中,可以按Cgo的特定语法混合编写C语言代码,然后Cgo工具可以将这些混合的C代码提取并生成对于C功能的调用包装代码,开发者基本上可以完全忽略这个go语言和C语言的边界是如何跨越的。 开发工具的选择 Goole并没有随着go 1的发布推出官方的go集成开发工具(ide),因此开发者需要自行考虑和选择合适的开发工具,目前比较流行的开发工具如下: 文本编辑工具 gedit(Linux) Notepad++(windows) Fraise(Mac OS X) 安装了goClipse插件的Eclipse,集成性做的很好。 Vim/Emacs,万能开发工具。 LiteIDE,一款专门为go语言开发的集成开发环境。
Pecan的介绍及安装 文章内容来自官方文档:http://pecan.readthedocs.io/en/latest/quick_start.html Pecan的介绍: Pecan是一个路由对象分发的oython web框架。本质上可以将url通过分割为每一部分,然后对每一部分查找对应处理该URL部分的处理类,处理后,继续交给后面部分的URL处理,直到所有URL部分都被处理后,调用最后分割的URL对应的处理函数处理。 本文以Xshall为主在其进行操作 Pecan的安装 创建项目 项目创建好之后目录结构如下 app.py:一般包含了Pecan应用的入口,包含初始化代码。 Config.py : 包含Pecan的应用配置,会被 app.py使用。 Controllersl : 这个目录包含所有的控制器,也就是API具体逻辑的地方 。 Cotrollers/root.py : 这个包含根路径对应的控制器。 Controllers/v1/ 这个目录放的是版本的API的。 Public : 文件夹存放一些Web应用所需的Image,Css或者JavaScript。 setup.py和setup.cfg用于Web应用的安装部署。 templates:存储Html或者Json的末班文件。 tests:存放测试用例。 代码变少了:application的配置 Pecan的配置很容易,通过 一个python的源码式的配置文件就可以完成基本的配置,这个配置的主要目的是指定应用程序的root,然后用于生成WSGI application。我们来看Magnum项目的列子,Magnum项目有个API服务是 用Pecan实现的,在magnum/api/config.py文件中可以找到这个文件,主要内容如下: 1 app = { 2 'root': 'magnum.api.controllers.root.RootController', 3 'modules': ['magnum.api'], 4 'debug': False, 5 'hooks': [ 6 hooks.ContextHook(), 7 hooks.RPCHook(), 8 hooks.NoExceptionTracebackHook(), 9 ], 10 'acl_public_routes': [ 11 '/' 12 ], 13 } 上面这个app对象就是Pecan的配置,每个Pecan应用都需要有这么一 个名为app的配置。app配置中最重要的就是root的值,这个值表示了应用程序的入口,也就是从哪个地方开始解析HTTP的根path:/。 hooks对应的配置是一些pecan的hook,作用类似于WSGI Middleware。有了app配置后,就可以让Pecan生成一个WSGI application。在Magnum项目中,magnum/api/app.py文件就是生成WSGI application的地方,我们来看一下这个主要的内容: 1 def get_pecan_config(): 2 # Set up the pecan configuration 3 filename = api_config.__file__.replace('.pyc', '.py') 4 return pecan.configuration.conf_from_file(filename) 5 6 7 def setup_app(config=None): 8 if not config: 9 config = get_pecan_config() 10 11 app_conf = dict(config.app) 12 13 app = pecan.make_app( 14 app_conf.pop('root'), 15 logging=getattr(config, 'logging', {}), 16 wrap_app=middleware.ParsableErrorMiddleware, 17 **app_conf 18 ) 19 20 return auth.install(app, CONF, config.app.acl_public_routes) get_pecan_config()方法读取我们上面提到的config.py文件,然后返回一个pecan.configuration.Config对象,setup_app()函数首先调用get_pecan_config()函数获取application的配置,然后调用pecan.make_app()函数创建了一个WSGI application,调用了auth.install()函数(也就是magnum.api.auth.install()函数)为刚刚生成的WSGI application加上keystone的认证中间件(确保所有的请求都会通过keystone认证)。 到这边为止,一个pecan的WSGI application就已经准备好了,只要调用这个setup_app()函数就获得,至于如何部署这个WSGI application请参考WSGI简介这篇文章(https://segmentfault.com/a/1190000003069785)从Magnum这个实际的列子可以看出,使用了pecan之后 ,我们不再需要自己写那些WSGI application代码了,直接调用pecan的make_app()函数就能完成 这些工作,另外,对于之前使用pasteDeploy时用到的很多WSGI中间件,可以选择使用pecan的hooks机制来实现,也选择使用WSGI中间件的方式来实现,在Magnum的API服务就同时使用了这两种方式,其实pecan还可以和pastedeploy一起使用,ceilometer项目就是这么做的,大家可以看看。 确定路由变得容易了:对象分发式的路由 Pecan不仅缩减了生成WSGI application的代码,而且也让开发人员更容易的指定一个application的路由,Pecan采用了一种对象分发风格(object-dispatch style)的路由模式,我们直接通过列子来解释这种路由模式,还是以Magnum项目为例。 上面提到了,Magnum的API服务的root是magnum.api.controllers.root.RootController。这里的RootController的是一个类,我们来看代码: 1 class RootController(rest.RestController): 2 3 _versions = ['v1'] 4 """All supported API versions""" 5 6 _default_version = 'v1' 7 """The default API version""" 8 9 v1 = v1.Controller() 10 11 @expose.expose(Root) 12 def get(self): 13 # NOTE: The reason why convert() it's being called for every 14 # request is because we need to get the host url from 15 # the request object to make the links. 16 return Root.convert() 17 18 @pecan.expose() 19 def _route(self, args): 20 """Overrides the default routing behavior. 21 22 It redirects the request to the default version of the magnum API 23 if the version number is not specified in the url. 24 """ 25 26 if args[0] and args[0] not in self._versions: 27 args = [self._default_version] + args 28 return super(RootController, self)._route(args) 别看这个类这么长,我来解释下你就懂了,首先你可以忽略掉_route()函数,这个函数使用来覆盖Pecan的默认路由实现的,在这里去掉它不妨碍我们理解Pecan(这里的_route()函数的作用把所有请求重定向到默认的API版本去),去掉_route()和其他的东西后,整个类就是变成这么短: 1 class RootController(rest.RestController): 2 v1 = v1.Controller() 3 4 @expose.expose(Root) 5 def get(self): 6 return Root.convert() 首先,你要记住,这个RootController对应的是URL中根路径,也就是path中最左边的/。 RootController继承自rest.RestController,是Pecan实现的RESTful控制器,这里get()函数表示,当访问的是GET/时,由该函数处理,get()函数会返回一个WSME对象,表示已个形式的HTTP Response,这个下面再讲。get()函数上面的expose装饰器是Pecan实现路由控制的一个方式,被expose的函数才会被路由处理。 这里的v1 = v1.Controller()表示,当访问的是GET/v1或者GET/v1/....时,请求由一个v1.Controller实例来处理。 为了加深大家的理解,我们再来看下v1.Controller的实现: 1 class Controller(rest.RestController): 2 """Version 1 API controller root.""" 3 4 bays = bay.BaysController() 5 baymodels = baymodel.BayModelsController() 6 containers = container.ContainersController() 7 nodes = node.NodesController() 8 pods = pod.PodsController() 9 rcs = rc.ReplicationControllersController() 10 services = service.ServicesController() 11 x509keypairs = x509keypair.X509KeyPairController() 12 certificates = certificate.CertificateController() 13 14 @expose.expose(V1) 15 def get(self): 16 return V1.convert() 17 18 ... 上面这个Controoler也是继承自restRestController。所以它的get函数表示,当访问的是GET/v1的时候,要做的处理。然后它还有很多类属性,这些属性分别表示不同的URL路径的控制器: 1、/vq/bays 由bays处理 2、/v1baymodels 由baymodels处理 3、/v1/containers 由containers处理 其他的都是类似的。我们在继续看bay.B安阳市Controller的代码: class BaysController(rest.RestController): """REST controller for Bays.""" def __init__(self): super(BaysController, self).__init__() _custom_actions = { 'detail': ['GET'], } def get_all(...): def detail(...): def get_one(...): def post(...): def patch(...): def delete(...): 这个Controller中只有函数,没有任何类属性,而且没有实现任何特殊方法,所以/v1/bays开头的URL处理都在这个controller中终结,这个类会处理如下请求: 1、GET /v1/bays 2、GET /v1/bays/{UUID} 3、POST /v1/bays 4、PATCH /v1/bays/{UUID} 5、DELETE /v1/bays/{UUID} 6、GET / v1/bays/detail/{UUID} 看到上面的3个controller之后,你应该能大概明白Pecan是如何对URL进行路由的,这种路由方式就是对象分发:(根据类属性)、(包括数据属性)和方法属性来决定如何路由一个HTTP请求,Pecan的文档中请求额路由有专门的描述,要想掌握Pecan的路由还是要完整的看一下官方文档。 内置RESTful支持 我们上面举例的controller都是继承自pecan.rest.RestController,这种controller称为RESTful controller,专门用于实现RESTful API的,因此在Openstack中使用特别多,Pecan还支持普通的controller,称为Generic controller。Generic controller继承自object对象,默认没有实现对RESTful请求的方法。简单的说,RESTful controller帮我们规定好了get_one(),get_all(),get(),post()等方法对应的HTTP请求,而Generic controller则没有,关于这两种controller的区别 ,可以看官方文档,有很清楚的示例。 对于RestController中没有预先定义好的方法,我们可以通过控制器的_custom_actions属性来指定其能处理的方法。 1 class RootController(rest.RestController): 2 _custom_actions = { 3 'test': ['GET'], 4 } 5 6 @expose() 7 def test(self): 8 return 'hello' 上面这个控制器是一个根控制器,指定了/test路径支持GET方法,效果如下: $ curl http://localhost:8080/test hello% 那么HTTP请求和HTTP响应呢? wsme Pecan对请求和响应的处理 在开始提到WSME之前,我们吸纳来看下Pecan自己对HTTP请求和响应的处理。这样你能更好的理解为什么会引入WSME库。 Pecan框架为每个线程维护了单独的请求和响应的对象,你可以直接在处理函数中访问。 pecan.requesr和pecan.response分别代表当前需要处理的请求和响应对象,你可以直接操作这两个对象,比如指定响应的状态码,就像下面这个列子一样: 1 @pecan.expose() 2 def login(self): 3 assert pecan.request.path == '/login' 4 username = pecan.request.POST.get('username') 5 password = pecan.request.POST.get('password') 6 7 pecan.response.status = 403 8 pecan.response.text = 'Bad Login!' 这个列子演示了访问POST请求的参数以及返回403,你也可以重新构造一个pecan.Response对象作为返回值: 1 from pecan import expose, Response 2 3 class RootController(object): 4 5 @expose() 6 def hello(self): 7 return Response('Hello, World!', 202) 另外,HTTP请求参数的参数也会可以作为控制器方法的参数,还是来看几个官方文档的列子: 1 class RootController(object): 2 @expose() 3 def index(self, arg): 4 return arg 5 6 @expose() 7 def kwargs(self, **kwargs): 8 return str(kwargs) 这个控制器中的方法直接返回了参数,演示了对GET请求参数的处理,效果是这样的: 1 $ curl http://localhost:8080/?arg=foo 2 foo 3 $ curl http://localhost:8080/kwargs?a=1&b=2&c=3 4 {u'a': u'1', u'c': u'3', u'b': u'2'} 有时候,参数也可能是URL的一部分,比如最后一段path作为参数,就像下面这样: 1 class RootController(object): 2 @expose() 3 def args(self, *args): 4 return ','.join(args) 效果是这样的: 1 $ curl http://localhost:8080/args/one/two/three 2 one,two,three 另外,我们还要看一下POST方法的参数 如何处理: 1 class RootController(object): 2 @expose() 3 def index(self, arg): 4 return arg 效果如下,就是把HTTP body解析成了控制器方法的参数: 1 $ curl -X POST "http://localhost:8080/" -H "Content-Type: 2 application/x-www-form-urlencoded" -d "arg=foo" foo 返回JSON还是HTML? 如果你不是明确的返回一个Response对象,那么Pecan中方法的返回内容类型就是由expose()装饰器决定的,默认情况下,控制器的方法返回的content-type是HTML。 1 class RootController(rest.RestController): 2 _custom_actions = { 3 'test': ['GET'], 4 } 5 6 @expose() 7 def test(self): 8 return 'hello' 效果如下: 1 $ curl -v http://localhost:8080/test 2 * Hostname was NOT found in DNS cache 3 * Trying 127.0.0.1... 4 * Connected to localhost (127.0.0.1) port 8080 (#0) 5 > GET /test HTTP/1.1 6 > User-Agent: curl/7.38.0 7 > Host: localhost:8080 8 > Accept: */* 9 > 10 * HTTP 1.0, assume close after body 11 < HTTP/1.0 200 OK 12 < Date: Tue, 15 Sep 2015 14:31:28 GMT 13 < Server: WSGIServer/0.1 Python/2.7.9 14 < Content-Length: 5 15 < Content-Type: text/html; charset=UTF-8 16 < 17 * Closing connection 0 18 hello% 也可以让他返回JSON: 1 class RootController(rest.RestController): 2 _custom_actions = { 3 'test': ['GET'], 4 } 5 6 @expose('json') 7 def test(self): 8 return 'hello' 效果如下: 1 curl -v http://localhost:8080/test 2 * Hostname was NOT found in DNS cache 3 * Trying 127.0.0.1... 4 * Connected to localhost (127.0.0.1) port 8080 (#0) 5 > GET /test HTTP/1.1 6 > User-Agent: curl/7.38.0 7 > Host: localhost:8080 8 > Accept: */* 9 > 10 * HTTP 1.0, assume close after body 11 < HTTP/1.0 200 OK 12 < Date: Tue, 15 Sep 2015 14:33:27 GMT 13 < Server: WSGIServer/0.1 Python/2.7.9 14 < Content-Length: 18 15 < Content-Type: application/json; charset=UTF-8 16 < 17 * Closing connection 0 18 {"hello": "world"}% 甚至,你可以让一个控制器方法根据URL path的来决定是返回HTML还是JSON: 1 class RootController(rest.RestController): 2 _custom_actions = { 3 'test': ['GET'], 4 } 5 6 @expose() 7 @expose('json') 8 def test(self): 9 return json.dumps({'hello': 'world'}) 返回JSON: 1 $ curl -v http://localhost:8080/test.json 2 * Hostname was NOT found in DNS cache 3 * Trying 127.0.0.1... 4 * Connected to localhost (127.0.0.1) port 8080 (#0) 5 > GET /test.json HTTP/1.1 6 > User-Agent: curl/7.38.0 7 > Host: localhost:8080 8 > Accept: */* 9 > 10 * HTTP 1.0, assume close after body 11 < HTTP/1.0 200 OK 12 < Date: Wed, 16 Sep 2015 14:26:27 GMT 13 < Server: WSGIServer/0.1 Python/2.7.9 14 < Content-Length: 24 15 < Content-Type: application/json; charset=UTF-8 16 < 17 * Closing connection 0 18 "{\"hello\": \"world\"}"% 返回HTML: 1 $ curl -v http://localhost:8080/test.html 2 * Hostname was NOT found in DNS cache 3 * Trying 127.0.0.1... 4 * Connected to localhost (127.0.0.1) port 8080 (#0) 5 > GET /test.html HTTP/1.1 6 > User-Agent: curl/7.38.0 7 > Host: localhost:8080 8 > Accept: */* 9 > 10 * HTTP 1.0, assume close after body 11 < HTTP/1.0 200 OK 12 < Date: Wed, 16 Sep 2015 14:26:24 GMT 13 < Server: WSGIServer/0.1 Python/2.7.9 14 < Content-Length: 18 15 < Content-Type: text/html; charset=UTF-8 16 < 17 * Closing connection 0 18 {"hello": "world"}% 这里要注意一下; 1、同一个字符串作为JSON返回和作为HTML返回是不一样的,仔细看一下HTTP响应的内容。 2、我们的列子中在URL的最后加上了.html后缀或者.json后缀,请尝试一下不加后缀的变化是返回什么?然后,调换一下两个expose()的顺序再试一下。 从上面的列子可以看出,决定响应类型的主要是传递给expose()函数的参数,我们看下expose()函数的完整声明: 1 pecan.decorators.expose(template=None, 2 content_type='text/html', 3 generic=False) template参数用来指定返回值得末班,如果是json就会返回json内容,这里可以指定一个 HTML文件,或者指定一个mako模板。 content_type指定响应的content-type,默认值是"text/html" generic参数表明该方法是一个"泛型"方法,可以指定多个不同的函数对应同一个路径的不同的HTTP方法。 看过参数的解释后,你应该能大概了解expose()函数是如何控制HTTP响应的内容和类型的。
单例模式的讲解以及用处 什么是单例模式用处何在? 答:单例模式(Singleton Pattern)是一种常用的软件设计模式,该模式的主要目的是确保某一个类只有一个实列存在,当你希望整个系统中只能出现一个实列时,这个时候单例对象就可以派上用场了。 举个列子!! 比如、某个服务器程序的配置信息存放在一个文件中,客户端通过一个AppConfig的类来读取配置文件的信息。如果在程序运行期间,有很多地方都需要使用配置文件的内容,也就是说,很多地方都需要创建AppConfig对象实列,这就导致系统中存在多个AppConfig的实列对象,而这样会严重浪费内存资源,尤其是在配置文件内容很多的情况下,事实上类似AppConfig这样的类,我们希望在程序运行期间只存在一个实例对象。 用 __new__来创建单例 如果想使得某个类从始至终最多只有一个实例,使用__new__方法会很简单,Python中类是通过__new__来创建实例的。 1 class A(object): 2 def __new__(cls, *args, **kwargs): 3 if not hasattr(cls,'_inst'): 4 cls._inst = super(A, cls).__new__(cls, *args, **kwargs) 5 return cls._inst 6 if __name__ == '__main__': 7 class B(A): 8 def __init__(self,s): 9 self.s = s 10 ret = A() 11 ret1 = B('two') 12 print id(ret),ret 13 print id(ret1),ret1.s 14 15 #结果 16 53445264 <__main__.A object at 0x032F8290> 17 53445392 two 通过__new__方法,将类的实例在创建的时候绑定到类属性_inst,如果cls._inst为None,说明类还没实例化,实列化并将实例绑定到cls._inst,以后每次实例化的时候都返回第一次实列化创建的实例,注意从A派生子类的时候,不要重载__new__。
状态机的简单介绍 最近公司做棋牌的项目,当时还是不理解什么是状态机,当一个项目做完之后,大脑里已经有了一个状态机的概念,所以今天就与大家分享出来,由于本人的技术博浅,有很多地方没有理解通透的地方,请望大神指点,抱拳了。 什么是状态机? 我理解的状态机就是,当一个事件触发之后,就会去寻找一个相对应的大的状态,然后在到大的状态里去寻找小的状态,然后执行完毕,给用户返回。 可能本人理解的不是多通透,在此边查资料边学习,与大家一起分享。 一丶状态模式 状态模式(State):当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类。 状态模式主要解决的是当控制一个对象状态转换的条件表达式过于复杂时的情况,把状态的判断逻辑转移到表示不同状态的一系列类当中,可以把复杂的逻辑简化,当然如果这个状态判断很简单,那就没有必要用 "状态模式" 了。 状态模式结构图 State类,抽象状态类,定义一个接口以封装与Context的一个特定状态相关的行为 abstract class State { public abstract void Handle(Context context) ; } State类 ConcreteState类,具体状态,每一个子类实现以个与Context的一个状态相关行为 ConcreteState类 Context类,维护一个ConcreteState子类的实列,这个实列定义当前的状态 class Context { private State state; public Context (State state) # 定义 Context的初始状态 { this.state = state; } public State State # 可读写的状态属性,用于读取当前状态和设置新状态 { get ( return state ;) set { state = value; Console.WriteLine("当前状态:" + state.GetType().Name); } } public void Request() { state.Handle(this); # 对请求做处理,并设置下一状态 } } Context类 客户端代码 state void Main (string[] args) { Context c = new Context(new ConcreteStateA()); # 设置Context的初始状态为ConcreteStateA c.Request(); c.Request(); c.Request(); c.Request(); # 不断请求,同事更改状态 Console.Read(); } 客户端代码 状态模式的好处与坏处 状态模式的好处是将于特定状态相关的行为局部化,并且将不同的状态的行为分割开来。 将特定的状态相关的行为都放入一个对象中,由于所有与状态相关的代码都存在与某个ConcreteState中,所以通过定义新的子类可以很容易地增加新的状态和转换。 这样做的目的是什么? 这样做的目的说白了就是为了消除庞大的条件分之语句,大的分之判断会使得它们难以修改和扩展,就想刻板和印刷一样,任何改动都是致命的,状态模式通过把各种状态转移逻辑分布到State的子类之间,来减少相互依赖,好比把整个版面改成一个又一个的活字,此时候就容易维护和扩展了。 什么时候应该考虑使用状态模式呢? 当一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为时,就可以考虑使用状态模式了。 参考设计模式举例 - 工作状态 代码结构图 抽象状态类,定义一个抽象方法"写程序" public abstract class State { public abstract void WriteProgram(Work w); } 抽象状态类 上午和中午工作状态类 pulic class ForenoonState : State { public override void WriteProgram (Work w) { if (w.Hour < 12) { Console.WriteLine("当前时间: {0}点 上午工作,精神百倍",w.Hour); } else { w.SetState(new NoonState());w.WriteProgram(); # 超过12点,则转入中午工作状态 } } } 上午工作状态类 public class NoonState : State { public override void WriteProgram(Work w) { if (w.Hour < 13){ Console.WriteLine("当前时间: {0}点 饿了,午饭:犯困,午休。", w.Hour); } else { w.SetState (new AfternoonState());w.WriteProgram(); # 超过13点则转入下午工作状态 } } } 中午工作状态 下午和傍晚工作状态类 public class AfternoonState : State { public override void WriteProgram (Work w) { if (w.Hour < 17) { Console.WriteLine("当前时间:{0}点 下午状态还不错,继续努力", w.Hour;) } else { w.SetState(new EveningState()); # 超过17点,则转入傍晚工作状态 w.WriteProgram(); } } } 下午工作状态 public class EveningState : State { public override void WriteProgram(Work w) { if (w.TaskFinished) { w.SetState(new RestState()); # 如果完成任务,则转入下班状态 w.WriteProgram(); } else { w.SetState(new SleepingState()); w.WriteProgram(); # 超过21点,则转入睡眠工作状态 } } } 晚间工作状态 睡眠状态和下班休息状态类 public class SleepingState : State { public override void WriteProgram(Work w) { Console.WriteLine("当前时间:{0}点不行了,睡着了。", w.Hour); } } 睡眠状态 public class RestState : State { public override void WriteProgram(Work w) { Console.WriteLine("当前时间:{0}点下班回家了", w.Hour); } } 下班休息状态 工作类 public class Work { private State current; public Work() # 工作初始化为上午工作状态,即上午9点开始上班 { current = new ForenoonState(); } private double hour; public double Hour {# 终点属性,状态转换的依据 get{return hour;} set{hour = value;} } private bool finish = false; public bool TaskFinished {# 任务完成属性,是否能下班的依据 get{return finish} set{finish= value} } public void SetState(State s) { current = s; } public void WriteProgram() { current.WriteProgram(this); } } 工作类 客户端代码 static void Main(string[] args); { //紧急项目 Work emergencyProjects = new Work(); energencyProjects.Hour = 9; Work emergencyProjects = new Work(); energencyProjects.Hour = 10; Work emergencyProjects = new Work(); energencyProjects.Hour = 12; Work emergencyProjects = new Work(); energencyProjects.Hour = 13; Work emergencyProjects = new Work(); energencyProjects.Hour = 14; Work emergencyProjects = new Work(); energencyProjects.Hour = 17; //emergencyProjects.WorkFinished = true; emergencyProjects.WorkFinished = false; Work emergencyProjects = new Work(); energencyProjects.Hour = 19; Work emergencyProjects = new Work(); energencyProjects.Hour = 22; Console.Read(); } 客户端代码 结果表现如下 1 当前时间:10点 上午工作, 精神百倍 2 当前时间:12点 饿了,午饭:犯困,午休 3 当前时间:13点 下午状态还不错,继续努力 4 当前时间:14点 下午状态还不错,继续努力 5 当前时间:17点 加班哦,疲劳之极 6 当前时间:19点 加班哦,疲劳之极 7 当前时间:22点 不行了,睡着了 状态机的理解,大概就是这样,从一个大的状态切换到一个小的状态。
取绝对值 a = abs(-95) print(a) 值有一个为假,就全为假 a = all([True,True,False]) print(a) 有一个为真,就全为真 a = any([False,True,True]) print(a) 返回一个可打印的对象字符串方式表示 a = ascii('0x\10000') b = ascii('b\x19') print(a,b) 将整数转换成二进制字符串 a= bin(95) print(a) 将以个数据转换成8进制 a = oct(95) print(a) 将一个数据转成十进制 a = int(95) print(a) 将整数转换成十六进制字符串 a = hex(95) print(type(a)) 转为布尔类型 a = bool("") print(a) 转换成字节形式bytes a = bytes("吴永聪",encoding='utf-8') print(a) chr返回一个字符串,其ascii码是一个整形,比如chr(97)返回字符串穿"a",桉树i的范围在0-255之间。 a = chr(88) print(a) ord参数是一个ascii字符,返回值是一个对应的十进制整数 a = ord("X") print(a) 创建数据字典 ret = dict({"wyc":2,"two":3}) dict(zip(("one","two"),(2,3))) dict(one=2,two=1) print(ret) dir列出某个类型的所有可用方法 a = dir(list) print(a) help查看帮助文档 ret = help(list) print(ret) 分别取商和余数 a = divmod(9,5) print(a) #计算表达式的值 a = eval('1+2*5') print(a) exec用来执行存储在字符串或文件中的python语句 ret = exec(print("Hi,girl.")) print(ret) filter 过滤 li = [1,2,3,4,5,6,7] a = filter(lambda x:x>3,li) print(a) float浮点型 a = float(1) print(a) 判断对象是不是属于int实列,返回True和False a = 5 b = isinstance(a,int) print(b) globals 返回全局变量 locals 返回当前局部变量 name = "wyc" def h1(): a = 1 print(locals()) h1() print(globals()) map遍历序列,对序列中每个元素进行操作,最终获取新的序列 li = [11,22,33] def func1(arg): return arg + 1 new_list = map(func1,li) for i in new_list:print(i) max 返回集合中的最大值 max min 返回集合中的最小值 min a = [1,2,3,4,5,6,7] s = max(a) n = min(a) print(s,n) pow 返回x的y次幂 a = pow(2,10) print(a) t = pow(2,10,100) print(t) round 四舍五入 a = round(9.5) print(a) sorted 队集合排序 char = ["吴","123","1","25","a","b","c"] new_chat = sorted(char) print(new_chat) for i in new_chat: print(bytes(i,encoding='utf-8')) sum求和的内容 a = sum([1,2,3,4,5]) print(a) a = sum(range(6)) print(a) __import__通过字符串的形式,导入模块 comm = input("Please:") ccas = __import__(comm) ccas.f1() #需要做拼接时后加 fromlist=True m = __import__("lib."+comm,fromlist=True) print(m)
time和datetime import time print(time.time()) #显示从系统时间到当前,1970年1月1日开始以秒计时 print(time.ctime()) #显示当前时间 print(time.ctime(time.time() - 86400)) #将时间戳转换成str格式 print(time.gmtime(time.time() - 86400)) #将时间戳转换成struct_time格式 print(time.localtime(time.time() - 86400) ) #将时间戳转换成struct_time格式返回本地时间 print(time.mktime(time.localtime())) #返回本地时间戳 print(time.strftime("%Y-%m-%d %H-%M-%S",time.gmtime())) #显示当前时间和当前年月日 print(type(time.strptime("2017-04-02","%Y-%m-%d"))) #将字符串格式转换成struct_time格式 # datetime import datetime print(datetime.date.today()) #输出当前年月日 格式2017-04-02 print(datetime.date.fromtimestamp(time.time() - 86400)) #将时间戳转换成格式日期86400,一天的时间戳 current_time = datetime.datetime.now() print(current_time) #输出2017-04-02 15:46:20.171962 print(current_time.timetuple()) #返回struct_time格式时间 print(current_time.replace(2008,8,8)) #当前时间被指定值给更换 str_to_date = datetime.datetime.strptime("28/7/08 11:20","%d/%m/%y %H:%M") print(str_to_date) #将字符串转换成日期格式 new_date = datetime.datetime.now() + datetime.timedelta(days=10) print(new_date) #比当前时间加十天 """ days = 10 比当前时间加10天 days = -10 比当前时间减10天 hours = -10 比当前时间减10小时 seconds=120 + 120s 比当前时间加120秒 """ random随机模块 random随机模块 #简单的随机验证码 import random temp = '' for i in range(6): num = random.randrange(0,4) if num == 0 or num == 3: rad2 = random.randrange(0,10) temp = temp + str(rad2) else: rad1 = random.randrange(65,91) c1 = chr(rad1) temp = temp + c1 print(temp) os模块 os模块用于提供系统级别的模块 os模块用于提供系统级别的操作 os.getcwd() 获取当前工作目录,即当前python脚本的目录路径 os.chdir("dirname") 改变当前脚本工作目录,相当于shell下的cd os.curdir 获取当前目录:('.') os.pardai 获取当前目录的父目录的字符串名:("...") os.makedirs('dir1/dir2') 可生成多层递归目录 os.removedirs('dirname1') 若目录为空,则删除,并递归到上一级目录,如若也为空则删除,以此类推 os.mkdir('dirname') 生成单级目录,相当于shell中mkdir dirname os.rmdir('dirname') 删除单级目录,若目录不为空则无法删除,报错,相当于shell中rmdir dirname os.listdir('dirname') 列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打开 os.remove() 删除一个文件 os.rename("oldname","new") 重命名,文件目录 os.stat('path/filename') 获取文件/目录信息 os.sep 操作系统特定的路径分隔符,win下为"\\",Linux下为"/" os.linesep 当前平台使用的行终止符,win下为"\t\n",Linux下为"\n" os.pathsep 用于分割文件路径的字符串 os.name 字符串指示当前使用平台。win->'nt',Linux-》’posix‘ os.system("bash command") 运行shell命令,直接显示 os.environ 获取系统环境变量 os.path.abspath(path) 返回path规范化的绝对路径 os.path.split(path) 将path分割成目录和文件名二元祖返回 os.path.dirname(path) 返回path的目录,其实就是os.path.split(path)的第一个元素 os.path.basename(path) 返回path的最后的文件名,如何path以/或\结尾,那么就会返回空值即os.path.split(path)的第二个元素 os.path.exists(path) 如果path存在,返回True,如果path不存在,返回False os.path.isabs(path) 如果path是绝对路径,返回True os.path.isfile(path) 如果path是一个存在的文件,返回True,否则返回False os.path.isdir(path) 如果path是一个存在的目录,则返回True,否则返回False os.path.join(path1[,path2[,....]]) 将多个路径组合返回,第一个绝对路径之前的参数将被忽略 os.path.getatime(path) 返回path所指向的文件或者目录的最后存取时间 os.path.getmtime(path) 返回path所指向的文件或者目录的最后修改时间 sys模块 sys用于提供解释器相关的操作(模块) sys.argv 命令行参数list,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时exit(0) sys.version 获取python解释程序版本信息 sys.maxint 最大的int值 sys.path 返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值 sys.platform 返回操作系统平台名称 sys.stdin 输入相关 sys.stdout 输出相关 sys.stderror 错误相关 进度条 手写进度条 import sys,time for ii in range(101): sys.stdout.write('\r') #每一次清空原行 sys.stdout.write("%s%% |%s|"%(int(int(ii)/100*100),int(int(ii)/100*100) * "#")) #一共次数除当前次数算进度 sys.stdout.flush() #强制刷新到屏幕 time.sleep(0.05)
list = ["a","b","c","d"] list.append("e") #往列表里边添加数据 print(list) list = ["a","b","c","d"] ret = list.insert(1,"f") #往列表位置插入数据 print(ret) list = ["a","b","c","d"] list.clear() #清空列表 print(list) list = ["a","b","c","d","a"] ret = list.count("a") #查看列表重复元素的个数 print(ret) pop : 移除元素 index: 索引元素的位置 del: 删除指定索引位置 sort: 对原列表排序 reverse: 反转列表 extend: 添加多个元素 字符串的基本操作: s = "hello word" print(s[1]) #索引出字符串位置的字符 partion : 字符串分割 replace : 字符串替换 元祖的基本操作: !!!!!元祖是不可修改的 count 查看元祖相同的元素个数 print(s[1]) 索引 print(s[1:]) 切片 字典的基本操作 a = user_name.get("user") 字典的key获取相对应的value a = user_name.values() 获取全部的values a = user_name.keys() 获取全部的keys a = user_name.items() 获取字典所有项的模式 user_name.popitem() 随机移除字典的一个key,value 应为字典是无序的 user_name.clear() 清空字典 s = user_name.copy() 浅拷贝所有key,value 如果key存在,则显示想对应的value,不存在则创建 a = user_name.setdefault("age") user_name.setdefault("ss") 将整个字典重新加入一个大的key,后面的字典成value d = dict.fromkeys(user_name) print(("wyc:%s") % str(d)) 将两个字典更新到一个字典里边 user_name.update(user_name1) set集合(无序,且不重复的) add 添加元素 alear 清空元素 pop 移除元素 remove 移除元素 update 更新元素 difference_update a中存在b中不存在则更新给a inrtersetion 交集,并且赋值给新值 intersection_update 交集,并更新给a symmetric_difference 对称交集 symmetric_difference_update 对称交集,更新到a union 并集,赋给新值 isdisjoint 如果没有交集饭会True,有的话则返回False issubset 是否是子序列 issuperset 是否是父序列 discard 移除指定元素, 不存在则报错 为迭代的对象添加序号, enuperate user_name = { "user":"wyc", "age":12, "jop":"python" } for k,v in enuperate(user_name,1): print(k,v,user_name.get(v)) 深浅拷贝 import copy #创建变量 a = 123 print(id(a)) #赋值 s = a print(s) #浅拷贝 ret = copy.copy(s) print(ret) #深拷贝 set = copy.deepcopy(s) print(set)
第一步创建一个新的项目 APPLICATIONNAME : 表示创建子项目 第二步:找到主项目的url 进行 include 分发式url 简单的说,就是将app里边的url放在这里。 这里也可以找到。 在下来一步就是在app里边的url里写url一定要注意,导入app下边的views url配置好了,接下来就进行写views里边的函数了。写函数时,后边一定要注意,添加一个request参数,应为前端传过来的 参数全部让request获取到了。接下来写函数里边的简单的登录验证返回子字符串的方法喽。全部写好之后一定要注意, setting里边的中间件是否注释CSRF跨域请求伪造。传过来的参数是unicode。 HTML一定要写进templates里边应为直接写进去,app的views里边的html会自动去templates里边去找。 Django简单一个验证就完成了。 HttpRequest里边的方法: path: 请求页面的全路径不包括域名。 method: 请求中使用的HTTP方法的字符串表示,(全部大写表示) GET: 包含所有Http GET参数的类字典对象。 POST: 包含所有HTTP POST参数类的字典对象 服务器收到空的POST请求的情况也是可能发生的,也就是说,表单form通过HTTP POST方法提交请求,但表单可能中可能没有数据,因此不能使用 if request.POST来判断是否使用了HTTP POST方法应该使用 if request.method =="POST": COOKIES: 包含所有cookies的标准python字典对象。key和values都是字符串。 FILES: 包含所有上传文的类字典对象。FILES中每一个key都是<input type="file" name="" />标签中。 filename : 上传文件名,用字符串表示。 content_type: 上传文件 content type content: 上传文件的原始内容。 SESSION: session是唯一可读写的属性,代表当前会话的字典对象,自己有激活django中的session支持时,改属性才可用。 HTTPResponse对象的方法: 在httpresponse扩展的常用的方法,页面渲染。 render,render_to_response,redirct,locals。 render:页面渲染, render(request,"index.html") render_to_response: 页面渲染, render_to_response("index.html") redirect:页面跳转, redirect("http://baidu.com") locals:获取全局变量 return (locals) Django用Terminal来输如命令创建数据表: 1: makemigrations 2: migrate
HTTP协议 一丶什么是HTTP协议: HTTP协议是hypertexttransferprotocol(超文本传输协议)的简写,它是TCP/IP协议的一个应用层协议,用于定义WEB浏览器服务器之间交换数据的过程,客户端连上web服务器后,若想获得web服务器中的某个资源,需遵守一定的通讯格式,HTTP协议用于定义客户端与web服务器通讯的格式。 二丶HTTP协议的版本有以下两种: HTTP协议版本:HTTP/1.0 、HTTP/1.1 三丶HTTP/1.0和1.1的区别 在HTTP1.0协议中,客户端与web服务器建立连接后,只能获得一个web资源。 在HTTP1.1协议中,允许客户端与web服务器建立连接后,在一个连接上获取多个web资源。 四丶HTTP协议请求: 1:HTTP协议请求由三部分组成,(请求行,消息报头,请求正文) 2:请求行: 请求行以一个方法符号开头,以空格分开,后面跟着请求的URL和协议的版本。 格式如下: Method Request-URL HTTP-Version CRLF Method:表示请求方法。 Request-URL:是一个统一资源标识符。 HTTP-Version:标识请求的HTTP协议版本。 CRLF:表示回车和换行(除了作为结尾的CRLF外,不允许出现单独的CR或LF字符。) 五丶请求方法:(Ps:所有请求方法均大写) GET: 请求获取Request-URL获取标识符的资源。 POST:在Request-URL获取标识的资源后添加新的数据。 HEAD:请求获取由Request-URL所标识的资源的响应消息报头。 PUT:请求服务器存储一个资源,并用Request-URL作为标识。 DELETE:请求服务器删除,Request-URL所标识的资源。 TRACE:请求服务器回送收到的请求消息,主要用于测试或诊断。 CONNECT:把服务器作为跳板,让服务器代替用户去访问其它网页,之后把数据原原本本的返回给用户。(Ps:这个方法需要使用TCP直接去连接的,所以不适合在网页开发中使用,不过网页开发中也用不到它。) OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项和需求。 TCP/IP协议 TCP/IP是一个大集合,所以统称TCP/IP协议。 TCP/IP分为四个层,每一层分一个职责,那个层除了问题直接维护那个层即可。 四层分为: 1:链路层 2:网络层 3:传输层 4:应用层 链路层的职责: 用来处理连接网络的硬件部分,包括控制操作系统硬件的设备驱动,NIC(Network.Interface.Card,网络适配器,既网卡)光纤等网络可见部分(还包括连接器等一切传输媒介),硬件上的范畴均在链路层的作用范围之内。 网络层的职责: 网络层用来处理在网络上流动的数据包,数据包是网络传输的最小单元,该层规定了通过怎样的路径(所谓的传输路线)到达对方计算机,并把数据包传送给对方,与对方计算机之间通过多台计算机或网络设备进行传输时,网络层所起的作用就是在众多的选项内选择一条传输路线。 传输层的职责: TCP(Transmission Control Protocol 传输控制协议) UDP(User Data Protaol 用户数据协议) 应用层的职责: FTP(File Transfer Protocol 文件传输协议) DNS(Domain Name System 域名系统Http协议) TCP/IP通信数据流:(PS:下图) HTTP关系密切的协议:IP、TCP和DNS IP协议: (Internet Protocol)这里的IP不是指的我们通常所说的:192.168.1.1,这个IP指的是一种协议,而后边的数字值是IP地址。 TCP协议: 如果说IP协议是我们找到对方的详细地址,那么TCP协议就是把安全的东西带给对方,各有分工,互不冲突。 DNS: DNS(Domain names System)和HTTP协议一样处于应用层的服务,提供域名到IP之间的解析服务。 各种协议的作用: HTTP协议职责: 生成针对目标,Web服务器的HTTP请求报文。 TCP协议职责: 为了方便通信,将HTTP请求报文分割成报文段,按序号分多个报文段,把每个报文段可靠的传给对方。 IP协议的职责: 搜索对方的地址,一边中转,一边发送。
初始多线程 import threading def Process(arg): print(arg) Process(1) #表示只有一个人去执行Process这个函数 for i in range(10): #创建十个线程一次次执行Process这个函数 t = threading.Thread(target=Process, args=(i,)) t.start() 多线程,多线程有一个好的东西就是线程池。 线程和进程的优缺点: 进程: 优点: 同时利用多个CPU,能够同时进行多个操作。 缺点: 耗费资源(重新开辟新的内存) 线程: 优点: 共享内存,IO操作的时候,创造并发操作。 缺点: 抢占资源。 进程不是越多越好,CPU个数 = 进程个数(有几个CPU最好创建几个进程) 线程也不是越多越好,具体案例,具体分析,(有几个线程创建几个线程,应为线程请求上下文时非常耗时) 进程和线程的目的是能够提高效率。 单线程和单进程的另一个名字: 主线程,主进程。 主线程可以创建子线程。 在计算机里边执行任务的最小单元是线程。 线程的应用的场景是在IO操作的时候,应为IO操作不用CPU, IO密集型: 适合用线程,IO(不用CPU) 计算密集型: 适合用进程,计算(用CPU) GIL: 在python里边叫全局解释器锁,锁一个进程里边的多个线程。 线程锁,threading.Rlock 和 threading.lock import threading import time globals_num = 0 lock = threading.Rlock() def Func(): lock.acquire() #获得锁 global globals_num globals_num += 1 time.sleep(1) #等待一秒 print (globals_num) lock.release() #释放锁 for i in range(10): #创建十个线程,每个线程都执行一遍Func函数 t = threading.Thread(target=Func) t.start()
网络的层次说明 核心层:核心层的功能主要是实现骨干网络时间的优化传输,骨干层设计任务的重点通常是冗余能力,可靠性和高速的传输. 汇聚层:汇聚层是楼群或小区的信息汇聚点,是连接介入层和核心层的网络设备,为接入层提供数据的汇聚\传输\管理\分发处理.汇聚层为接入层提供基于策略的连接,如地址合并,协议过滤,路由服务,认证管理等,通过网络划分(如VLAN)与网络隔离可以防止某些网段的问题蔓延和影响到核心层,汇聚层同时也可以提供接入层虚拟网之间的互连,控制和限制接入层对核心层的访问,保证核心层的安全和稳定. 接入层:接入层通常指网络中直接面向用户连接或访问的部分,接入层目的是允许终端用户连接到网络,因此用户连接到网络,因此接入层交换机具有低成本和高端口密度特性. OSI网络模型概念 OSI 的概念: open system interconnect 开放系统互连参考模型,是由ISO(国际标准化组织)定义的,是个灵活的,稳健的和可互操作的模型,并不是协议,是用来了解和设计网络体系结构的. OSI模型的目的: 规范不同系统的互联标准,使两个不同系统能够较容易的通信,而不需要改变底层的硬件或软件的逻辑 OSI模型分为七层: OSI把网络按照层次分为7层,由下到上分别为物理层,数据链路层,网络层,传输层,会话层,表示层,应用层. 为山么分为7层 上层分为(Boss 秘书 商务) 秘书可以负责将信息进行编码,然后将数据加密和压缩等,将Boss的信息传给商务部. 传输层(销售部/采购部),作为一个传输的通道,进行长期的连接,可以将从上层获得的流量进行一个分段. ①进行连接会话的建立,并且可以是可靠的连接. ②将上层的数据进行分块/分段. 网络层(邮局):将打包的设备运输到家门口,进行拆包,分给公司内部的每一个人,也负责将上层的打包分派给底层的搬运工. 物理层:就相当于搬运工 OSI7层模型的结构: 可以依据OSI参考模型,作为一个通信的依据. 特点说明: 1,OSI模型每层都有自己的功能集 2,层与层之间相互独立有互相依靠 3,上层依赖于下层,下层为上层提供服务. OSI层次 --- 应用层 主要就是提供应用程序可以接入网络接口,并根据程序的不同对应不同的接口协议. OSI层次 --- 表示层 OSI层次 --- 会话层 OSI层次 --- 传输层 负责网络中端到端的连接(TCP UDP) OSI层次 --- 网络层 网络层的主要作用就是路由和寻址,主要接触到的是IP协议即IP地址 layer3网络层: 对应设备有路由器 路由器的作用: 1, 广播,组播控制 2, 对数据做寻址,选择到达目的网络的最佳路径 3, 流量管理 4, 连接广域网(WAN) IP地址概念说明: 根据地址的概念,来举例介绍网络号和主机号的概念,以及路由寻址和路由的概念. OSI层次 --- 数据链路层 Layer2数据链路层:MAC层-IEEE 802.3协议,MAC地址是48bit的 IP地址是三层地址,那么MAC地址就是二层地址,全球网络设备唯一的地址, 作用域的不同:IP作用在不同的网络之间,MAC地址作用在相同的网络你不 MAC地址48位的地址,采用16进制进行表示 MAC地址是硬件地址,IP地址会被看做是逻辑地址 layer2数据链路层;对应设备有交换机 OSI层次 --- 物理层 就是将逐个的bit进行传输的过程 网络物理连接介质 网线 要连接局域网,网线是必不可少的,在局域网中常见的网线主要为双绞线,双绞线,是有许多线组成的数据传输线,它的特点就是价格便宜,所以被广泛应用,如我们常见的电话线等,它是用来和RJ45水晶头相连的. 制作规范: 568A 568B 线序: 橙白 橙 绿白 蓝 蓝白 绿 棕白 棕 光纤线: OSI层次模型总结: OSI7层模型功能就类似于人类传递信息,会用一句话传递,而一句话又是多个词组成,而每个词又是多个字组成.
1丶初始网络 网络的体系是一个庞大的体系,涉及到路由交换,安全,无线,语言,数据中心等等多个方面. ①网络基础知识:涉及到网络的发展历程,网络的一些名词概念,路由交换介绍 ②OSI七层模型的介绍 ③TCP/IP协议簇的简介,包含TCP/IP三次握手和四次挥手的过程 ④VLSM可变长子网的概念 2丶网络拓扑 网络拓扑(Network Topology)结构是指用传输介质互连各种设备的物理布局。指构成 网络的成员间特定的物理的即真实的、或者逻辑的即虚拟的排列方式。如果两个网络的 连接结构相同我们就说它们的网络拓扑相同,尽管它们各自内部的物理接线、节点间距 离可能会有不同。 实质上网络拓扑就是类似于网络设备组成的一个连接图,通过设备的连接图可以判断设 备的连接情况,便于出现故障时,根据拓扑图更快的定位故障点。 对于配置网络设备之前,一定要对网络设备进行规划,也就是网络设备如何进行连接, 进而形成一个网络设备的连接图,即网络拓扑(类似于网络设备规划的地图) 3丶网络的概念与发展 简单 理解网络的概念: 就是计算机网络,有许许多多电子设备互联构建而成的一个IP的网络。 网络的 演变发展过程:简单的网络,是由两根网线将两个网络设备连接起来 。 在简单的网络环境中,就出现了 IP 地址的概念,类似于人的名字一样,便于互联 访问;IP地址作为网络中的任意一个节点的标识符出现在网络中 互连的网络,由于网络规模的壮大,就需要一个更科学的网络拓扑, 因此出现了 HUB(是一个总线) 但是HUB会出现冲突域的概念,某一时段,HUB接口中,只能有一个用户建立数 据链路,和目的端进行通信,其它接口处于监听的状态(CSMA/CD技术) 由于上面的问题,因此随着网络的发展引入了交换机设备,可以有效的解决上面所 出现的问题 。 4丶 交换机(switch) 厂商:DLINK,H3C,CISCO,所有服务器接到交换机上互相通信。 交换机(英文:Switch,意为“开关”)是一种用于电信号转发的网络设备。它可以 为接入交换机的任意两个网络节点提供独享的电信号通路。最常见的交换机是以太 网交换机。其他常见的还有电话语音交换机、光纤交换机等。 http://baike.baidu.com/link?url=aB0qKNPOyqcbX44601L8empFSMgD4bw eoyrmx7AX1Dxj_-E6NfhvqMdct15M753baptl_95xb8q9c-2aed8FSK 交换机的作用和特点说明 在一个交换机的端口上所连接的所有终端设备,均在一个网段上(称为一个广 播域)。 并且一个网段会有一个统一的网络标识,会产生广播消耗设备CPU资源 交换机可以隔离冲突域,每一个端口就是一个冲突域 终端用户的设备接入 基本的安全功能 广播域的隔离(VLAN) 广播域的介绍: 当一个交换机连接多个终端设备,多个终端设备即处于一个相同的网段中,而一个 相同的网段,即表示一个广播域 广播方式不会根据需要传输或接收消息,而是在一个网段中全部机器都要进行无条 件接收,因此当广播信息大量产生时,会耗费网段机器的 CPU资源,来接收广播 信息,即所谓的广播风暴 两个不同的广播域是不能进行通信的,因为所属在不同的两个网段中 提示:相同的网段就是一个统一的网络标识 . 5丶路由器(router) 路由器(Router),是连接因特网中各局域网、广域网的设备,它会根据信道的情 况自动选择和设定路由,以最佳路径,按前后顺序发送信号。OSPF路由协议,大 企业RIP,静态路由(route) http://baike.baidu.com/link?url=4AD4Cz9hy6QNpi5LfdqHM5Zb_0dVc6eo 6Pu5ym7a5QuFOgoweTyBiz7QHetg5_bOoWI46NSeNVUnAP5O2nTd3K CISCO,广域网、公网互联需要路由器,路由器不转发私网地址。 路由器的实质是隔离广播域,是两个广播域之间信息互通,也就是使两个不同的网 段之间互相连通。 路由器的作用和特点说明 : 路由协议的转发 路由类似于现实生活中从 A 地去往 B 地可能需要先步行,在坐车,在做飞机 才能到达B地,这样的整个过程在网络中对应数据的传递过程就称为路由。 因此一个数据信息跨越不同的网段传递到目的地址,就可以把传递数据的过程 称为路由,也可以看做每条传递数据的路径。 数据转发,会维护一个路由表(相当于一个地图) 路由器会作为网关 一般会在网络出口的位置摆放一台路由器 广域网链路支持 协议 : 协议是通信双方为了实现通信而设计的约定或通话规则。 http 协议,tcp/ip 协议族。 必须会的: 1、tcp/ip 协议的三次握手和四次断开过程。 2、http 协议的工作原理(拔高). 1.1园区网简单介绍 待更新.........
简单工厂模式 最近朋友推荐了一本书《大话设计模式》,此书刚刚到,博主也还没开始看,希望以博文的方式与大家一起分享,一起学习. 简单工厂模式,也就是说,到底要实列化谁,将来会不会增加实列化的对象,比如增加开根运算,这是很容易实列化的地方应该考虑用一个单独的类来做这个创造实列的过程,这就是工厂,来我们一起看看这个类如何写。 简单运算工厂类: import public public class OperationFactory { public static OperationFactory(string operate) { Operation oper = null; switch (operate) { case "+"; oper = new OperationFactory(); break; case "-"; oper = new OperationFactory(); break; case "*"; oper = new OperationFactory(); break; case "/"; oper = new OperationFactory(); break; } return oper; } } 看到了吧,这样子只需要输入运算符号,工厂就实列出合适的对象,通过多态,返回父类的方式实现了计算器的结果。 客户端代码: #客户端代码 Operation oper; oper = OperationFactory.createOperate("+"); oper.NumberA = 1; oper.NumberB = 2; double result = oper.GetResult(); 界面实现就是这样的代码、不管你是控制台程序,Windows 程序, Web 程序, PDA或手机程序,都可以用这段代码来实现计算器的功能,如果有一天我们需要更改加法运算,我们只需要改 (OperationADD)就可以了,那么我们需要增加各种复杂运算,比如平方根,立方根,自然对数,正弦和余弦等,那么如何做呢?(只要增加相应的运算子类就可以了),增加之后,还得需要去修改一下运算类工厂,在switch中增加分支。 写到这,不知不觉到结尾了,这就是简单的工厂模式,以下是几个类的结构图. 模式还有很多......待更新
RabbitMQ 一,RabbitMQ简单介绍: RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统。他遵循Mozilla Public License开源协议。 MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法。应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们。消 息传递指的是程序之间通过在消息中发送数据进行通信,而不是通过直接调用彼此来通信,直接调用通常是用于诸如远程过程调用的技术。排队指的是应用程序通过 队列来通信。队列的使用除去了接收和发送应用程序同时执行的要求。 二,安装 pip install pika 三,简单队列 1丶使用API操作RabbitMQ 基于Queue实现生产者消费者模型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #!/usr/bin/env python # -*- coding:utf-8 -*- import Queue import threading message = Queue.Queue(10) def producer(i): while True: message.put(i) def consumer(i): while True: msg = message.get() for i in range(12): t = threading.Thread(target=producer, args=(i,)) t.start() for i in range(10): t = threading.Thread(target=consumer, args=(i,)) t.start() View Code 对于RabbitMQ来说,生产和消费不再针对内存里的一个Queue对象,而是某台服务器上的RabbitMQ Server实现的消息队列。 # !/usr/bin/env python # -*- coding:utf-8 -*- import pika connection = pika.BaseConnection(pika.ConnectionParameters(host='10.211.55.4')) # 封装socket逻辑部分 channel = connection.channel() # 拿到操作句柄 channel.queue_declare(queue='hello') # 通过channel创建一个队列,再给给队列取名字 channel.basic_publish(exchange='', # 通过句柄给 routing_key='hello', # 把body的数据放到名为hello的队列里去 body='Hello World!', )) print("[x] Sent 'Hello World!") connection.close() 生产者 # !/usr/bin/env python # -*- coding:utf-8 -*- import pika connection = pika.BaseConnection(pika.ConnectionParameters(host='10.211.55.4')) channel = connection.channel() channel.queue_declare(queue='hello') # 创建队列 def callback(ch, method, properties, body): # 就是个回调函数 print(" [x] Received %r" % body) channel.basic_consume(callback, # 函数名;取出数据就执行这个函数 queue='hello', # 队列名 no_ack=Ture) # 无应答是(Ture);有应答(False) print(' [*] Waiting for messages.To exit press CTRL+C') channel.start_consuming() 消费者 2丶acknowledgment消息不丢失 no-ack = False,如果消费者遇到情况(its channel is closed, connection is closed, or TCP connection is lost)挂掉了,那么,RabbitMQ会重新将该任务添加到队列中。 # !/usr/bin/env python # -*- coding:utf-8 -*- import pika connection = pika.BaseConnection(pika.ConnectionParameters(host='10.211.55.4')) channel = connection.channel() channel.queue_declare(queue='hello') # 创建队列 def callback(ch, method, properties, body): # 就是个回调函数 print(" [x] Received %r" % body) import time time.sleep(10) print('ok') ch.basic_ack(delivery_tag=method.delivery_tag) # 调为有应答要加上的(下面的要改no_ack=False) channel.basic_qos(prefetch_count=1) channel.basic_consume(callback, # 函数名;取出数据就执行这个函数 queue='hello', # 队列名 no_ack=False) # 无应答是(Ture);有应答(False) print(' [*] Waiting for messages.To exit press CTRL+C') channel.start_consuming() 消费者 3丶durable消息不丢失 import pika connection = pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.4')) channel = connection.channel() # make message persistent channel.queue_declare(queue='hello', durable=True) # durable=True这个参数是把数据保存到硬盘 channel.basic_publish(exchange='', routing_key='hello', body='Hello World!', properties=pika.BasicProperties( delivery_mode=2, # 传递模式从默认的1,改为2 )) print(" [x] Sent 'Hello World!'") connection.close() 生产者 #!/usr/bin/env python # -*- coding:utf-8 -*- import pika connection = pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.4')) channel = connection.channel() # make message persistent channel.queue_declare(queue='hello', durable=True) def callback(ch, method, properties, body): print(" [x] Received %r" % body) import time time.sleep(10) print 'ok' ch.basic_ack(delivery_tag = method.delivery_tag) # 把无应答调整为有应答 channel.basic_consume(callback, queue='hello', no_ack=False) # 改为False,表示有应答 print(' [*] Waiting for messages. To exit press CTRL+C') channel.start_consuming() 消费者 4丶消息获取顺序 默认消息队列里的数据是按照顺序被消费者拿走,例如:消费者1 去队列中获取 奇数 序列的任务,消费者1去队列中获取 偶数 序列的任务。 channel.basic_qos(prefetch_count=1) 表示谁来谁取,不再按照奇偶数排列 #!/usr/bin/env python # -*- coding:utf-8 -*- import pika connection = pika.BlockingConnection(pika.ConnectionParameters(host='10.211.55.4')) channel = connection.channel() # make message persistent channel.queue_declare(queue='hello') def callback(ch, method, properties, body): print(" [x] Received %r" % body) import time time.sleep(10) print 'ok' ch.basic_ack(delivery_tag = method.delivery_tag) channel.basic_qos(prefetch_count=1) # prefetch_count=1这个参数就让取的方式改变,不在顺序取数据 channel.basic_consume(callback, queue='hello', no_ack=False) print(' [*] Waiting for messages. To exit press CTRL+C') channel.start_consuming() 消费者 四,exchange 1、fanout模式 发布订阅 发布订阅和简单的消息队列区别在于,发布订阅会将消息发送给所有的订阅者,而消息队列中的数据被消费一次便消失。 所以,RabbitMQ实现发布和订阅时,会为每一个订阅者创建一个队列,而发布者发布消息时,会将消息放置在所有相关队列中。 exchange type = fanout #!/usr/bin/env python import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() # 创建交换机 channel.exchange_declare(exchange='logs', # 名字 type='fanout') # 类型 message = ' '.join(sys.argv[1:]) or "info: Hello World!" channel.basic_publish(exchange='logs', # 往名字为logs的交换机里 routing_key='', # 把数据直接放到交换机里,不用放到队列中,所以默认为空 body=message) print(" [x] Sent %r" % message) connection.close() # 关闭 发布者 #!/usr/bin/env python import pika connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() #创建交换机 channel.exchange_declare(exchange='logs', type='fanout') # 随机创建一个队列 result = channel.queue_declare(exclusive=True) queue_name = result.method.queue channel.queue_bind(exchange='logs', # 随机生成的队列绑定交换机 queue=queue_name) print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body): print(" [x] %r" % body) channel.basic_consume(callback, # 在下面阻塞后,如果得到数据后才执行这个函数 queue=queue_name, no_ack=True) channel.start_consuming() # 阻塞住,等待生产者把数据放到消费者,并监听 订阅者 图形解释: 2、dirct模式 关键字发送 RabbitMQ 还支持根据关键字发送,即:队列绑定关键字,发送者将数据根据关键字发送到消息exchange, exchange 根据 关键字 判定应该将数据发送至指定队列。 exchange type = direct #!/usr/bin/env python import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() channel.exchange_declare(exchange='direct_logs', type='direct') severity = sys.argv[1] if len(sys.argv) > 1 else 'info' message = ' '.join(sys.argv[2:]) or 'Hello World!' channel.basic_publish(exchange='direct_logs', routing_key=severity, body=message) print(" [x] Sent %r:%r" % (severity, message)) connection.close() 生产者 #!/usr/bin/env python import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() channel.exchange_declare(exchange='direct_logs', type='direct') result = channel.queue_declare(exclusive=True) queue_name = result.method.queue severities = sys.argv[1:] if not severities: sys.stderr.write("Usage: %s [info] [warning] [error]\n" % sys.argv[0]) sys.exit(1) for severity in severities: # 用循环是可以绑定多个队列 channel.queue_bind(exchange='direct_logs', queue=queue_name, routing_key='severity') # 定义的参数(关键字) channel.queue_bind(exchange='direct_logs', queue=queue_name, routing_key='alex') print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body): print(" [x] %r:%r" % (method.routing_key, body)) channel.basic_consume(callback, queue=queue_name, no_ack=True) channel.start_consuming() 消费者 图形解释: 在交换机中用一关键字,只有队列里有关键字交换机才会发送数据给绑定的队列。 3、topic 模糊匹配 在topic类型下,可以让队列绑定几个模糊的关键字,之后发送者将数据发送到exchange,exchange将传入”路由值“和 ”关键字“进行匹配, 匹配成功,则将数据发送到指定队列。exchange type = topic # 表示可以匹配 0 个 或 多个 单词 * 表示只能匹配 一个 单词 发送者路由值 队列中 old.boy.python old.* -- 不匹配 old.boy.python old.# -- 匹配 #!/usr/bin/env python import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() channel.exchange_declare(exchange='topic_logs', type='topic') routing_key = sys.argv[1] if len(sys.argv) > 1 else 'anonymous.info' message = ' '.join(sys.argv[2:]) or 'Hello World!' channel.basic_publish(exchange='topic_logs', routing_key=routing_key, body=message) print(" [x] Sent %r:%r" % (routing_key, message)) connection.close() 生产者 #!/usr/bin/env python import pika import sys connection = pika.BlockingConnection(pika.ConnectionParameters( host='localhost')) channel = connection.channel() channel.exchange_declare(exchange='topic_logs', type='topic') result = channel.queue_declare(exclusive=True) queue_name = result.method.queue binding_keys = sys.argv[1:] if not binding_keys: sys.stderr.write("Usage: %s [binding_key]...\n" % sys.argv[0]) sys.exit(1) for binding_key in binding_keys: channel.queue_bind(exchange='topic_logs', queue=queue_name, routing_key=binding_key) print(' [*] Waiting for logs. To exit press CTRL+C') def callback(ch, method, properties, body): print(" [x] %r:%r" % (method.routing_key, body)) channel.basic_consume(callback, queue=queue_name, no_ack=True) channel.start_consuming() 消费者 图形解释:
同步,异步(一) 同步: 主机A发送数据的时候,主机B必须等待接收,处于阻塞状态,这就好比别人给你打电话,你必须当场听话,否则则【错失良机】。 异步: 主机A发送数据的时候,主机B无须等待接收,主机B要获得数据就从缓存里取,就好比别人给你发邮件一样。 同步,异步(二) 异步 调用是通过使用单独的线程执行的。原始线程启动异步调用,异步调用使用另一个线程执行请求,而与此同时原始的线程继续处理。同步 调用则在继续之前必须等待响应或返回值。如果不允许调用继续即无响应或返回值,就说调用被阻塞了,不能继续执行。
Model 到目前为止,当我们的程序涉及到数据库相关操作时,我们一般都会这么搞: 创建数据库,设计表结构和字段 使用MySQLdb 来连接数据库,并编写数据访问层代码 业务逻辑层去调用数据访问层执行数据库操作 import MySQLdb def GetList(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost') cursor = db.cursor() cursor.execute(sql) data = cursor.fetchall() db.close() return data def GetSingle(sql): db = MySQLdb.connect(user='root', db='wupeiqidb', passwd='1234', host='localhost') cursor = db.cursor() cursor.execute(sql) data = cursor.fetchone() db.close() return data View Code django为使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM) (ORM):就是用面向对象的方式去操作数据库的创建表以及增删改查等操作 创建表 1丶基本表结构 注意: 1、创建表的时候,如果我们不给表加自增列,生成表的时候会默认给我们生成一列为ID的自增列,当然我们也可以自定义 2、如果我们给某一列设置了外键的时候,生成表的时候,该列的表名会自动生成auter_id(即俩个字段中间用_连接起来) 3、创建外键的时候 models.ForeignKey(UserType) ForeignKey中参数代表的类必须在其上面,否则就必须写成字符串的形式 from django.db import models class userinfo(models.Model): nid = models.AutoField(primary_key=True) name = models.CharField(max_length=30) email = models.EmailField() memo = models.TextField() class Meta: verbose_name = '用户名' verbose_name_plural = verbose_name def __str__(self): #相当于tornado中的__repr__ return self.name class Host_To_Group(models.Model): nid = models.AutoField(primary_key=True) host_id = models.ForeignKey('Host') group_id = models.ForeignKey('Group') class Meta: index_together = ('host_id','Group') #联合索引 unique_together = [ #联合唯一索引 ('host_id', 'Group') ] 1 models.AutoField 自增列 = int(11) 2 如果没有的话,默认会生成一个名称为 id 的列,如果要显示的自定义一个自增列,必须将给列设置为主键 primary_key=True。 3 models.CharField 字符串字段 4 必须 max_length 参数 5 models.BooleanField 布尔类型=tinyint(1) 6 不能为空,Blank=True 7 models.ComaSeparatedIntegerField 用逗号分割的数字=varchar 8 继承CharField,所以必须 max_lenght 参数 9 models.DateField 日期类型 date 10 对于参数,auto_now = True 则每次更新都会更新这个时间;auto_now_add 则只是第一次创建添加,之后的更新不再改变。 11 models.DateTimeField 日期类型 datetime 12 同DateField的参数 13 models.Decimal 十进制小数类型 = decimal 14 必须指定整数位max_digits和小数位decimal_places 15 models.EmailField 字符串类型(正则表达式邮箱) =varchar 16 对字符串进行正则表达式 17 models.FloatField 浮点类型 = double 18 models.IntegerField 整形 19 models.BigIntegerField 长整形 20 integer_field_ranges = { 21 'SmallIntegerField': (-32768, 32767), 22 'IntegerField': (-2147483648, 2147483647), 23 'BigIntegerField': (-9223372036854775808, 9223372036854775807), 24 'PositiveSmallIntegerField': (0, 32767), 25 'PositiveIntegerField': (0, 2147483647), 26 } 27 models.IPAddressField 字符串类型(ip4正则表达式) 28 models.GenericIPAddressField 字符串类型(ip4和ip6是可选的) 29 参数protocol可以是:both、ipv4、ipv6 30 验证时,会根据设置报错 31 models.NullBooleanField 允许为空的布尔类型 32 models.PositiveIntegerFiel 正Integer 33 models.PositiveSmallIntegerField 正smallInteger 34 models.SlugField 减号、下划线、字母、数字 35 models.SmallIntegerField 数字 36 数据库中的字段有:tinyint、smallint、int、bigint 37 models.TextField 字符串=longtext 38 models.TimeField 时间 HH:MM[:ss[.uuuuuu]] 39 models.URLField 字符串,地址正则表达式 40 models.BinaryField 二进制 41 models.ImageField 图片 42 models.FilePathField 文件 AutoField 一个 IntegerField, 添加记录时它会自动增长. 你通常不需要直接使用这个字段; 如果你不指定主键的话,系统会自动添加一个主键字段到你的 model.(参阅 _自动主键字段) BooleanField A true/false field. admin 用 checkbox 来表示此类字段. CharField 字符串字段, 用于较短的字符串. 如果要保存大量文本, 使用 TextField. admin 用一个 <input type="text"> 来表示此类字段 (单行输入). CharField 要求必须有一个参数 maxlength, 用于从数据库层和Django校验层限制该字段所允许的最大字符数. CommaSeparatedIntegerField 用于存放逗号分隔的整数值. 类似 CharField, 必须要有 maxlength 参数. DateField 一个日期字段. 共有下列额外的可选参数: Argument 描述 auto_now 当对象被保存时,自动将该字段的值设置为当前时间.通常用于表示 "last-modified" 时间戳. auto_now_add 当对象首次被创建时,自动将该字段的值设置为当前时间.通常用于表示对象创建时间. admin 用一个文本框 <input type="text"> 来表示该字段数据(附带一个 JavaScript 日历和一个"Today"快键. DateTimeField 一个日期时间字段. 类似 DateField 支持同样的附加选项. admin 用两上文本框 <input type="text"> 表示该字段顺序(附带JavaScript shortcuts). EmailField 一个带有检查 Email 合法性的 CharField,不接受 maxlength 参数. FileField 一个文件上传字段. 要求一个必须有的参数: upload_to, 一个用于保存上载文件的本地文件系统路径. 这个路径必须包含 strftime formatting, 该格式将被上载文件的 date/time 替换(so that uploaded files don't fill up the given directory). admin 用一个``<input type="file">``部件表示该字段保存的数据(一个文件上传部件) . 在一个 model 中使用 FileField 或 ImageField 需要以下步骤: 在你的 settings 文件中, 定义一个完整路径给 MEDIA_ROOT 以便让 Django在此处保存上传文件. (出于性能考虑,这些文件并不保存到数据库.) 定义 MEDIA_URL 作为该目录的公共 URL. 要确保该目录对 WEB 服务器用户帐号是可写的. 在你的 model 中添加 FileField 或 ImageField, 并确保定义了 upload_to 选项,以告诉 Django 使用 MEDIA_ROOT 的哪个子目录保存上传文件. 你的数据库中要保存的只是文件的路径(相对于 MEDIA_ROOT). 出于习惯你一定很想使用 Django 提供的 get_<fieldname>_url 函数.举例来说,如果你的 ImageField 叫作 mug_shot, 你就可以在模板中以 {{ object.get_mug_shot_url }} 这样的方式得到图像的绝对路径. FilePathField 可选项目为某个特定目录下的文件名. 支持三个特殊的参数, 其中第一个是必须提供的. 参数 描述 path 必需参数. 一个目录的绝对文件系统路径. FilePathField 据此得到可选项目. Example: "/home/images". match 可选参数. 一个正则表达式, 作为一个字符串, FilePathField 将使用它过滤文件名. 注意这个正则表达式只会应用到 base filename 而不是路径全名. Example: "foo.*\.txt^", 将匹配文件 foo23.txt 却不匹配 bar.txt 或 foo23.gif. recursive 可选参数.要么 True 要么 False. 默认值是 False. 是否包括 path 下面的全部子目录. 这三个参数可以同时使用. 我已经告诉过你 match 仅应用于 base filename, 而不是路径全名. 那么,这个例子: FilePathField(path="/home/images", match="foo.*", recursive=True) ...会匹配 /home/images/foo.gif 而不匹配 /home/images/foo/bar.gif FloatField 一个浮点数. 必须 提供两个 参数: 参数 描述 max_digits 总位数(不包括小数点和符号) decimal_places 小数位数 举例来说, 要保存最大值为 999 (小数点后保存2位),你要这样定义字段: models.FloatField(..., max_digits=5, decimal_places=2) 要保存最大值一百万(小数点后保存10位)的话,你要这样定义: models.FloatField(..., max_digits=19, decimal_places=10) admin 用一个文本框(<input type="text">)表示该字段保存的数据. ImageField 类似 FileField, 不过要校验上传对象是否是一个合法图片.它有两个可选参数:height_field 和 width_field,如果提供这两个参数,则图片将按提供的高度和宽度规格保存. 该字段要求 Python Imaging Library. IntegerField 用于保存一个整数. admin 用一个``<input type="text">``表示该字段保存的数据(一个单行编辑框) IPAddressField 一个字符串形式的 IP 地址, (i.e. "24.124.1.30"). admin 用一个``<input type="text">``表示该字段保存的数据(一个单行编辑框) NullBooleanField 类似 BooleanField, 不过允许 NULL 作为其中一个选项. 推荐使用这个字段而不要用 BooleanField 加 null=True 选项. admin 用一个选择框 <select> (三个可选择的值: "Unknown", "Yes" 和 "No" ) 来表示这种字段数据. PhoneNumberField 一个带有合法美国风格电话号码校验的 CharField``(格式: ``XXX-XXX-XXXX). PositiveIntegerField 类似 IntegerField, 但取值范围为非负整数(这个字段应该是允许0值的....所以字段名字取得不太好,无符号整数就对了嘛). PositiveSmallIntegerField 类似 PositiveIntegerField, 取值范围较小(数据库相关) SlugField "Slug" 是一个报纸术语. slug 是某个东西的小小标记(短签), 只包含字母,数字,下划线和连字符.它们通常用于URLs. 若你使用 Django 开发版本,你可以指定 maxlength. 若 maxlength 未指定, Django 会使用默认长度: 50. 在以前的 Django 版本,没有任何办法改变 50 这个长度. 这暗示了 db_index=True. 它接受一个额外的参数: prepopulate_from, which is a list of fields from which to auto-populate the slug, via JavaScript, in the object's admin form: models.SlugField(prepopulate_from=("pre_name", "name")) prepopulate_from 不接受 DateTimeFields. admin 用一个``<input type="text">``表示 SlugField 字段数据(一个单行编辑框) SmallIntegerField 类似 IntegerField, 不过只允许某个取值范围内的整数.(依赖数据库) TextField 一个容量很大的文本字段. admin 用一个 <textarea> (文本区域)表示该字段数据.(一个多行编辑框). TimeField A time. Accepts the same auto-population options as DateField 和 DateTimeField. admin 用一个 <input type="text"> 文本框表示该字段保存的数据(附加一些JavaScript shortcuts). URLField 用于保存 URL. 若 verify_exists 参数为 True (默认), 给定的 URL 会预先检查是否存在(即URL是否被有效装入且没有返回404响应). admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框) USStateField 一个两字母的美国州名缩写. admin 用一个 <input type="text"> 文本框表示该字段保存的数据(一个单行编辑框) XMLField 一个校验值是否为合法XML的 TextField,必须提供参数: schema_path, 它是一个用来校验文本的 RelaxNG schema 的文件系统路径. 更多字段 1、null=True 数据库中字段是否可以为空 2、blank=True django的 Admin 中添加数据时是否可允许空值 3、primary_key = False 主键,对AutoField设置主键后,就会代替原来的自增 id 列 4、auto_now 和 auto_now_add auto_now 自动创建---无论添加或修改,都是当前操作的时间 auto_now_add 自动创建---永远是创建时的时间 5、choices GENDER_CHOICE = ( (u'M', u'Male'), (u'F', u'Female'), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE) 6、max_length 7、default 默认值 8、verbose_name Admin中字段的显示名称 9、name|db_column 数据库中的字段名称 10、unique=True 不允许重复 11、db_index = True 数据库索引 12、editable=True 在Admin里是否可编辑 13、error_messages=None 错误提示 14、auto_created=False 自动创建 15、help_text 在Admin中提示帮助信息 16、validators=[] 17、upload-to 更多参数 通过内部类Meta给数据模型类增加扩展属性: class Meta: verbose_name='名称' #表名由英文转换成中文了 verbose_name_plural='名称复数形式' ordering='排序字段' 2、连表结构(当我们在类中写上这样的字段后,就会为我们自动创建一张关系表) 一对多: models.ForeignKey(其他表) 一对多: 就是主外键关系 多对多: models.ManyToManyField(其他表) 多对多:多个主外键的关系 一对一:models.OneToOneField(其他表) 一对一:实质就是在主外键的关系基础上,给外键加了 问:什么是一对一,一对多,多对多? 答:一对一:一般用于某张表的补充,比如用户基本信息是一张表,但并非每一个用户都需要有登录的权限,不需要记录用户名和密码,此时,合理的做法就是新建一张记录登录信息的表,与用户信息进行一对一的关联,可以方便的从子表查询母表信息或反向查询 外键:有很多的应用场景,比如每个员工归属于一个部门,那么就可以让员工表的部门字段与部门表进行一对多关联,可以查询到一个员工归属于哪个部门,也可反向查出某一部门有哪些员工 多对多:如很多公司,一台服务器可能会有多种用途,归属于多个产品线当中,那么服务器与产品线之间就可以做成对多对,多对多在A表添加manytomany字段或者从B表添加,效果一致. 操作表 1丶基本操作 用于获取后台提交的数据 username = req.POST.get("username") password = req.POST.get("password") 增: models.tb1.objects.create(c1='xx',c2='oo') -----增加一条数据,可以接受字典类型数据 **kwargs obj = models.Tb1(c1='xx',c2='oo') obj.save() 查: models.Tb1.objects.get(id=123) -----获取单条数据,不存在则报错(不建议使用) models.Tb1.objects.all() -----获取全部 models.Tb1.objects.filter(name='seven') -----获取指定的单条数据 删: models.Tb1.objects.filter(name='seven').delete() -----删除指定条件的数据 改: models.Tb1.objects.filter(name='seven').update(gender='0') -----指定条件的数据更新,均支持 **kwargs obj = models.Tb1.objects.get(id=1) obj.c1 = '111' obj.save() -----修改单条数据 基本方法 1.1丶增加数据 可以接受字典类型数据 **kwargs obj = models.UserType(caption='管理员') # 在表中插入数据 UserType为表名 obj.save() # 提交进去 models.UserType.objects.create(caption='普通用户') # 在表里插入数据(两种都是在表里插入数据) user_dict = {'caption': '超级管理员'} models.UserType.objects.create(**user_dict) 在UserInfo中插入数据 user_info_dict = {'user': 'alex', 'email': 'alex3712@qq.com', 'pwd': '123', 'user_type': models.UserType.objects.get(nid=1) # (获取的是一个对象)获取表UserType的nid=1的数据 } user_info_dict = {'user': 'even', 'email': 'even3712@qq.com', 'pwd': '123', 'user_type': models.UserType.objects.get(nid=1) # (获取的是一个对象)获取表UserType的nid=1的数据 } models.UserInfo.objects.create(**user_info_dict) # **表示插入所有 UserInfo 1.2丶查找数据 models.Tb1.objects.get(id=123) -----获取单条数据,不存在则报错 models.Tb1.objects.all() -----获取全部数据 models.Tb1.objects.filter(name='test') -----获取指定条件的数据 表单查询,结果为queryset类型 ret = models.UserType.objects.all() print(type(ret),ret,ret.query) #输出是<class 'django.db.models.query.QuerySet'> #<QuerySet [<UserType: UserType object>等,为queryset类型 for item in ret: print(item,item.nid,item.caption) #输出UserType objects 2 普通用户这类型数据 """ """ ret1 = models.UserType.objects.all().values('nid') print(type(ret1),ret1,ret1.query) # 输出<QuerySet [{'nid': 2}, {'nid': 1}, {'nid': 3}]> for item in ret1: print(item,type(item)) #输出的是{'nid':2}<class 'dict'>这类字典类型 ret = models.UserType.objects.all().values_list('nid') print(type(ret),ret) #输出结果<class 'django.db.models.query.QuerySet'> <QuerySet [(2,), (1,), (3,)]> 1.3修改数据 models.Tb1.objects.filter(name='test').update(age='30') #将指定条件的数据更新,均支持 **kwargs 或 obj = models.Tb1.objects.get(id=1) obj.c1 = '111' #修改单条数据 obj.save() 1.4删除数据 models.user.objects.filter(name='seven').delete() #删除指定条件的数据 1.5获取个数 models.author.onjects.filter(age='30').count() #author是作者表 1.6排列 models.author.objects.filter(age='30').order_by('id') #asc从小到大 models.author.objects.filter(age='30').order_by('-id') #desc从大到小 1.7大于,小于 models.Tb1.objects.filter(id__gt=1) #获取id大于1的值 models.Tb1.objects.filter(id__lt=10) #获取id小于10的值 models.Tb1.object.filter(id__lt=10,id__gt=1) #获取id大于1且小于10的值 1.8存在 models.Tb1.objects.filter(id__in=[11,22,33]) #获取id等于11,22,33的数据 models.Tb1.objects.exclude(id__in=[11,22,33]) #not in 1.9contains models.Tb1.objects.filter(name__contains='ven') models.Tb1.onjects.filter(name__icontains='ven') #icontains大小写不敏感 models.Tb1.objects.exclude(name__icontains='ven') 1.10其他 # range 随机的 # # models.Tb1.objects.filter(id__range=[1, 2]) # 范围bettwen and # 其他类似 # # startswith,istartswith, endswith, iendswith, # order by 排序 # # models.Tb1.objects.filter(name='seven').order_by('id') # asc # models.Tb1.objects.filter(name='seven').order_by('-id') # desc # limit 、offset 分页 # # models.Tb1.objects.all()[10:20] # group by 分组 from django.db.models import Count, Min, Max, Sum # models.Tb1.objects.filter(c1=1).values('id').annotate(c=Count('num')) #values这个映射后,就是根据id来分组 View Code # SELECT "app01_tb1"."id", COUNT("app01_tb1"."num") AS "c" FROM "app01_tb1" WHERE "app01_tb1"."c1" = 1 GROUP BY "app01_tb1"."id" View Code 2丶连表操作 2.1一对多 对象.query -- 查看代码的sql语句 (利用双下划线和__set 将表之间的操作连接起来) class UserInfo(models.Model): user = models.CharField(max_length=32) # 字符串(必须带字节长度参数) email = models.EmailField(max_length=32) pwd = models.CharField(max_length=64) user_type = models.ForeignKey("UserType") # (一对多)models.ForeignKey 连表关系 class UserType(models.Model): nid = models.AutoField(primary_key=True) # 自增列(主键) caption = models.CharField(max_length=16, unique=True) # unique=True 不允许重复 表结构 # 在UserType表插入数据 obj = models.UserType(caption='管理员') # 在表中插入数据 obj.save() # 提交进去 models.UserType.objects.create(caption='普通用户') # 在表里插入数据(两种都是在表里插入数据) user_dict = {'caption': '超级管理员'} models.UserType.objects.create(**user_dict) UserType # 在UserInfo中插入数据 user_info_dict = {'user': 'alex', 'email': 'alex3712@qq.com', 'pwd': '123', 'user_type': models.UserType.objects.get(nid=1) # (获取的是一个对象)获取表UserType的nid=1的数据 } user_info_dict = {'user': 'even', 'email': 'even3712@qq.com', 'pwd': '123', 'user_type': models.UserType.objects.get(nid=1) # (获取的是一个对象)获取表UserType的nid=1的数据 } models.UserInfo.objects.create(**user_info_dict) # **表示插入所有 UserInfo #不在filter()或values()中查询使用 ret = models.UserInfo.objects.all() for i in ret : print(type(i),i.user,i.user_type.caption) #得到的ret是一个queryset对象,只有我们循环我们得到每一行的一个对象的时候才可以用.字段名获取数据 # 想获取和其有联系表的数据的时候,i.user_type得到的是一个有联系表的对象,我们就可以获取数据了 1 2 3 4 5 6 7 #在filter()或values()中查询使用 ret1 = models.UserInfo.objects.filter(user_type__caption='管理员').all().values('user','user_type__caption') ret2 = models.UserInfo.objects.all().values('user','user_type__caption') print(type(ret1),ret1) print(type(ret2),ret2) #我们查的是userinfo表中的user,所以应该user中数据全部显示,而'user_type__caption'即另一张表中的数据根据user对应的值进行显示 第二部 一对多之正向查找通过UserInfo表查找UserType的内容,使用双下划线(__),了不起的双下划线. # 正向查找 ret = models.UserInfo.objects.all() for item in ret: print(item, item.id, item.user_type.nid, item.user_type.caption, item.user_type_id) # 取出的是对象;输出结果:UserInfo object 1 1 管理员 1 ret1 = models.UserInfo.objects.all().values('user', 'user_type__caption') # user_type__caption中用双下划线是可以连表操作 print(ret1) # 获得是拼接过得 # 拿用户类型是管理员的所有用户 models.UserInfo.objects.filter(user='alex') models.UserInfo.objects.filter(user_type__caption=1) ret = models.UserInfo.objects.filter(user_type__caption="管理员").values('user', 'user_type__caption') print(ret, type(ret)) 一对多之反向查找,通过UserType查找UserInfo的内容,使用__set # 反向查找 obj = models.UserType.objects.filter(caption='管理员').first() print(obj.nid) print(obj.caption) # (反向查找)表名_set.all()可以获取; 这种obj.user_type_set()报错,user_type_set:列名_set,不能获得数据 print(obj.userinfo_set.all()) # (反向查找)表名_set.all() 可以获取 obj = models.UserType.objects.get(nid=1) # userinfo__user 双下划线;userinfo表下的user列 ret = models.UserType.objects.all().values('nid', 'caption', 'userinfo__user') # userinfo__user的双下划线,可以关联userinfo表下的user列 print(ret) # 输出结果:[{'userinfo__user': None, 'nid': 2, 'caption': '普通用户'}, ...] 2.2一对一 user_info_obj = models.UserInfo.objects.filter(id=1).first() print user_info_obj.user_type print user_info_obj.get_user_type_display() print user_info_obj.userprofile.password user_info_obj = models.UserInfo.objects.filter(id=1).values('email', 'userprofile__username').first() print user_info_obj.keys() print user_info_obj.values() 2.3多对多 表结构的创建方法: 方法一:传统的多对多(自定义第三张表) class HostToGroup(models.Model): hgid = models.AutoField(primary_key=True) host_id = models.ForeignKey('Host') group_id = models.ForeignKey('Group') # ForeignKey会创建第三列放入表中 class Host(models.Model): hid = models.AutoField(primary_key=True) hostname = models.CharField(max_length=32) ip = models.CharField(max_length=32) class Group(models.Model): gid = models.AutoField(primary_key=True) name = models.CharField(max_length=16) 传统的多对多 方法二:Django的多对多(自动生成第三张表) class Host(models.Model): hid = models.AutoField(primary_key=True) hostname = models.CharField(max_length=32) ip = models.CharField(max_length=32) # h2g = models.ManyToManyField('Group') # 与下面建立多对多关系是一样的,差别就是放在下面关联表是上面这个Host表 class Group(models.Model): gid = models.AutoField(primary_key=True) name = models.CharField(max_length=16) h2g = models.ManyToManyField('Host') # 建立多对多关系 Django多对多 方法三:自定义第三张表+ManyToManyField+through字段 示列: h2g = models.ManyToManyField('Host', through='HostToGroup') h2g = models.ManyToManyField('Host', through='HostToGroup') 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class HostToGroup(models.Model): hgid = models.AutoField(primary_key=True) host_id = models.ForeignKey('Host') group_id = models.ForeignKey('Group') status = models.IntegerField() class Host(models.Model): hid = models.AutoField(primary_key=True) hostname = models.CharField(max_length=32) ip = models.CharField(max_length=32) # h2g = models.ManyToManyField('Group') # group_set class Group(models.Model): gid = models.AutoField(primary_key=True) name = models.CharField(max_length=16) h2g = models.ManyToManyField('Host', through='HostToGroup') 自定义第三张表 以上三种都可以创建多对多表. 插入数据 models.Host.objects.create(hostname='c1', ip='1.1.1.1') models.Host.objects.create(hostname='c2', ip='1.1.1.2') models.Host.objects.create(hostname='c3', ip='1.1.1.3') models.Host.objects.create(hostname='c4', ip='1.1.1.4') models.Host.objects.create(hostname='c5', ip='1.1.1.5') Host models.Group.objects.create(name='财务部') models.Group.objects.create(name='人事部') models.Group.objects.create(name='公关部') models.Group.objects.create(name='技术部') models.Group.objects.create(name='运营部') models.Group.objects.create(name='销售部') models.Group.objects.create(name='客服部') Group 操作表 添加(正,反) # 将多台机器分配给一个组 # 1、一个一个添加 # obj = models.Group.objects.get(gid=1) # h1 = models.Host.objects.get(hid=2) # obj .h2g.add(h1) # 一个一个添加 # 2、"*"批量添加 # obj = models.Group.objects.get(gid=1) # q = models.Host.objects.filter(hid__gt=3) # (正向操作)过滤出(__gt=3表示大于3)hid大于3的 # obj.h2g.add(*q) # "*"批量添加 # 将一台机器分给多个组 # 1、一个个添加 # h = models.Host.objects.get(hid=1) # obj = models.Group.objects.get(gid=1) # obj.h2g.add(h) # obj = models.Group.objects.get(gid=2) # 一个个添加 # obj.h2g.add(h) # 2、批量添加 # h = models.Host.objects.get(hid=1) # h.group_set.add(*models.Group.objects.filter(gid__gt =3) # (反向操作)批量添加 添加正,反 删除 # 1、remove;删除的是关系表 # h = models.Host.objects.get(hid=1) # h.group_set.remove(*models.Group.objects.filter(gid__gt=5)) # 反向 # 2、delete;关系表与基础表数据都删除(慎用) # h = models.Host.objects.get(hid=3) # h.group_set.all().delete() 删除 设置 # 1、set ,如果表里没有就添加,如果有就保留 h = models.Host.objects.get(hid=3) h.group_set.set(models.Group.objects.filter(gid__gt=4)) # 2、参数clear=True表示先进行清空,再添加 h.group_set.set(models.Group.objects.filter(gid__gt=3), clear=True) 设置 增加 # 1、create 增加一条数据,可以接受字典类型数据 # 2、get_or_create 如果表里面存在不变,关系表里面没有,那样在基础表与关系表都创建 r = h.group_set.get_or_create(name='公关部') print(r) # 3、update_or_create 如果关系表里没有,关系表和基础表都添加,如果存在不变(和上面一样) r = h.group_set.get_or_create(name='销售部') print(r) 增加 查看 relation_list = models.HostRelation.objects.all() 或 relation_list = models.HostRelation.objects.filter(c2__username='wang') for item in relation_list: print item.c1.hostname print item.c2.username 查看 Q,F 其中F表示可以让某一列的数据在当前的状态下自增多少,而我们平时用的updata只能把某一列数据都改变成同一个值其中Q表示搜索条件可以有or和and # from django.db.models import F # models.Tb1.objects.update(num=F('num')+1) F,使用条件查询的值 from django.db.models import Q # con = Q() # # q1 = Q() # q1.connector = 'OR' # q1.children.append(('id', 1)) # q1.children.append(('id', 10)) # q1.children.append(('id', 9)) # # q2 = Q() # q2.connector = 'OR' # q2.children.append(('c1', 1)) # q2.children.append(('c1', 10)) # q2.children.append(('c1', 9)) # # con.add(q1, 'AND') # con.add(q2, 'AND') # # models.Tb1.objects.filter(con) # # from django.db import connection # cursor = connection.cursor() # cursor.execute("""SELECT * from tb where name = %s""", ['Lennon']) # row = cursor.fetchone() Q,构建搜索条件 示列: 用Q 的条件搜索,查询图书的相关信息 from django.conf.urls import url from django.contrib import admin from app1 import views urlpatterns = [ url(r'^admin/', admin.site.urls), url(r'^test/', views.test), url(r'^index/', views.index), ] urls <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .left{ float: left; } .clearfix:after{ // 清除漂浮 content: '.'; clear: both; display: block; visibility: hidden; height: 0; } </style> </head> <body> <div class="condition"> <div class="item clearfix"> <div class="icon left" onclick="AddCondition(this);">+</div> <div class="left"> <select onchange="ChangeName(this);"> <option value="name">书名</option> <option value="book_type__caption">图书类型</option> <option value="price">价格</option> <option value="pages">页数</option> </select> </div> <div class="left"><input type="text" name="name" /></div> </div> </div> <div> <input type="button" onclick="Search();" value="搜索" /> </div> <div class="container"> </div> <script src="/static/jquery-1.12.4.js"></script> <script> function AddCondition(ths) { var new_tag = $(ths).parent().clone(); //复制父标签 new_tag.find('.icon').text('-'); // 在子孙中找,把内容改为“-” new_tag.find('.icon').attr('onclick', 'RemoveCondition(this);'); // (重新写个事件)把之前绑定的增添事件更新成删除 $(ths).parent().parent().append(new_tag); //添加 } function RemoveCondition(ths) { // 删除事件 $(ths).parent().remove(); } function ChangeName(ths) { //修改内容触发这个事件 var v = $(ths).val(); //获得当前选中标签的属性 $(ths).parent().next().find('input').attr('name',v); //select标签,父亲的下一个标签的input找出来,把属性改为“v” } function Search() { //搜索事件 var post_data_dict = {}; //获得的值放在这个字典 $('.condition input').each(function () { // 获取所有input的内容,循环一个个获取;提交数据 // console.log($(this)[0]) // ($(this)[0],是把Jquery对象转变成DOM对象 var n = $(this).attr('name'); //这里的this是jQuery对象;获取name属性 var v = $(this).val(); //获取对象的值 var v_list = v.split(','); // 利用分割,得到输入的多个内容 post_data_dict[n] = v_list; //把这些输入值放到字典 }); console.log(post_data_dict); //打印出 var post_data_str = JSON.stringify(post_data_dict); // 把post_data_dict这个字典转换成字符串 $.ajax({ url: '/index/', //这里index后面必须加 "/" type: 'POST', data: { 'post_data': post_data_str}, // 要传输默认为字符串, dataType: 'json', //转换类型 success: function (arg) { // 字符串 "<table>" + if(arg.status){ var table = document.createElement('table'); // 成功的话把内容添加到table table.setAttribute('border', 1); // [{,name,pubdate,price,caption},] $.each(arg.data, function(k,v){ //循环得到返回的内容 var tr = document.createElement('tr'); //创建标签 var td1 = document.createElement('td'); //创建标签 td1.innerText = v['name']; //标签内容 var td2 = document.createElement('td'); td2.innerText = v['price']; var td3 = document.createElement('td'); td3.innerText = v['book_type__caption']; var td4 = document.createElement('td'); td4.innerText = v['pubdate']; tr.appendChild(td1); //标签添加内容 tr.appendChild(td2); tr.appendChild(td3); tr.appendChild(td4); table.appendChild(tr); // 以上都是Dom创建标签和添加标签内容 }); $('.container').empty(); //加之前进行清空 $('.container').append(table); //找到container把table添加进去 }else{ alert(arg.message); } } }) } </script> </body> </html> index.html from django.db import models # Create your models here. class Author(models.Model): """ 作者 """ name = models.CharField(max_length=100) age = models.IntegerField() class BookType(models.Model): """ 图书类型 """ caption = models.CharField(max_length=64) class Book(models.Model): """ 图书 """ name = models.CharField(max_length=64) pages = models.IntegerField() price = models.DecimalField(max_digits=10, decimal_places=2) pubdate = models.DateField() # authors = models.ManyToManyField(Author) book_type = models.ForeignKey(BookType) def __str__(self): # 获取内容方便查看 return 'obj:%s-%s' % (self.name, self.price) models.py from django.shortcuts import render, HttpResponse from app1 import models # Create your views here. import json from datetime import date from datetime import datetime from decimal import Decimal def test(request): # 插入作者 """ models.Author.objects.create(name='alex', age=30) models.Author.objects.create(name='eric', age=40) models.Author.objects.create(name='svion', age=20) models.Author.objects.create(name='riok', age=60) models.Author.objects.create(name='vion', age=50) models.Author.objects.create(name='sion', age=40) models.Author.objects.create(name='sdion', age=20) models.Author.objects.create(name='svnn', age=80) models.Author.objects.create(name='aion', age=60) models.Author.objects.create(name='xzon', age=70) """ # 插入图书类型 """ models.BookType.objects.create(caption='历史') models.BookType.objects.create(caption='政治') models.BookType.objects.create(caption='文学') models.BookType.objects.create(caption='计算机') models.BookType.objects.create(caption='小说') models.BookType.objects.create(caption='故事') models.BookType.objects.create(caption='语文') models.BookType.objects.create(caption='数学') models.BookType.objects.create(caption='科技') models.BookType.objects.create(caption='化学') """ # 插入图书 """ models.Book.objects.create(name='文艺复兴', pages='100', price='40', pubdate='1992-11-2', book_type_id='1') models.Book.objects.create(name='解密', pages='80', price='10', pubdate='2016-6-10', book_type_id='5') models.Book.objects.create(name='刀锋', pages='50', price='3', pubdate='2014-02-16', book_type_id='5') models.Book.objects.create(name='路84号', pages='260', price='40', pubdate='1999-10-12', book_type_id='3') models.Book.objects.create(name='红楼', pages='1000', price='500', pubdate='1760-1-1', book_type_id='3') models.Book.objects.create(name='将夜', pages='2000', price='300', pubdate='2010-3-3', book_type_id='5') models.Book.objects.create(name='跑路', pages='20', price='10', pubdate='1998-9-2', book_type_id='4') models.Book.objects.create(name='马克思主义', pages='50', price='100', pubdate='1937-3-3', book_type_id='2') """ # 查询 # # ret1 = models.Book.objects.filter(book_type__caption='文学').values('name', 'pages', 'price', 'pubdate') # # print(ret1) # ret2 = models.Book.objects.filter(authors__name='alex').values('pages', 'price', 'pubdate') # print(ret2) # obj2 = models.BookType.objects.filter(book_authors__name='alex').first() # ret3 = obj2.book_set.values_list('authors__book__name', 'authors__book__price', 'authors__book__pubdate') # print(ret3) return HttpResponse("欢迎进入图书馆") class JsonCustomEncoder(json.JSONEncoder): # 固定的格式模块 def default(self, field): if isinstance(field, datetime): return field.strftime('%Y-%m-%d %H:%M:%S') elif isinstance(field, date): return field.strftime('%Y-%m-%d') elif isinstance(field, Decimal): return str(field) else: return json.JSONEncoder.default(self, field) def index(request): if request.method == 'POST': ret = {'status': False, 'message': '', 'data': None} try: post_data = request.POST.get('post_data', None) post_data_dict = json.loads(post_data) # 反序列化 print(post_data_dict) # {'name': ['11', 'sdf'],'price': ['11', 'sdf']} # 构造搜索条件(是或的) 搜索内容 返回内容 from django.db.models import Q con = Q() # 最外层 for k, v in post_data_dict.items(): q = Q() q.connector = 'OR' # 或的关系 for item in v: # 循环所有的列表如“['11', 'sdf']” q.children.append((k, item)) # item是每一个搜索条件(循环的值),在添加到 con.add(q, 'AND') """ ret = models.Book.objects.filter(con) print(ret) # queryset,[对象] # 使用serializers方法序列化 from django.core import serializers data = serializers.serialize("json", ret) # 字符串 print(type(data),data) """ """ # 序列化 # values 内部元素变成字典 # values_list 内部元素变为元祖 #ret = models.Book.objects.filter(con).values('name','book_type__caption') # 这里ret外边是queryset类型;里边的列表类型;遇到values就会变成字典类型 ret = models.Book.objects.filter(con).values_list('name', 'book_type__caption') print(ret,type(ret)) li = list(ret) data = json.dumps(li) # 获得后直接序列化 print(data,type(data)) """ result = models.Book.objects.filter(con).values('name', 'price', 'pubdate', 'book_type__caption') # ret = models.Book.objects.filter(con).values_list('name', 'book_type__caption') # ret是queryset类型 li = list(result) ret['status'] = True ret['data'] = li except Exception as e: # 错误信息 ret['message'] = str(e) # 错误了就把错误信息放进去 ret_str = json.dumps(ret, cls=JsonCustomEncoder) # cls=JsonCustomEncoder循环每个字段 return HttpResponse(ret_str) # 这里只能返回字符串;把信息返回到前端 return render(request, 'index.html') views.py Dom对象与JQuesry对象的转换 index.html的关于Dom与JQuesry的知识补充 Dom对象与JQuery对象的相互转换: document.getElementsTagName('div)[0] jQuery对象 $('div').first() Dom对象转换成JQuery对象: $(document.getElementsTagName('div)[0]) # 直接在Dom对象前加'$' JQuery对象转换成Dom对象: $('div').first()[0] # 直在jQuery对象后加索引'[0]'
django amdin是django提供的一个后台管理页面,改管理页面提供完善的html和css,使得你在通过Model创建完数据库表之后, 就可以对数据进行增删改查,而使用django admin 则需要以下步骤: 1、创建后台管理员 2、配置url 3、注册和配置django admin后台管理页面 壹丶创建后台管理员 python manage.py createsuperuser 贰丶配置后台管理url url(r'^admin/', include(admin.site.urls)), 叁丶注册和配置Django admin 后台管理页面 1· 在admin中执行如下配置 from django.contrib import admin from app01 import models admin.site.register(models.UserType) admin.site.register(models.UserInfo) admin.site.register(models.UserGroup) admin.site.register(models.Asset) 2·设置数据表名称 class UserType(models.Model): name = models.CharField(max_length=50) class Meta: verbose_name = '用户类型' verbose_name_plural = '用户类型' 3·打开表之后,设定默认显示,需要早model中作如下配置 class UserType(models.Model): name = models.CharField(max_length=50) def __unicode__(self): return self.name from django.contrib import admin from app01 import models class UserInfoAdmin(admin.ModelAdmin): list_display = ('username', 'password', 'email') admin.site.register(models.UserType) admin.site.register(models.UserInfo,UserInfoAdmin) admin.site.register(models.UserGroup) admin.site.register(models.Asset) 4·为数据表添加搜索功能 from django.contrib import admin from app01 import models class UserInfoAdmin(admin.ModelAdmin): list_display = ('username', 'password', 'email') search_fields = ('username', 'email') admin.site.register(models.UserType) admin.site.register(models.UserInfo,UserInfoAdmin) admin.site.register(models.UserGroup) admin.site.register(models.Asset) 5·添加快速过滤 from django.contrib import admin from app01 import models class UserInfoAdmin(admin.ModelAdmin): list_display = ('username', 'password', 'email') search_fields = ('username', 'email') list_filter = ('username', 'email') admin.site.register(models.UserType) admin.site.register(models.UserInfo,UserInfoAdmin) admin.site.register(models.UserGroup) admin.site.register(models.Asset) 更多详见:http://www.cnblogs.com/wupeiqi/articles/5246483.html http://www.cnblogs.com/wupeiqi/articles/5237704.html
一丶什么是CSRF? CSRF是Cross Site Request Forgery的缩写,翻译过来就是跨站请求伪造。那么什么是跨站请求伪造呢?让我一个词一个词的解释: 1、跨站:顾名思义,就是从一个网站到另一个网站。 2、请求:即HTTP请求。 3、伪造:在这里可以理解为仿造、伪装。 综合起来的意思就是:从一个网站A中发起一个到网站B的请求,而这个请求是经过了伪装的,伪装操作达到的目的就是让请求看起来像是从网站B中发起的,也就是说,让B网站所在的服务器端误以为该请求是从自己网站发起的,而不是从A网站发起的。当然,请求一般都是恶意的。 二丶简介 django为用户实现防止跨站请求伪造的功能,通过中间件django.middleware.csrf.CsrfViewMiddleware 来完成。 对于django中设置防跨站请求伪造功能分为全局和局部。 全局: 中间件 django.middleware.csrf.CsrfViewMiddleware 局部: @csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。 @csrf_protect,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。 默认(全局):'django.middleware.csrf.CsrfViewMiddleware' 中间间,过滤所有post的请求。是为全局的,需要遵循下面 在html中加上{% csrf_token %} views:的返回用render方法 去掉(全局):'django.middleware.csrf.CsrfViewMiddleware'就不需要遵循csrf 设置(局部)也可以通过装饰器来设定局部的CSRF。(指定某些遵循csrf) @csrf_protect 在html中加上{% csrf_token %} views:的返回用render 使用装饰器也可以(局部)不遵循CSRF(指定某些不遵循csrf) @csrf_exempt 总结 三丶应用 1丶普通表单 1 veiw中设置返回值: 2 return render_to_response('Account/Login.html',data,context_instance=RequestContext(request)) <br> # render_to_response需要context_instance=RequestContext(request)这个参数,因为render_to_response不生成随机字符串。 3 或者 return render(request, 'xxx.html', data) html中设置Token: {% csrf_token %} 2丶Ajax 对于传统的form,可以通过表单的方式将token再次发送到服务端,而对于ajax的话,使用如下方式。 from django.template.context import RequestContext # Create your views here. def test(request): if request.method == 'POST': print request.POST return HttpResponse('ok') return render_to_response('app01/test.html',context_instance=RequestContext(request)) view.py <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> {% csrf_token %} <input type="button" onclick="Do();" value="Do it"/> <script src="/static/plugin/jquery/jquery-1.8.0.js"></script> <script src="/static/plugin/jquery/jquery.cookie.js"></script> <script type="text/javascript"> var csrftoken = $.cookie('csrftoken'); // 获取 function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ // 是一个全局的配置,在所有的ajax发来之前执行 beforeSend: function(xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); // 在发ajax之前设置一个请求头,名字是X-CSRFToken, // 在ajax发送之前把请求头放到csrftoken,在一块发过去,对的就执行 } } }); // 上面是获取token,在以后ajax操作前,写上面这个配置。 function Do(){ $.ajax({ url:"/app01/test/", data:{id:1}, type:'POST', success:function(data){ console.log(data); } }); } </script> </body> </html> text.html 更多:https://docs.djangoproject.com/en/dev/ref/csrf/#ajax
Cookie 在浏览器端(客户端)保存的键值对,特性:每次http请求都会携带. 举个例子:{"name":身份证号} 1丶获取cookie request.COOKIE['key'] request.get_signed_cookie(key,default=RAISE_ERROR,salt='',max_age=None) 参数: default:默认值 salt:加密盐 max_age:后台控制过期时间 2丶设置Cookie def cook2(request): prnt(request.COOKIES) #print(request.get_signed_cookie('k2',None,salt='uuu')) #rep = HttpResponse('ok') #rep.set_cookie('k1',123) #rep.set_signed_cookie('k2',666,salt='uuu') rep = HttpResponse('ok') return rep 3丶Cookie的参数 rep.set_cookie(key,value,...) rep.set_signed_cookie(key,value,salt='加密盐',...) 参数: key, 键 value='', 值 max_age=None, 超时时间, 单位是秒 expires=None, 超时时间(IE requires expires,so set it if hasn't been already.)支持datetime,时间戳time.time这两种 path='/', Cookie生效的路径,/ 表示跟路径,特殊的:根路径的cookie可以被任何url的页面访问 domain=None, Cookie生效的域名 secure=False, https传输 httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对的,底层抓包可以获取到也可以被覆盖) 例子: def cook1(request): #print(request.COOKIES) #获取所有的Cookie #print(request.get_signed_cookie('k2',None,salt='uuu')) #rep = HttpResponse('ok') #rep.set_cookie('k1',123) #设置Cookie #rep.set_signed_cookie('k2',666,salt='uuu') #签名的cookie,salt为加密盐 rep = HttpResponse('cook1') rep.set_cookie('k999',123,path='/cookie1/') #path是cookie生效的路径(局部的);/表示根路径,特殊的;根路径的cookie可以被任何url的页面访问 rep.set_cookie('k888',123) #全局的cookie return rep 由于cookie保存在客户端的电脑上,所以,JavaScript和Jquery也可以操作cookie. <script src='/static/js/jquery.cookie.js'></script> $.cookie('list_pager_num',30,{path:'/'});
Django -- Seeion介绍 问: Django的session是什么? 答: Django 完全支持匿名 Session的。 Session 框架允许每一个用户保存并取回数据。它将数据保存在服务器端,并将发送和接收, Cookie的操作包装起来。在 Cookie 中包含的是 Session ID,而不是数据本身。 好了回到正题,那么我们来简单的使用一下Session把. 壹:Seeion的简单使用 def index(request): # 获取、设置、删除Session中数据 request.session['v1'] request.session.get('v1',None) request.session['v1'] = 123 request.session.setdefault('v1',123) # 存在则不设置 del request.session['v1'] # 所有 键、值、键值对 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 用户session的随机字符串 request.session.session_key # 将所有Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否 request.session.exists("session_key") # 删除当前用户的所有Session数据 request.session.delete("session_key") 贰:Session的种类 Django中默认支持Session,其内部提供了5种类型的Session供开发者使用,使用以下的类型只需要在引擎修改下配置换成相应的类型就可以了。 ①数据库(默认) ②缓存 ③文件 ④缓存+数据库 ⑤加密cookie ①数据库Session Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认) 使用 def index(request): # 获取、设置、删除Session中数据 request.session['k1'] # 获取 request.session.get('k1',None) request.session['k1'] = 123 # 设置 request.session.setdefault('k1',123) # 设置,存在则不设置 del request.session['k1'] # 获取所有 键、值、键值对 request.session.keys() request.session.values() request.session.items() request.session.iterkeys() request.session.itervalues() request.session.iteritems() # 用户session的随机字符串(存在客户端浏览器中,也存在服务端的数据库中) request.session.session_key # 将所有Session失效日期小于当前日期的数据删除 request.session.clear_expired() # 检查 用户session的随机字符串 在数据库中是否 request.session.exists("session_key") # 删除当前用户的所有Session数据 request.session.delete("session_key") 使用 def session(request): # request.session request.session['k1'] = 123 # 设置session # request.session['k1'] print(request.session.session_key) # 获得用户session的随机字符串(存在客户端浏览器中,也存在服务端的数据库中) return HttpResponse('session') def index(request): # 获得session return HttpResponse(request.session['k1']) # 这里可以直接读取到session 简单列子 ②缓存Session SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎 SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 SESSION_COOKIE_SECURE = False # 是否Https传输cookie SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期 SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存 配置 settings.py 使用方法和以上列子是一样的,只需要简单的修改下配置就可以. ③文件Session 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎 SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir() #如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串 SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径 SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名 SESSION_COOKIE_SECURE = False # 是否Https传输cookie SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输 SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期 SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存 配置 settings.py 使用方法同上 (↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑) ④缓存+数据库Session 数据库用于做持久化,缓存用于提高效率 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎 配置 ⑤加密Cookie,Session 配置 settings.py SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎 配置 ⑥登录认证小列子 <form class="common_form" id="Form" method="post" action="/app01/login/"> <div><h1 class="login_title">登录</h1></div> <div style="width: 600px"> <div class="form_group"><input name="username" class="form-control" label='用户名' type="text" placeholder="用户名" require='true'></div> </div> <div style="width: 600px"> <div class="form_group"><input name="password" class="form-control" label='密码' type="password" placeholder="密码" require='true'></div> </div> <div class="form_group"><input class="btn btn-info form_btn" type="submit" value="登录"></div> </form> HTML def login(request): if request.method == "POST": username = request.POST.get("username") password = request.POST.get("password") if username == "zhangsan" and password == "123456": request.session["IS_LOGIN"] = True #创建session return redirect("/app01/home/") return render(request,"app01/login.html") def home(request): islogin = request.session.get("IS_LOGIN",False) if islogin:#如果用户已登录 return render(request,"app01/menus.html") else: return redirect("/app01/login/") def logout(request):#退出 try: del request.session['IS_LOGIN'] except KeyError: pass return redirect("/app01/login/") views
Django · Django流程 · Django url · Django view · Django form ①:Django流程介绍 MTV模式 注明的MVC模式:所谓MVC就是把web应用分为模型(M),控制器(C),视图(V)三层;他们之间以一种插件似的,松耦合的方式连接在一起. 模型负责业务对象与数据库的对象(ORM),视图负责与用户的交互(页面),控制器(C)接受用户的输入调用模型和视图完成用户的请求. 注: 什么是松耦合:简单的说,松耦合是一个 重要的保证互换性的软件开发方法. Django的MTV模式本质上与MVC模式没有什么差别,也是各组件之间为了保持松耦合关系,只是定义上有些许不同,Django的MTV分别代表: Model(模型):负责业务对象与数据库的对象(ORM) Template(模版):负责如何把页面展示给用户 View(视图):负责业务逻辑,并在适当的时候调用Model和Template 此外,Django还有一个url分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template ②:Django URL URL配置(URLconf)就像Django 所支撑网站的目录。它的本质是URL模式以及要为该URL模式调用的视图函数之间的映射表;你就是以这种方式告诉Django,对于这个URL调用这段代码,对于那个URL调用那段代码。URL的家在是从配置文件中开始。 参数说明: · 一个正则表达式字符串 · 一个可调用对象,通常为一个视图函数或一个指定视图函数路径的字符串 · 可选的要传递给视图函数的默认参数(字典形式) · 一个可选的name参数 下面是一个示例URLconf: from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ] 注释: · To capture a value from the URL, just put parenthesis around it. (从URL中捕获值,只是把它周围的括号。) There’s no need to add a leading slash, because every URL has that. For example, it’s ^articles, not ^/articles. (没有必要添加一个领先的削减,因为每个URL。例如,它的^的文章,而不是^ /文章。) · The 'r' in front of each regular expression string is optional but recommended. It tells Python that a string is “raw” – that nothing in the string should be escaped. See Dive Into Python’s explanation. (每个正则表达式字符串前面的'R'是可选的,但建议。它告诉Python字符串是“原始” - 没有什么字符串中应该进行转义。见深入Python的解释。) Example requests: · A request to /articles/2005/03/ would match the third entry in the list. Django would call the functionviews.month_archive(request, '2005', '03'). (请求/文章/ 2005/03 /匹配列表中的第三项,Django的将调用函数views.monthly存档(要求下,'2005','03')。) · /articles/2005/3/ would not match any URL patterns, because the third entry in the list requires two digits for the month. (/文章/ 2005/3 /不匹配任何URL模式,因为第三个条目列表中需要两个数字的月. .) · /articles/2003/ would match the first pattern in the list, not the second one, because the patterns are tested in order, and the first one is the first test to pass. Feel free to exploit the ordering to insert special cases like this. Here, Django would call the function views.special_case_2003(request) (/文章/ 2003 /将匹配第一个模式列表中,没有第二个,因为模式是为了进行测试.第一个是第一个测试通过,随时利用顺序插入这样的特殊情况,这里,Django所说的功能的观点。特殊情况2003(请求)) · /articles/2003 would not match any of these patterns, because each pattern requires that the URL end with a slash. (/文章/ 2003不匹配任何这些模式,因为每个模式要求以斜线结尾的URL。) · /articles/2003/03/03/ would match the final pattern. Django would call the functionviews.article_detail(request, '2003', '03', '03'). (/文章/ 2003/03/03 /将最终的模式相匹配,Django将调用函数views.article细节(的要求,'2003','03','03')。) Named groups · The above example used simple, non-named regular-expression groups (via parenthesis) to capture bits of the URL and pass them as positional arguments to a view. In more advanced usage, it’s possible to use named regular-expression groups to capture URL bits and pass them as keyword arguments to a view. (上面的例子中使用简单,non-named正则表达式组(通过括号)捕捉到的URL,将他们作为一个视图的位置参数。在更高级的用法,可以使用指定的正则表达式组捕获的URL) · In Python regular expressions, the syntax for named regular-expression groups is (?P<name>pattern), where name is the name of the group and pattern is some pattern to match. (在Python正则表达式,命名正则表达式组的语法是(?P <名>的模式),其中name是组的名称和模式是某种模式相匹配。) · Here’s the above example URLconf, rewritten to use named groups: (下面是上面的例子中的URLconf,改写使用命名组:) import re ret=re.search('(?P<id>\d{3})/(?P<name>\w{3})','weeew34ttt123/ooo') print(ret.group()) print(ret.group('id')) print(ret.group('name')) 正则知识 from django.conf.urls import url from . import views urlpatterns = [ url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive), url(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<day>[0-9]{2})/$', views.article_detail), ] This accomplishes exactly the same thing as the previous example, with one subtle difference: The captured values are passed to view functions as keyword arguments rather than positional arguments. For example: (这完成了前面的例子一样,有一个微妙的差异:捕获的值传递给视图函数作为关键字参数而不是位置参数。例如:) A request to /articles/2005/03/ would call the function views.month_archive(request, year='2005',month='03'), instead of views.month_archive(request, '2005', '03'). (的请求/用品/ 2005/03/会调用函数views.monthly存档(要求,今年='2005',一个月='03'),而不是views.monthly存档(要求下,'2005','03')。) A request to /articles/2003/03/03/ would call the function views.article_detail(request, year='2003',month='03', day='03'). (请求/文章/ 2003/03/03 /将调用该函数的观点。文章细节(请求,年= ' 2003 ',月=“03”,天=“03”)。) In practice, this means your URLconfs are slightly more explicit and less prone to argument-order bugs – and you can reorder the arguments in your views’ function definitions. Of course, these benefits come at the cost of brevity; some developers find the named-group syntax ugly and too verbose. (在实践中,这意味着你的URLconf稍微更明确,不容易参数顺序错误 - 你可以在你的意见'函数定义重新排序的参数。当然,这些优点来在简短的费用;一些开发商找到命名组的语法丑陋,太冗长。) 常见写法实列: Captured arguments are always strings: Each captured argument is sent to the view as a plain Python string, regardless of what sort of match the regular expression makes. For example, in this URLconf line: (每个捕获的参数发送到视图作为普通的Python字符串,无论什么样的匹配正则表达式做。例如,在该URL配置行:) url(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive), ...the year argument passed to views.year_archive() will be a string, (…参数传递给视图。年存档()将是一个字符串,) not an integer, even though the [0-9]{4} will only match integer strings. (不是整数,即使[0-9]{4}将只匹配整数串。) Including other URLconfs : At any point, your urlpatterns can “include” other URLconf modules. This essentially “roots” a set of URLs below other ones. (在任何时候,您的网址模式可以“包含”其他的URLconf模块。这实质上是“根”的一套低于其他的网址。) For example, here’s an excerpt of the URLconf for the Django website itself. It includes a number of other URLconfs: (例如,这里的URL配置为Django的网站本身的摘录。它包括许多其他URL配置的:) from django.conf.urls import include, url urlpatterns = [ # ... snip ... url(r'^community/', include('django_website.aggregator.urls')), url(r'^contact/', include('django_website.contact.urls')), # ... snip ... ] Passing extra options to view functions: URLconfs have a hook that lets you pass extra arguments to your view functions, as a Python dictionary. (URLconf中有一个挂钩,可以传递额外的参数给您的视图功能,作为一个Python字典。) The django.conf.urls.url() function can take an optional third argument which should be a dictionary of extra keyword arguments to pass to the view function. (该django.conf.urls.url()函数可以接受这应该是额外的参数的字典传递给视图功能可选的第三个参数。) For example: from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}), ] In this example, for a request to /blog/2005/, Django will call views.year_archive(request, year='2005',foo='bar'). (在本例中,请求/博客/ 2005 / Django将调用视图。年存档(请求,年= ' 2005 ',foo = '参数')。) This technique is used in the syndication framework to pass metadata and options to views. (这种技术用于聚合框架通过元数据和视图选项。) Dealing with conflicts ( 应对冲突) It’s possible to have a URL pattern which captures named keyword arguments, and also passes arguments with the same names in its dictionary of extra arguments. When this happens, the arguments in the dictionary will be used instead of the arguments captured in the URL. (可以有一个URL模式捕获关键字参数,并通过参数具有相同名字的字典的额外参数。当这种情况发生时,将使用参数在字典里而不是参数捕获) 需要注意的是,当你加上参数时,对应函数views.index必须加上一个参数,参数名也必须命名为a,如下: if auth(): obj=model.user.filter() {'obj':obj} 应用 name param urlpatterns = [ url(r'^index',views.index,name='bieming'), url(r'^admin/', admin.site.urls), # url(r'^articles/2003/$', views.special_case_2003), url(r'^articles/([0-9]{4})/$', views.year_archive), # url(r'^articles/([0-9]{4})/([0-9]{2})/$', views.month_archive), # url(r'^articles/([0-9]{4})/([0-9]{2})/([0-9]+)/$', views.article_detail), ] ################### def index(req): if req.method=='POST': username=req.POST.get('username') password=req.POST.get('password') if username=='alex' and password=='123': return HttpResponse("登陆成功") return render(req,'index.html') ##################### <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {# <form action="/index/" method="post">#} <form action="{% url 'bieming' %}" method="post"> 用户名:<input type="text" name="username"> 密码:<input type="password" name="password"> <input type="submit" value="submit"> </form> </body> </html> ####################### name的应用 Django views http请求中产生两个核心对象: http请求:HttpRequest对象 http响应:HttpResponse对象 # 获取提交方式 request.method if request.method == "POST": times = time.time() return render(request,'index.html') # 获取前端post提交的数据 request.POST.get('username') # 获取域名后路径 get_full_path() 例:http://127.0.0.1:8000/index33/?name=123 ,req.get_full_path()得到的结果就是/index33/?name=123 HttpRequest对象 def test(request): # 往前端写入字符串 return HttpResponse("xxx") # 跳转路径 return redirect('/index/') # 渲染HTML文件两种方式 return render(reuqest, "test.html") return render_to_response('text.html') # 可以直接将函数中所有的变量传给模板 return render(reuqest, "test.html",locals()) # 可以根据通过字典的方式往前端传值,取值输入key即可 return render(reuqest, "test.html",{'shijie':'你好'}) HttpResponse对象 # path: 请求页面的全路径,不包括域名 # # method: 请求中使用的HTTP方法的字符串表示。全大写表示。例如 # # if req.method=="GET": # # do_something() # # elseif req.method=="POST": # # do_something_else() # # GET: 包含所有HTTP GET参数的类字典对象 # # POST: 包含所有HTTP POST参数的类字典对象 # # 服务器收到空的POST请求的情况也是可能发生的,也就是说,表单form通过 # HTTP POST方法提交请求,但是表单中可能没有数据,因此不能使用 # if req.POST来判断是否使用了HTTP POST 方法;应该使用 if req.method=="POST" # # # # COOKIES: 包含所有cookies的标准Python字典对象;keys和values都是字符串。 # # FILES: 包含所有上传文件的类字典对象;FILES中的每一个Key都是<input type="file" name="" />标签中 name属性的值,FILES中的每一个value同时也是一个标准的python字典对象,包含下面三个Keys: # # filename: 上传文件名,用字符串表示 # content_type: 上传文件的Content Type # content: 上传文件的原始内容 # # # user: 是一个django.contrib.auth.models.User对象,代表当前登陆的用户。如果访问用户当前 # 没有登陆,user将被初始化为django.contrib.auth.models.AnonymousUser的实例。你 # 可以通过user的is_authenticated()方法来辨别用户是否登陆: # if req.user.is_authenticated();只有激活Django中的AuthenticationMiddleware # 时该属性才可用 # # session: 唯一可读写的属性,代表当前会话的字典对象;自己有激活Django中的session支持时该属性才可用。 参数 Django Form 一、基础form提交 比如写一个计算 a和 b 之间的简单应用,网页上这么写. <!DOCTYPE html> <html> <body> <p>请输入两个数字</p> <form action="/add/" method="POST"><input type="text" name="a"> <input type="text" name="b"> <input type="submit" value="提交"> </form> </body> </html> HTML 把这些代码保存成一个index.html,放在 templates 文件夹中。 网页的值传到服务器是通过 <input> 或 <textarea>标签中的 name 属性来传递的,在服务器端这么接收: from django.http import HttpResponse from django.shortcuts import render def index(request): return render(request, 'index.html') def add(request): a = request.POST.GET('a') b = request.POST.GET('b') a = int(a) b = int(b) return HttpResponse(str(a+b) 服务器端 但是,比如用户输入的不是数字,而是字母,就出错了,还有就是提交后再回来已经输入的数据也会没了。 那么,当然如果我们手动将输入之后的数据在 views 中都获取到再传递到网页,这样是可行的,但是很不方便,所以 Django 提供了更简单易用的 forms 来解决验证等这一系列的问题。 二、Django Forms应用 1、简单案例一 在app01下新建一个文件forms.py from django import forms class AddForm(forms.Form): a = forms.IntegerField() b = forms.IntegerField() forms.py (视图函数) views.py #!/usr/bin/env python # -*- coding:utf-8 -*- from django.shortcuts import render,HttpResponse from app01.forms import AddForm def index(request): if request.method == 'POST':# 当提交表单时 # form 包含提交的数据 form = AddForm(request.POST) # 如果提交的数据合法 if form.is_valid(): a = form.cleaned_data['a'] b = form.cleaned_data['b'] return HttpResponse(str(int(a) + int(b))) # 当正常访问时 else: form = AddForm() return render(request, 'index.html', {'form': form}) views.py 对应的模板文件 index.html <form method='post'> {% csrf_token %} {{ form }} <input type="submit" value="提交"> </form> index.html 这个简单的案例,大家不知道有没有看出其中的蹊跷呢,仔细观察,form类给我做了验证,用户输入错了会弹出报错信息 2丶简单案例二 from django.db import models # Create your models here. class BookType(models.Model): caption = models.CharField(max_length=64) #最大长度 class Book(models.Model): name = models.CharField(max_length=64) #最大长度 pages = models.IntegerField() price = models.DecimalField(max_digits=10,decimal_places=2) pubdate = models.DateField() book_type = models.ForeignKey('BookType') #当然min_length --最小长度 models.py #!/usr/bin/env python # -*- coding:utf-8 -*- from django.shortcuts import render from app01.forms import Form1 def form1(request): if request.method == 'POST': # 获取请求内容做验证 f = Form1(request.POST) if f.is_valid(): print(f.cleaned_data) else: print(type(f.errors),f.errors) return render(request,'form1.html',{'error':f.errors,'form':f}) else: f = Form1() return render(request,'form1.html',{'form':f}) views.py 在app01下新建一个文件forms.py #!/usr/bin/env python # -*- coding:utf-8 -*- from django import forms from app01 import models class Form1(forms.Form): # 用户名,给该标签添加一个class属性,还有空值的报错信息修改 user = forms.CharField( widget=forms.TextInput(attrs={'class': 'c1'}), error_messages={'required': '用户名不能为空'},) # 密码定义最大长度和最小长度 pwd = forms.CharField(max_length=4,min_length=2) # 邮箱定义错误信息,required为空值错误信息,invalid为邮箱匹配错误信息 email = forms.EmailField(error_messages={'required': '邮箱不能为空', 'invalid': '邮箱格式错误'}) # 生成多行文本编辑框 memo = forms.CharField(widget=forms.Textarea()) # 下拉菜单实时更新数据库 user_type_choice = models.BookType.objects.values_list('id','caption') book_type = forms.CharField(widget=forms.widgets.Select(choices=user_type_choice,attrs={'class': "form-control"})) def __init__(self,*args, **kwargs): super(Form1, self).__init__(*args, **kwargs) self.fields['book_type'] = forms.CharField( widget=forms.widgets.Select(choices=models.BookType.objects.values_list('id','caption'),attrs={'class': "form-control"})) forms.py HTML页面(form1.html) <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .input-group{ position: relative; padding: 20px; width: 250px; } .input-group input{ width: 200px; display: inline-block; } .input-group span{ display: inline-block; position: absolute; height: 12px; font-size: 8px; border: 1px solid red; background-color: darksalmon; color: white; top: 41px; left: 20px; width: 202px; } </style> </head> <body> <form action="/form1/" method="post"> <div class="input-group"> {{ form.user }} {% if error.user.0 %} <span>{{ error.user.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.pwd }} {% if error.pwd.0 %} <span>{{ error.pwd.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.email }} {% if error.email.0 %} <span>{{ error.email.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.memo }} {% if error.memo.0 %} <span>{{ error.memo.0 }}</span> {% endif %} </div> <div class="input-group"> {{ form.book_type }} {% if error.book_type.0 %} <span>{{ error.book_type.0 }}</span> {% endif %} </div> <div> <input type="submit" value="提交"> </div> </form> </body> </html> form1.html
本篇对于python操作Mysql主要有两种情况 ·原生模块 pymsql ·ORM框架 SQLAchemy pymysql pymsql是python中操作的MYsql的模块,其使用方法和MySQLdb几乎相同 下载安装 1丶pip3 install pymsql 使用操作: 1·执行SQL conn= pymsql.connect(host = "127.0.0.1",post = 3306,user = "root",passwd = "123",db = "t1") #创建连接 cursor = conn.cursor() #创建游标 effect_row = cursor.execute("updata host set host = "1.1.1.2"") #执行SQL,并返回受影响行数 effect_row = cursor.execute("update host set = '1.1.1.2' where nid > %s",(1,)) #执行SQL,并返回受影响行数 effect_row = cursor.executemany("insert info host(host,color_id)values(%s,%s)",[("1.1.1.11",1)("1.1.1.11",2)]) #执行SQL,并返回受影响行数 conn.commit() #提交,不然无法保存新建或者修改的数据 cursor.close() #关闭游标 conn.close() #关闭连接 2丶获取创建数据自增ID #!/use/bin/evn python # -*- coding:utf-8 -*- import pymsql conn = pymsql.connect(host= "127.0.0.1",port= 3306,user= "root",passwd="123",db="t1") cursor = conn.cursor() cursor.executemanty("insert info hosts(host,color_id)values(%s,%s)",[("1.1.1.11",1),("1.1.1.11",2)]) conn.commit() cursor.colose() conn.close() #获取最新自增ID new_id = cursor.lastrowid 3丶获取查询数据 #!/use/bin/env python # -*- coding:utf-8 -*- import pymsql conn = pymsql.connect(host="127.0.0.1",post=3306,user='root',passwd='123',db='t1') cursor = conn.cursor() cursor.execute('select * from hosts') row_1 = cursor.fetchone() #获取第一行数据 row_2 = cursor.fetchmany(3) #获取前N行数据 row_3 = cursor.fetchall() #获取所有数据 conn.commit() cursor.close() conn.close() 注:在fetch数据时按照顺序进行,可以使用cursor.scroll(num,mode)来移动游标位置,如: ·cursoe.scroll(1,mode='relative') #相对当前位置移动 ·cursor.scroll(2,mode="absolute") #相对绝对位置移动 4丶fetch数据类型 关于默认获取的数据是元祖类型,如果想要或者字典类型的数据,即: #!/use/bin/env python # -*- coding:utf-8 -*- import pymsql conn = pymsql.connect(host='127.0.0.1',port=3306,user='root',passwb='12 3',db='t1') #游标设置为字典类型 cursor = conn.cursor(cursor=pymsql.cursor.DictCursor) r = cursor.execute("call p1()") result = cursor.fetchone() conn.commit() cursor.close() conn.close() SQLAchemy SQLAchemy是python编程语言下的一款ORM框架,该框架建立 在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果· 安装: pip3 install SQLAlchemy SQLAlchemy本身无法操作数据库,其必须依赖pymysql等第三方插件,Dialect用于和数据API进行交流,根据配置文件的不同,调用不同的数据库API,从而实现对数据库的操作,如; My SQL - Python mysql+mysldb://<user>:<password>@<host>[:<post>]/<dbname> pymsql mysql+pymsql://<username>:<password>@<host>/<dbname>[?<options>] MySQL - Connector mysql + mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname> cx_Oracle oracle+cx_oracle://user:pass@host:port/dbname[?key=value*key=value...] 更多详见:http://docs.sqlalchemy.org/en/latest/dialects/index.html 一丶内部处理 使用 Engine/ConnectionPooling/Dialect 进行数据库操作,Engine使用ConnectionPooling连接数据库,然后再通过Dialect执行SQL语句。 #!/usr/bin/env python # -*- coding:utf-8 -*- from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5) # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES ('1.1.1.22', 3)" # ) # 新插入行自增ID # cur.lastrowid # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES(%s, %s)",[('1.1.1.22', 3),('1.1.1.221', 3),] # ) # 执行SQL # cur = engine.execute( # "INSERT INTO hosts (host, color_id) VALUES (%(host)s, %(color_id)s)", # host='1.1.1.99', color_id=3 # ) # 执行SQL # cur = engine.execute('select * from hosts') # 获取第一行数据 # cur.fetchone() # 获取第n行数据 # cur.fetchmany(3) # 获取所有数据 # cur.fetchall() View Code 二、ORM功能使用 使用 ORM/Schema Type/SQL Expression Language/Engine/ConnectionPooling/Dialect 所有组件对数据进行操作。根据类创建对象,对象转换成SQL,执行SQL。 1、创建表 #!/usr/bin/env python # -*- coding:utf-8 -*- from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5) Base = declarative_base() # 创建单表 class Users(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(32)) extra = Column(String(16)) __table_args__ = ( UniqueConstraint('id', 'name', name='uix_id_name'), Index('ix_id_name', 'name', 'extra'), ) # 一对多 class Favor(Base): __tablename__ = 'favor' nid = Column(Integer, primary_key=True) caption = Column(String(50), default='red', unique=True) class Person(Base): __tablename__ = 'person' nid = Column(Integer, primary_key=True) name = Column(String(32), index=True, nullable=True) favor_id = Column(Integer, ForeignKey("favor.nid")) # 多对多 class Group(Base): __tablename__ = 'group' id = Column(Integer, primary_key=True) name = Column(String(64), unique=True, nullable=False) port = Column(Integer, default=22) class Server(Base): __tablename__ = 'server' id = Column(Integer, primary_key=True, autoincrement=True) hostname = Column(String(64), unique=True, nullable=False) class ServerToGroup(Base): __tablename__ = 'servertogroup' nid = Column(Integer, primary_key=True, autoincrement=True) server_id = Column(Integer, ForeignKey('server.id')) group_id = Column(Integer, ForeignKey('group.id')) def init_db(): Base.metadata.create_all(engine) def drop_db(): Base.metadata.drop_all(engine) View Code 注:设置外检的另一种方式 ForeignKeyConstraint(['other_id'], ['othertable.other_id']) 2、操作表 #!/usr/bin/env python # -*- coding:utf-8 -*- from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index from sqlalchemy.orm import sessionmaker, relationship from sqlalchemy import create_engine engine = create_engine("mysql+pymysql://root:123@127.0.0.1:3306/t1", max_overflow=5) Base = declarative_base() # 创建单表 class Users(Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) name = Column(String(32)) extra = Column(String(16)) __table_args__ = ( UniqueConstraint('id', 'name', name='uix_id_name'), Index('ix_id_name', 'name', 'extra'), ) def __repr__(self): return "%s-%s" %(self.id, self.name) # 一对多 class Favor(Base): __tablename__ = 'favor' nid = Column(Integer, primary_key=True) caption = Column(String(50), default='red', unique=True) def __repr__(self): return "%s-%s" %(self.nid, self.caption) class Person(Base): __tablename__ = 'person' nid = Column(Integer, primary_key=True) name = Column(String(32), index=True, nullable=True) favor_id = Column(Integer, ForeignKey("favor.nid")) # 与生成表结构无关,仅用于查询方便 favor = relationship("Favor", backref='pers') # 多对多 class ServerToGroup(Base): __tablename__ = 'servertogroup' nid = Column(Integer, primary_key=True, autoincrement=True) server_id = Column(Integer, ForeignKey('server.id')) group_id = Column(Integer, ForeignKey('group.id')) group = relationship("Group", backref='s2g') server = relationship("Server", backref='s2g') class Group(Base): __tablename__ = 'group' id = Column(Integer, primary_key=True) name = Column(String(64), unique=True, nullable=False) port = Column(Integer, default=22) # group = relationship('Group',secondary=ServerToGroup,backref='host_list') class Server(Base): __tablename__ = 'server' id = Column(Integer, primary_key=True, autoincrement=True) hostname = Column(String(64), unique=True, nullable=False) def init_db(): Base.metadata.create_all(engine) def drop_db(): Base.metadata.drop_all(engine) Session = sessionmaker(bind=engine) session = Session() 表结构+数据库连接 3丶基本操作 obj = Users(name="alex0", extra='sb') session.add(obj) session.add_all([ Users(name="alex1", extra='sb'), Users(name="alex2", extra='sb'), ]) session.commit() 增 session.query(Users).filter(Users.id > 2).delete() session.commit() 删 session.query(Users).filter(Users.id > 2).update({"name" : "099"}) session.query(Users).filter(Users.id > 2).update({Users.name: Users.name + "099"}, synchronize_session=False) session.query(Users).filter(Users.id > 2).update({"num": Users.num + 1}, synchronize_session="evaluate") session.commit() 改 ret = session.query(Users).all() ret = session.query(Users.name, Users.extra).all() ret = session.query(Users).filter_by(name='alex').all() ret = session.query(Users).filter_by(name='alex').first() 查 # 条件 ret = session.query(Users).filter_by(name='alex').all() ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all() ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all() ret = session.query(Users).filter(Users.id.in_([1,3,4])).all() ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all() ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all() from sqlalchemy import and_, or_ ret = session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all() ret = session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all() ret = session.query(Users).filter( or_( Users.id < 2, and_(Users.name == 'eric', Users.id > 3), Users.extra != "" )).all() # 通配符 ret = session.query(Users).filter(Users.name.like('e%')).all() ret = session.query(Users).filter(~Users.name.like('e%')).all() # 限制 ret = session.query(Users)[1:2] # 排序 ret = session.query(Users).order_by(Users.name.desc()).all() ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all() # 分组 from sqlalchemy.sql import func ret = session.query(Users).group_by(Users.extra).all() ret = session.query( func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.name).all() ret = session.query( func.max(Users.id), func.sum(Users.id), func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) >2).all() # 连表 ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all() ret = session.query(Person).join(Favor).all() ret = session.query(Person).join(Favor, isouter=True).all() # 组合 q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.caption).filter(Favor.nid < 2) ret = q1.union(q2).all() q1 = session.query(Users.name).filter(Users.id > 2) q2 = session.query(Favor.caption).filter(Favor.nid < 2) ret = q1.union_all(q2).all() 其他 更多功能参见文档,猛击这里下载PDF
视图 视图就是一个虚拟表(非真实存在),其本质是[根据SQL语句获取动态的数据集,并为其命名],用户使用时只需要使用[名称]即可获取结果集并可以将其当做代表来使用· -- 临时表搜索 SELECT * FROM ( SELECT nid, name FROM tb1 WHERE nid > 2 ) AS A WHERE A.name > 'Wyc'; 1丶创建视图 -- 格式: CREATE VIEW 视图名称 AS SQL语句 CREATE VIEW v1 AS SELECT nid, name FROM A WHERE nid > 4; 2丶删除视图 -- 格式: DROP VIEW 视图名称 DROP VIEW v1; 3丶修改视图 -- 格式:ALTER VIEW 视图名称 AS SQL语句 ALTER VIEW v1 AS SELTER A.nid, B.name FROM A LETE JOIN B ON A.id = B.nid LETE JOIN C ON A.id = C.nid WHERE A.id > 2 AND C.nid < 5; 4丶使用视图 使用视图时,将其当做表进行操作即可,由于视图是虚拟表,所以无法使用其对真实表进行创建,更新和删除操作,仅能做查询用· select * from v1; 触发器 对某个表进行[增/删/改]操作的前后如果希望触发某个特定的行为时,可以使用触发器,触发器用于定制用户对表的行,进行[增/删/改]前后的行为· 1丶创建基本语法 -- 插入前 CREATE TRIGGER tri_before_insert_tb1 BEFORE INSERT ON tb1 FOR EACH ROW BEGIN .... END -- 插入后 CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW BEGIN ..... END -- 删除前 CREATE TRIGGER tri_before_delete_tb1 BEFORE DELETE ON tb1 FOR EACH ROW BEGIN .... END -- 删除后 CREATE TRIGGER tri_after_delete_tb1 AFTER DELETE ON tb1 FOR EACH ROW BEGIN .... END -- 更新前 CREATE TRIGGER tri_before_updata_tb1 BEFORE UPDATE ON tb1 FOR EACH ROW BEGIN .... END -- 更新后 CREATE TRIGGER tri_after_update_tb1 AFTER UPDATA ON FOR EACH ROW BEGIN .... END -- 插入前触发器 delimiter // CREATE TRIGEER tri_before_insert_tb1 BEFOR INSERT ON tb1 FOR EACH ROW BEGIN IF NEW.NAME == 'Wyc' THEN INSERT INTO tb2 (NAME) VALUES ('aa') END END// delimiter ; -- 插入后触发 delimiter // CREATE TRIGGER tri_after_insert_tb1 AFTER INSERT ON tb1 FOR EACH ROW BEGIN IF NEW.nue = 666 THEN INSERT INTO tb2(NAME) VALUES ('666'), ('666'); ELSEIF NEW.num = 555 THEN INSERT INTO tb2(NAME) VALUES ('555'), ('555'); END IF; END // delimiter; 特别的:NEW表示即将插入的数据行,OLD表示即将删除的数据· 2丶删除触发器 DROP TRIGGER tri_after_insert_tb1; 3丶使用触发器 触发器无法由用户直接调用,而只由于对表的[增/删/改]操作被动引发的· insert into tb1(num) values(666); 存储过程 存储过程是一个SQL语句集合,当主动去调用存储过程时,其内部的SQL语句会按照逻辑执行· 1丶创建存储过程 -- 无参数存储过程 delimiter// create procedure p1() BEGIN select * from t1; END// delimiter; -- 执行存储过程 call p1() 对于存储过程,可以接收参数,其参数有三类: · in 仅用于传入参数用 · out 仅用于返回值用 · inout 既可以传入有可以当做返回值 -- 有参数存储过程 delimiter \\ create procedure p1( in i1 int, in i2 int, inout i3 int, out r1 int ) BEGIN DECLARE temp1 int; DECLARE temp2 int default 0; set temp1 = 1; set r1 = i1 + i2 + temp1 + temp2; set i3 = i3 + 100; end \\ delimiter; -- 执行存储过程 DECLARE @t1 INT default 3; DECLARE @t2 INT; CALL p1 (1,2,@t1,@t2); SELECT @t1,@t2; 2丶删除存储过程 drop procedure proc_name; 3丶执行存储过程 -- 无参数 call proc_name() -- 有参数,全in call proc_name(1,2) -- 有参数,有in,out,inout DECLARE @t1 INT; DECLARE @t2 INT default 3; call proc_name(1,2,@t1,@t2) ## pymysql执行存储过程 import pymysql conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwod='123',db='t1') cursor = conn.cursor(cursor=pymysql.cursors.DictCursor) #执行存储过程 cursor.callproc('p1',args=(1,2,3,4)) #获取执行完存储的参数 cursor.execute('select @_p1_0,@_p1_1,@_p1_2,@_p1_3') result = cursor.fetchall() conn.commit() -- 提交 cursor.close() conn.close() #execute :创建游标 索引 索引,是数据库中专门用于帮助用户快速查询数据的一种数据结构,类似于字典中的目录查找字典内容时可以根据目录查找到数据的存放位置,然后直接获取即可· MySQL中常见索引有: ·普通索引 ·唯一索引 ·主键索引 ·组合索引 1丶普通索引 普通索引仅有一个功能:加速查询 1 create table in1( 2 nid int not null auto_increment primary key, 3 name varchar(32) not null, 4 email varchar(64) not null, 5 extra text, 6 index ix_name(name) 7 ) 创建表+索引 1 create_index index_name on table_name(column_name) 创建索引 1 drop index_name on table_nme; 删除索引 1 show index from table_name; 查看索引 注意:对于创建索引时如果是BLOB和TEXT类型,必须制定length· create index ix_extra on in1(extra(32)); 2丶唯一索引 唯一索引有两个功能:加速查询和唯一约束(可含null) 1 create table in1( 2 nid int not null auti_increment primary key, 3 name varchar(32) not null, 4 email barchar(64) not null, 5 extra text, 6 unique ix_name (name) 7 ) 创建表+唯一索引 1 create unique index 索引名 on 表名(列名) 创建唯一索引 1 drop unique index 索引名 on 表名 删除唯一索引 3丶主键索引 主键有两个功能:加速查询和唯一约束(不可含null) 1 create table in1( 2 nid int not null auto_increment primary key, 3 name varchar(32) not null, 4 email varchar(64) not null, 5 extra text, 6 index ix_name(name) 7 ) 8 9 OR 10 11 create table in1( 12 nid int not null auto_increment, 13 name varchar(32) not null, 14 email varchar(64) not null, 15 extra text, 16 primary key(ni1), 17 index ix_name(name) 18 ) 创建表+创建主键 1 alter table 表名 add primary key(列名); 创建主键 1 alter table 表名 add paimary key; 2 alter table 表名 modify 列名 int,drop primary key; 删除主键 4丶组合索引 组合索引时将n个列组合成一个索引 其应用场景为:频繁的同事使用n列来进行查询,如:where n1 = 'Wyc' and n2 =666· 1 create table in3( 2 nid int not null auto_increment primary key, 3 name varchar(32) not null, 4 email varchar(64) not null, 5 extra text 6 ) 创建表 1 create index ix_name_email on in3(name,email); 创建组合索引 如上创建组合索引之后,查询: · name and email -- 使用索引 · name -- 使用索引 · email -- 不使用索引 注意:对于同时搜索n个条件时,组合索引的性能好于多个单一索引合并· 其他 1、条件语句 delimiter \\ CREATE PROCEDURE proc_if () BEGIN declare i int default 0; if i = 1 THEN SELECT 1; ELSEIF i = 2 THEN SELECT 2; ELSE SELECT 7; END IF; END\\ delimiter ; 2、循环语句 delimiter \\ CREATE PROCEDURE proc_while () BEGIN DECLARE num INT ; SET num = 0 ; WHILE num < 10 DO SELECT num ; SET num = num + 1 ; END WHILE ; END\\ delimiter ; while循环 delimiter \\ CREATE PROCEDURE proc_repeat () BEGIN DECLARE i INT ; SET i = 0 ; repeat select i; set i = i + 1; until i >= 5 end repeat; END\\ delimiter ; repeat循环 delimiter \\ CREATE PROCEDURE proc_loop () BEGIN declare i int default 0; loop_label: loop select i; set i=i+1; if i>=5 then leave loop_label; end if; end loop; END\\ delimiter ; loop 3、动态执行SQL语句 delimiter \\ DROP PROCEDURE IF EXISTS proc_sql \\ CREATE PROCEDURE proc_sql () BEGIN declare p1 int; set p1 = 11; set @p1 = p1; PREPARE prod FROM 'select * from tb2 where nid > ?'; EXECUTE prod USING @p1; DEALLOCATE prepare prod; END\\ delimiter ; 动态执行SQL
Memcached Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon )是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信 Memcached安装和基本使用 Memcached安装: wget http://memcached.org/latest tar -zxvf memcached-1.x.x.tar.gz cd memcached-1.x.x ./configure && make && make test && sudo make install PS:依赖libevent yum install libevent-devel apt-get install libevent-dev 启动Memcached memcached -d -m 10 -u root -l 10.211.55.4 -p 12000 -c 256 -P /tmp/memcached.pid 参数说明: -d 是启动一个守护进程 -m 是分配给Memcache使用的内存数量,单位是MB -u 是运行Memcache的用户 -l 是监听的服务器IP地址 -p 是设置Memcache监听的端口,最好是1024以上的端口 -c 选项是最大运行的并发连接数,默认是1024,按照你服务器的负载量来设定 -P 是设置保存Memcache的pid文件 Memcached命令 存储命令: set/add/replace/append/prepend/cas 获取命令: get/gets 其他命令: delete/stats.. pyhton操作Memcached 安装API python操作Memcached使用Python-memcached模块 下载安装:https://pypi.python.org/pypi/python-memcached 1丶第一次操作 import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) mc.set("foo", "bar") ret = mc.get('foo') print ret Ps:debug = True 表示运行出现错误时,现实错误信息,上线后移除该参数。 2丶天生支持集群 python-memcached模块原生支持集群操作,其原理是在内存维护一个主机列表,且集群中主机的权重值和主机在列表中重复出现的次数成正比 主机 权重 1.1.1.1 1 1.1.1.2 2 1.1.1.3 1 那么在内存中主机列表为: host_list = ["1.1.1.1", "1.1.1.2", "1.1.1.2", "1.1.1.3", ] 如果用户根据如果要在内存中创建一个键值对(如:k1 = "v1"),那么要执行一下步骤: ·根据算法将 k1 转换成一个数字 ·将数字和主机列表长度求余数,得到一个值 N( 0 <= N < 列表长度 ) ·在主机列表中根据 第2步得到的值为索引获取主机,例如:host_list[N] ·连接 将第3步中获取的主机,将 k1 = "v1" 放置在该服务器的内存中 代码实现如下: mc = memcache.Client([('1.1.1.1:12000', 1), ('1.1.1.2:12000', 2), ('1.1.1.3:12000', 1)], debug=True) mc.set('k1', 'v1') 3丶add 添加一条键值对,如果已经存在的 key,重复执行add操作异常 #!/usr/bin/env python # -*- coding:utf-8 -*- import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) mc.add('k1', 'v1') # mc.add('k1', 'v2') # 报错,对已经存在的key重复添加,失败!!! 4丶replace replace 修改某个key的值,如果key不存在,则异常 import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) # 如果memcache中存在kkkk,则替换成功,否则一场 mc.replace('kkkk','999') 5丶set和set_multi set 设置一个键值对,如果key不存在,则创建,如果key存在,则修改set_multi 设置多个键值对,如果key不存在,则创建,如果key存在,则修改 import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) mc.set('key0', 'wupeiqi') mc.set_multi({'key1': 'val1', 'key2': 'val2'}) 6丶delete和delete_multi delete 在Memcached中删除指定的一个键值对delete_multi 在Memcached中删除指定的多个键值对 import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) mc.delete('key0') mc.delete_multi(['key1', 'key2']) 7丶get和get_multi get 获取一个键值对get_multi 获取多一个键值对 import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) val = mc.get('key0') item_dict = mc.get_multi(["key1", "key2", "key3"]) 8丶append和prepend append 修改指定key的值,在该值 后面 追加内容prepend 修改指定key的值,在该值 前面 插入内容 import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) # k1 = "v1" mc.append('k1', 'after') # k1 = "v1after" mc.prepend('k1', 'before') # k1 = "beforev1after" 9丶decr和incr incr 自增,将Memcached中的某一个值增加 N ( N默认为1 )decr 自减,将Memcached中的某一个值减少 N ( N默认为1 ) import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True) mc.set('k1', '777') mc.incr('k1') # k1 = 778 mc.incr('k1', 10) # k1 = 788 mc.decr('k1') # k1 = 787 mc.decr('k1', 10) # k1 = 777 10丶gets和cas 如商城商品剩余个数,假设改值保存在memcache中,product_count = 900A用户刷新页面从memcache中读取到product_count = 900B用户刷新页面从memcache中读取到product_count = 900 如果A、B用户均购买商品 A用户修改商品剩余个数 product_count=899B用户修改商品剩余个数 product_count=899 如此一来缓存内的数据便不在正确,两个用户购买商品后,商品剩余还是 899如果使用python的set和get来操作以上过程,那么程序就会如上述所示情况! 如果想要避免此情况的发生,只要使用 gets 和 cas 即可,如 import memcache mc = memcache.Client(['10.211.55.4:12000'], debug=True, cache_cas=True) v = mc.gets('product_count') # ... # 如果有人在gets之后和cas之前修改了product_count,那么,下面的设置将会执行失败,剖出异常,从而避免非正常数据的产生 mc.cas('product_count', "899") Ps:本质上每次执行gets时,会从memcache中获取一个自增的数字,通过cas去修改gets的值时,会携带之前获取的自增值和memcache中的自增值进行比较,如果相等,则可以提交,如果不想等,那表示在gets和cas执行之间,又有其他人执行了gets(获取了缓冲的指定值), 如此一来有可能出现非正常数据,则不允许修改。 Redis redis是一个key-value存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步. ①·Redis安装和基本使用 wget http://download.redis.io/releases/redis-3.0.6.tar.gz tar xzf redis-3.0.6.tar.gz cd redis-3.0.6 make ②·启动服务端 src/redis-server ③·启动客户端 src/redis-cli redis> set foo bar OK redis> get foo "bar" ④·python操作Redis sudo pip install redis or sudo easy_install redis or 源码安装 详见:https://github.com/WoLpH/redis-py API使用 redis-py 的API的使用可以分类为: · 连接 · 连接池 · 操作 · Streing 操作 · Hash 操作 · List 操作 · Set 操作 · Sort Set 操作 · 管道 · 发布订阅 壹丶操作模式 redis-py提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。 import redis r = redis.Redis(host='10.211.55.4', port=6379) r.set('foo', 'Bar') print r.get('foo') 贰丶连接池 redis-py使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,然后作为参数Redis,这样就可以实现多个Redis实例共享一个连接池。 import redis pool = redis.ConnectionPool(host='10.211.55.4', port=6379) r = redis.Redis(connection_pool=pool) r.set('foo', 'Bar') print r.get('foo') 叁丶操作 String操作,redis中的String在在内存中按照一个name对应一个value来存储。如图: set(name, value, ex=None, px=None, nx=False, xx=False) 在Redis中设置值,默认,不存在则创建,存在则修改 参数: ex,过期时间(秒) px,过期时间(毫秒) nx,如果设置为True,则只有name不存在时,当前set操作才执行 xx,如果设置为True,则只有name存在时,岗前set操作才执行 setnx(name, value) 设置值,只有name不存在时,执行设置操作(添加) setex(name, value, time) # 设置值 # 参数: # time,过期时间(数字秒 或 timedelta对象) psetex(name, time_ms, value) # 设置值 # 参数: # time_ms,过期时间(数字毫秒 或 timedelta对象) mset(*args, **kwargs) 批量设置值 如: mset(k1='v1', k2='v2') 或 mget({'k1': 'v1', 'k2': 'v2'}) get(name) 获取值 mget(keys, *args) 批量获取 如: mget('ylr', 'wupeiqi') 或 r.mget(['ylr', 'wupeiqi']) getset(name, value) 设置新值并获取原来的值 getrange(key, start, end) # 获取子序列(根据字节获取,非字符) # 参数: # name,Redis 的 name # start,起始位置(字节) # end,结束位置(字节) # 如: "明天会更好" ,0-3表示 "明" setrange(name, offset, value) # 修改字符串内容,从指定字符串索引开始向后替换(新值太长时,则向后添加) # 参数: # offset,字符串的索引,字节(一个汉字三个字节) # value,要设置的值 setbit(name, offset, value) # 对name对应值的二进制表示的位进行操作 # 参数: # name,redis的name # offset,位的索引(将值变换成二进制后再进行索引) # value,值只能是 1 或 0 # 注:如果在Redis中有一个对应: n1 = "foo", 那么字符串foo的二进制表示为:01100110 01101111 01101111 所以,如果执行 setbit('n1', 7, 1),则就会将第7位设置为1, 那么最终二进制则变成 01100111 01101111 01101111,即:"goo" # 扩展,转换二进制表示: # source = "吴永聪" source = "foo" for i in source: num = ord(i) print bin(num).replace('b','') 特别的,如果source是汉字 "吴永聪"怎么办? 答:对于utf-8,每一个汉字占 3 个字节,那么 "吴永聪" 则有 9个字节 对于汉字,for循环时候会按照 字节 迭代,那么在迭代时,将每一个字节转换 十进制数,然后再将十进制数转换成二进制 11100110 10101101 10100110 11100110 10110010 10011011 11101001 10111101 10010000 -------------------------- ----------------------------- ----------------------------- 吴 永 聪 getbit(name, offset) # 获取name对应的值的二进制表示中的某位的值 (0或1) bitcount(key, start=None, end=None) # 获取name对应的值的二进制表示中 1 的个数 # 参数: # key,Redis的name # start,位起始位置 # end,位结束位置 bitop(operation, dest, *keys) # 获取多个值,并将值做位运算,将最后的结果保存至新的name对应的值 # 参数: # operation,AND(并) 、 OR(或) 、 NOT(非) 、 XOR(异或) # dest, 新的Redis的name # *keys,要查找的Redis的name # 如: bitop("AND", 'new_name', 'n1', 'n2', 'n3') # 获取Redis中n1,n2,n3对应的值,然后讲所有的值做位运算(求并集),然后将结果保存 new_name 对应的值中 strlen(name) # 返回name对应值的字节长度(一个汉字3个字节) incr(self, name, amount=1) # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。 # 参数: # name,Redis的name # amount,自增数(必须是整数) # 注:同incrby incrbyfloat(self, name, amount=1.0) # 自增 name对应的值,当name不存在时,则创建name=amount,否则,则自增。 # 参数: # name,Redis的name # amount,自增数(浮点型 decr(self, name, amount=1) # 自减 name对应的值,当name不存在时,则创建name=amount,否则,则自减。 # 参数: # name,Redis的name # amount,自减数(整数) append(key, value) # 在redis name对应的值后面追加内容 # 参数: key, redis的name value, 要追加的字符串 Hash操作,redis中Hash在内存中的存储格式如下图: hset(name, key, value) # name对应的hash中设置一个键值对(不存在,则创建;否则,修改) # 参数: # name,redis的name # key,name对应的hash中的key # value,name对应的hash中的value # 注: # hsetnx(name, key, value),当name对应的hash中不存在当前key时则创建(相当于添加) hmset(name, mapping) # 在name对应的hash中批量设置键值对 # 参数: # name,redis的name # mapping,字典,如:{'k1':'v1', 'k2': 'v2'} # 如: # r.hmset('xx', {'k1':'v1', 'k2': 'v2'}) hget(name,key) # 在name对应的hash中获取根据key获取value hmget(name, keys, *args) # 在name对应的hash中获取多个key的值 # 参数: # name,reids对应的name # keys,要获取key集合,如:['k1', 'k2', 'k3'] # *args,要获取的key,如:k1,k2,k3 # 如: # r.mget('xx', ['k1', 'k2']) # 或 # print r.hmget('xx', 'k1', 'k2') hgetall(name) 获取name对应hash的所有键值 hlen(name) # 获取name对应的hash中键值对的个数 hkeys(name) # 获取name对应的hash中所有的key的值 hvals(name) # 获取name对应的hash中所有的value的值 hexists(name, key) # 检查name对应的hash是否存在当前传入的key hdel(name,*keys) # 将name对应的hash中指定key的键值对删除 hincrby(name, key, amount=1) # 自增name对应的hash中的指定key的值,不存在则创建key=amount # 参数: # name,redis中的name # key, hash对应的key # amount,自增数(整数) hincrbyfloat(name, key, amount=1.0) # 自增name对应的hash中的指定key的值,不存在则创建key=amount # 参数: # name,redis中的name # key, hash对应的key # amount,自增数(浮点数) # 自增name对应的hash中的指定key的值,不存在则创建key=amount hscan(name, cursor=0, match=None, count=None) # 增量式迭代获取,对于数据大的数据非常有用,hscan可以实现分片的获取数据,并非一次性将数据全部获取完,从而放置内存被撑爆 # 参数: # name,redis的name # cursor,游标(基于游标分批取获取数据) # match,匹配指定key,默认None 表示所有的key # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 # 如: # 第一次:cursor1, data1 = r.hscan('xx', cursor=0, match=None, count=None) # 第二次:cursor2, data1 = r.hscan('xx', cursor=cursor1, match=None, count=None) # ... # 直到返回值cursor的值为0时,表示数据已经通过分片获取完毕 hscan_iter(name, match=None, count=None) # 利用yield封装hscan创建生成器,实现分批去redis中获取数据 # 参数: # match,匹配指定key,默认None 表示所有的key # count,每次分片最少获取个数,默认None表示采用Redis的默认分片个数 # 如: # for item in r.hscan_iter('xx'): # print item List操作,redis中的List在在内存中按照一个name对应一个List来存储。如图: lpush(name,values) # 在name对应的list中添加元素,每个新的元素都添加到列表的最左边 # 如: # r.lpush('oo', 11,22,33) # 保存顺序为: 33,22,11 # 扩展: # rpush(name, values) 表示从右向左操作 lpushx(name,value) # 在name对应的list中添加元素,只有name已经存在时,值添加到列表的最左边 # 更多: # rpushx(name, value) 表示从右向左操作 llen(name) # name对应的list元素的个数 linsert(name, where, refvalue, value)) # 在name对应的列表的某一个值前或后插入一个新值 # 参数: # name,redis的name # where,BEFORE或AFTER # refvalue,标杆值,即:在它前后插入数据 # value,要插入的数据 r.lset(name, index, value) # 对name对应的list中的某一个索引位置重新赋值 # 参数: # name,redis的name # index,list的索引位置 # value,要设置的值 r.lrem(name, value, num) # 在name对应的list中删除指定的值 # 参数: # name,redis的name # value,要删除的值 # num, num=0,删除列表中所有的指定值; # num=2,从前到后,删除2个; # num=-2,从后向前,删除2个 lpop(name) # 在name对应的列表的左侧获取第一个元素并在列表中移除,返回值则是第一个元素 # 更多: # rpop(name) 表示从右向左操作 lindex(name, index) 在name对应的列表中根据索引获取列表元素 lrange(name, start, end) # 在name对应的列表分片获取数据 # 参数: # name,redis的name # start,索引的起始位置 # end,索引结束位置 ltrim(name, start, end) # 在name对应的列表中移除没有在start-end索引之间的值 # 参数: # name,redis的name # start,索引的起始位置 # end,索引结束位置 rpoplpush(src, dst) # 从一个列表取出最右边的元素,同时将其添加至另一个列表的最左边 # 参数: # src,要取数据的列表的name # dst,要添加数据的列表的name blpop(keys, timeout) # 将多个列表排列,按照从左到右去pop对应列表的元素 # 参数: # keys,redis的name的集合 # timeout,超时时间,当元素所有列表的元素获取完之后,阻塞等待列表内有数据的时间(秒), 0 表示永远阻塞 # 更多: # r.brpop(keys, timeout),从右向左获取数据 brpoplpush(src, dst, timeout=0) # 从一个列表的右侧移除一个元素并将其添加到另一个列表的左侧 # 参数: # src,取出并要移除元素的列表对应的name # dst,要插入元素的列表对应的name # timeout,当src对应的列表中没有数据时,阻塞等待其有数据的超时时间(秒),0 表示永远阻塞 自定义增量迭代 # 由于redis类库中没有提供对列表元素的增量迭代,如果想要循环name对应的列表的所有元素,那么就需要: # 1、获取name对应的所有列表 # 2、循环列表 # 但是,如果列表非常大,那么就有可能在第一步时就将程序的内容撑爆,所有有必要自定义一个增量迭代的功能: def list_iter(name): """ 自定义redis列表增量迭代 :param name: redis中的name,即:迭代name对应的列表 :return: yield 返回 列表元素 """ list_count = r.llen(name) for index in xrange(list_count): yield r.lindex(name, index) # 使用 for item in list_iter('pp'): print item Set操作,Set集合就是不允许重复的列表 sadd(name,values) # name对应的集合中添加元素 scard(name) 获取name对应的集合中元素个数 sdiff(keys, *args) # 检查value是否是name对应的集合的成员 在第一个name对应的集合中且不在其他name对应的集合的元素集合 sdiffstore(dest, keys, *args) # 获取第一个name对应的集合中且不在其他name对应的集合,再将其新加入到dest对应的集合中 sinter(keys, *args) # 获取多一个name对应集合的并集 sinterstore(dest, keys, *args) # 获取多一个name对应集合的并集,再讲其加入到dest对应的集合中 sismember(name, value) # 检查value是否是name对应的集合的成员 smembers(name) # 获取name对应的集合的所有成员 smove(src, dst, value) # 将某个成员从一个集合中移动到另外一个集合 spop(name) # 从集合的右侧(尾部)移除一个成员,并将其返回 srandmember(name, numbers) # 从name对应的集合中随机获取 numbers 个元素 srem(name, values) # 在name对应的集合中删除某些值 sunion(keys, *args) # 获取多一个name对应的集合的并集 sunionstore(dest,keys, *args) # 获取多一个name对应的集合的并集,并将结果保存到dest对应的集合中 sscan(name, cursor=0, match=None, count=None)sscan_iter(name, match=None, count=None) # 同字符串的操作,用于增量迭代分批获取元素,避免内存消耗太大 有序集合,在集合的基础上,为每元素排序;元素的排序需要根据另外一个值来进行比较,所以,对于有序集合,每一个元素有两个值,即:值和分数,分数专门用来做排序。 zadd(name, *args, **kwargs) # 在name对应的有序集合中添加元素 # 如: # zadd('zz', 'n1', 1, 'n2', 2) # 或 # zadd('zz', n1=11, n2=22) zcard(name) # 获取name对应的有序集合元素的数量 zcount(name, min, max) # 获取name对应的有序集合中分数 在 [min,max] 之间的个数 zincrby(name, value, amount) # 自增name对应的有序集合的 name 对应的分数 r.zrange( name, start, end, desc=False, withscores=False, score_cast_func=float) # 按照索引范围获取name对应的有序集合的元素 # 参数: # name,redis的name # start,有序集合索引起始位置(非分数) # end,有序集合索引结束位置(非分数) # desc,排序规则,默认按照分数从小到大排序 # withscores,是否获取元素的分数,默认只获取元素的值 # score_cast_func,对分数进行数据转换的函数 # 更多: # 从大到小排序 # zrevrange(name, start, end, withscores=False, score_cast_func=float) # 按照分数范围获取name对应的有序集合的元素 # zrangebyscore(name, min, max, start=None, num=None, withscores=False, score_cast_func=float) # 从大到小排序 # zrevrangebyscore(name, max, min, start=None, num=None, withscores=False, score_cast_func=float) zrank(name, value) # 获取某个值在 name对应的有序集合中的排行(从 0 开始) # 更多: # zrevrank(name, value),从大到小排序 zrangebylex(name, min, max, start=None, num=None) # 当有序集合的所有成员都具有相同的分值时,有序集合的元素会根据成员的 值 (lexicographical ordering)来进行排序,而这个命令则可以返回给定的有序集合键 key 中, 元素的值介于 min 和 max 之间的成员 # 对集合中的每个成员进行逐个字节的对比(byte-by-byte compare), 并按照从低到高的顺序, 返回排序后的集合成员。 如果两个字符串有一部分内容是相同的话, 那么命令会认为较长的字符串比较短的字符串要大 # 参数: # name,redis的name # min,左区间(值)。 + 表示正无限; - 表示负无限; ( 表示开区间; [ 则表示闭区间 # min,右区间(值) # start,对结果进行分片处理,索引位置 # num,对结果进行分片处理,索引后面的num个元素 # 如: # ZADD myzset 0 aa 0 ba 0 ca 0 da 0 ea 0 fa 0 ga # r.zrangebylex('myzset', "-", "[ca") 结果为:['aa', 'ba', 'ca'] # 更多: # 从大到小排序 # zrevrangebylex(name, max, min, start=None, num=None) zrem(name, values) # 删除name对应的有序集合中值是values的成员 # 如:zrem('zz', ['s1', 's2']) zremrangebyrank(name, min, max) zremrangebyrank(name, min, max) zremrangebyscore(name, min, max) # 根据分数范围删除 zremrangebylex(name, min, max) # 根据值返回删除 zscore(name, value) # 获取name对应有序集合中 value 对应的分数 zinterstore(dest, keys, aggregate=None) # 获取两个有序集合的交集,如果遇到相同值不同分数,则按照aggregate进行操作 # aggregate的值为: SUM MIN MAX zunionstore(dest, keys, aggregate=None) # 获取两个有序集合的并集,如果遇到相同值不同分数,则按照aggregate进行操作 # aggregate的值为: SUM MIN MAX zscan(name, cursor=0, match=None, count=None, score_cast_func=float)zscan_iter(name, match=None, count=None,score_cast_func=float) # 同字符串相似,相较于字符串新增score_cast_func,用来对分数进行操作 其他常用操作 delete(*names) # 根据删除redis中的任意数据类型 exists(name) # 检测redis的name是否存在 keys(pattern='*') # 根据模型获取redis的name # 更多: # KEYS * 匹配数据库中所有 key 。 # KEYS h?llo 匹配 hello , hallo 和 hxllo 等。 # KEYS h*llo 匹配 hllo 和 heeeeello 等。 # KEYS h[ae]llo 匹配 hello 和 hallo ,但不匹配 hillo expire(name ,time) # 为某个redis的某个name设置超时时间 rename(src, dst) # 对redis的name重命名为 move(name, db)) # 将redis的某个值移动到指定的db下 randomkey() # 随机获取一个redis的name(不删除) type(name) # 获取name对应值的类型 scan(cursor=0, match=None, count=None)scan_iter(match=None, count=None) # 同字符串操作,用于增量迭代获取key 肆、管道 redis-py默认在执行每次请求都会创建(连接池申请连接)和断开(归还连接池)一次连接操作,如果想要在一次请求中指定多个命令,则可以使用pipline实现一次请求指定多个命令,并且默认情况下一次pipline 是原子性操作。 import redis pool = redis.ConnectionPool(host='10.211.55.4', port=6379) r = redis.Redis(connection_pool=pool) # pipe = r.pipeline(transaction=False) pipe = r.pipeline(transaction=True) r.set('name', 'alex') r.set('role', 'sb') pipe.execute() 伍、发布订阅 订阅者:Dashboad和数据处理 1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 4 import redis 5 6 7 class RedisHelper: 8 9 def __init__(self): 10 self.__conn = redis.Redis(host='10.211.55.4') 11 self.chan_sub = 'fm104.5' 12 self.chan_pub = 'fm104.5' 13 14 def public(self, msg): 15 self.__conn.publish(self.chan_pub, msg) 16 return True 17 18 def subscribe(self): 19 pub = self.__conn.pubsub() 20 pub.subscribe(self.chan_sub) 21 pub.parse_response() 22 return pub Dome如下 订阅者: ####订阅者 # import redis # # r = redis.Redis(host='IP地址') # pub = r.pubsub() # pub.subscribe('fm999') # while True: # msg = pub.parse_response() # print(msg) 发布者: # 发布者 # import redis # r = redis.Redis(host='IP地址') # r.publish('fm999','hh') 更多参见:https://github.com/andymccurdy/redis-py/ http://doc.redisfans.com/
2丶查询‘生物’课程比‘物理’课程成绩高的所有学生的学号 思路: 获取所有有生物课成的人(学号,成绩) -- 临时表 获取所有有物理课程的人(学号,成绩) -- 临时表 根据[学号]连接两个临时表: 学号 物理成绩 生物成绩 然后在进行筛选 select A.studeny_id,sw,ty from (select student_id,num as sw from score left join coure.course_id = course.cid where course.cname = '生物') as A left join (select student_id,num as ty from score left join course on score.course_id = course.cid where course.cname = '物理') as B 3丶查询平均成绩大于60分的同学的学号和平均成绩: 思路: 根据学生分组,使用avg获取平均值,通过having对avg进行筛选 select student_id,avg(num) from score group by student_id having avg(num) > 60 4丶查询所有同学的学号,姓名,选课数,总成绩: select score.student_id,sum(score.num),count(score.student_id),stident.sname from score left join sudent on score.student_id = student.sid group by score.student_id 5丶查询姓“李”的老师的个数: 1, select count(tid) from teacher where tname like '李%' 2, select count(1) from (select tid from teacher where tname like '李%') as B 6丶查询没学过‘叶平’老师课的同学的学号,姓名: 思路: 先查到‘李平老师’所教的所有课的ID 获取选过课的所有学生ID 学生表中筛选 select * from student where sid not in ( select DISTINCT student_id from score where score.course_id in ( select cid from course left join teacher on course.teacher_id = teacher.tid where tname = '李平老师' ) ) 7丶查询学过‘001’并且也学过编号‘002’课程的同学的学号,姓名: 思路: 先查到即选择001又选择002课程的所有同学 根据学生进行分组,如果学生数量等于2表示,两门均已选择 select student_id,sname from (select student_id,course_id from score where couse_id = 1 or course_id = 2) as B left join student on B.student_id = student.sid group by student_id having count(student_id) > 1 8丶查询学过‘叶平’老师所教的所有课的学号,姓名: 同上,支部过奖001和002变成了 in (叶平老师的所有课) 9丶查询课程编号'002'的成绩比课程编号‘001’课程低的所有同学的学号,姓名: 同第一题 10丶查询所有课程成绩小于60分的同学的学号,姓名: select sid,sname from student where sid in ( select distinct student_id from score where num < 60 ) 11丶查询没有学全所有课的同学的学号,姓名: 思路: 在分数表中根据学生进行分组,获取没一个学生选课数量 如果数量 == 总课程数量,表示已经选择了所有课程 select student_id,sname from score left join student on score.student_id = student.sid group by student_id having count(course_id) = (select count(1) from course) 12丶查询只收有一门课与学号为‘001’的同学所学相同的同学的学号和姓名: 思路: 获取 001 同学选择的所有课程 获取课程在其中的素偶有人一级所有课程 根据学生筛选,获取所有学生信息 再与学生表连接,获取姓名 select student_id,sname,count(course_id) from score left join student on score.student_id = student.sid where student_id != 1 and course_id in (select course_id from score where student_id = 1) group by student_id 13丶查询只少学过学号为‘001’同学所有课的其他同学学号和姓名: 先找到和001的学过的所有人 然后个数 = 001所有学科 == > 其他人可以选择的更多 select student_id,sname,count(course_id) from score left join student on score score.student_id = student.sid where student-id != 1 and course_id in (select course_id from score where student_id = 1) group by student_id having count(course_id) = (select count(course_id) from score where student_id = 1) 14丶查询和'002'号的同学学习的课程完全相同的其他同学学号的姓名: 个数相同 002学过的也相同 select student_id,sname from score left join student on score.student_id = student.sid where student_id in ( select student_id from score where student_id != 1 group by student_id having count(course_id) = (select count(1) from score where student_id = 1) )and course_id in (select course_id from score where student_id = 1) group by student_id having count(course_id) = (select count(1) from score where student_id = 1) 15丶删除学习‘叶平’老师课的score表记录 delete from score where course_id in ( select cid from course left join tecaher on course.teacher_id = teacher.tid where teacher.name = '叶平' ) 16丶向sc表中插入一些记录,这些记录要求符合以下条件:没有上过编号'002'课程的同学学号:插入‘002’号课程的平均成绩: 思路: 由于insert 支持 insert into tb1(xx,xx) select x1,x2 from tb2; 所有,获取所有没上过002课的所有人,获取002的平均成绩 insert into score(student_id,course_id,num)select sid,2,(select avg(num) from score where course_id = 2) from student where sid not in( select student_id from score where course_id = 2 ) 17丶按平均成绩从低到高显示所有学生的‘语文’,‘数学’,‘英语’三门课程成绩,按如下形式显示:学生ID,语文,数学,英语,有效课程,有效平均分: select sc.student_id, (select num from score left join course on score.score.course_id = course.cid where course.cname = '生物' and score.student_id = sc.student_id ) as sy, (select num from score left join course on score.course_id = course.cid where course.cname = '物理' and score.student_id = sc.student_id) as w, (select num from left join course on score.course_id = course.cid where course.cname = '体育' and score.student_id = sc.student_id) as ty, count(sc.course_id), avg(sc.num) from score as sc group by student_id desc 18丶查询各科成绩最高和最低的分:以如下形式显示:课程ID,最高分,最低分; select course_id,max(num) as max_num,min(num) as min_num from score group by course_id; 19丶按各科平均成绩从低到高和及格率的百分数从高到低顺序: 思路: case where ... thed select course_id,avg(num) as avgnum,sum(case when score.num > 60 then 1 else 0 END)/count(1) * 100 as percent from score group by course_id order by avgnum asc,percent desc; 20丶课程平均分从高到低显示(现实任课老师): select avg(if(isnull(score.num),0,score.num)),teacher.tname from course left join score on course.cid = score.course_id left join teacher on course.teacher_id = teacher.tid group by score.course_id 21、查询各科成绩前三名的记录:(不考虑成绩并列情况) select score.sid,score.course_id,score.num,T.first_num,T.second_num from score left join ( select sid, (select num from score as s2 where s2.course_id = s1.course_id order by num desc limit 0,1) as first_num, (select num from score as s2 where s2.course_id = s1.course_id order by num desc limit 3,1) as second_num from score as s1 ) as T on score.sid =T.sid where score.num <= T.first_num and score.num >= T.second_num 22、查询每门课程被选修的学生数; select course_id, count(1) from score group by course_id; 23、查询出只选修了一门课程的全部学生的学号和姓名; select student.sid, student.sname, count(1) from score left join student on score.student_id = student.sid group by course_id having count(1) = 1 24、查询男生、女生的人数; select * from (select count(1) as man from student where gender='男') as A , (select count(1) as feman from student where gender='女') as B 25、查询姓“张”的学生名单; select sname from student where sname like '张%'; 26、查询同名同姓学生名单,并统计同名人数; select sname,count(1) as count from student group by sname; 27、查询每门课程的平均成绩,结果按平均成绩升序排列,平均成绩相同时,按课程号降序排列; select course_id,avg(if(isnull(num), 0 ,num)) as avg from score group by course_id order by avg asc,course_id desc; 28、查询平均成绩大于85的所有学生的学号、姓名和平均成绩; select student_id,sname, avg(if(isnull(num), 0 ,num)) from score left join student on score.student_id = student.sid group by student_id; 29、查询课程名称为“数学”,且分数低于60的学生姓名和分数; select student.sname,score.num from score left join course on score.course_id = course.cid left join student on score.student_id = student.sid where score.num < 60 and course.cname = '生物' 30、查询课程编号为003且课程成绩在80分以上的学生的学号和姓名; select * from score where score.student_id = 3 and score.num > 80 31、求选了课程的学生人数 select count(distinct student_id) from score select count(c) from ( select count(student_id) as c from score group by student_id) as A 32、查询选修“杨艳”老师所授课程的学生中,成绩最高的学生姓名及其成绩; select sname,num from score left join student on score.student_id = student.sid where score.course_id in (select course.cid from course left join teacher on course.teacher_id = teacher.tid where tname='张磊老师') order by num desc limit 1; 33、查询各个课程及相应的选修人数; select course.cname,count(1) from score left join course on score.course_id = course.cid group by course_id; 34、查询不同课程但成绩相同的学生的学号、课程号、学生成绩; select DISTINCT s1.course_id,s2.course_id,s1.num,s2.num from score as s1, score as s2 where s1.num = s2.num and s1.course_id != s2.course_id; 35、查询每门课程成绩最好的前两名; select score.sid,score.course_id,score.num,T.first_num,T.second_num from score left join ( select sid, (select num from score as s2 where s2.course_id = s1.course_id order by num desc limit 0,1) as first_num, (select num from score as s2 where s2.course_id = s1.course_id order by num desc limit 1,1) as second_num from score as s1 ) as T on score.sid =T.sid where score.num <= T.first_num and score.num >= T.second_num 36、检索至少选修两门课程的学生学号; select student_id from score group by student_id having count(student_id) > 1 37、查询全部学生都选修的课程的课程号和课程名; select course_id,count(1) from score group by course_id having count(1) = (select count(1) from student); 38、查询没学过“叶平”老师讲授的任一门课程的学生姓名; select student_id,student.sname from score left join student on score.student_id = student.sid where score.course_id not in ( select cid from course left join teacher on course.teacher_id = teacher.tid where tname = '张磊老师' ) group by student_id 39、查询两门以上不及格课程的同学的学号及其平均成绩; select student_id,count(1) from score where num < 60 group by student_id having count(1) > 2 40、检索“004”课程分数小于60,按分数降序排列的同学学号; select student_id from score where num< 60 and course_id = 4 order by num desc; 41、删除“002”同学的“001”课程的成绩; delete from score where course_id = 1 and student_id = 2
一丶概述 1·什么是MySQL丶Oracle丶SQLite丶Access丶MS SQL Server等? 答:放数据的仓库,如:在ATM的实列中我们创建了一个db目录,称其为数据库· 2·什么事MySQL,Oracle,SQLite,Access,MS SQL Server等? 答:他们均是一个软件,都有两个主要的功能, ·1.强数据保存到文件或内存 ·2.接收特定的命令,然后对文件进行相对应的操作· 3丶什么是SQL? 答:上述提到MySQL等软件可以接收命令,并做出相对应的操作 ,由于命令中可以包含删除文件,获取文件内容等众多操作,对于编写的命令就是SQL语句· 二丶下载安装 MySQL是一个关系型数据库管理系统,由瑞典MySQL AB公司开发,目前属于Oracle旗下公司.MySQL最流行的关系型数据库管理系统,在WEB应用方面MySQL是最好的RDBMS(Relational Database Manaqement System,关系数据库管理系统)应用软件之一· 想要MySQL来储存并操作数据,则需要做几件事情: 1·安装MySQL服务端 2·安装MySQL客户端 3·[客户端]连接[服务端] 4·[客户端]发送命令给[服务端MySQL]服务的接收命令并执行相应操作(增删改查等) 下载: http://dev.mysql.com/downloads/mysql/ 服务端启动: mysql.server start 客户端连接: 连接; mysql - h host -u user -p 常见错误: ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2), it means that the MySQL server daemon (Unix) or service (Windows) is not running. 退出: QUIT 或者 Conntrol+D 三丶数据库操作 1·显示数据库 SHOW DATABASES; #注意一定要加分号 默认数据库 mysql - 用户权限相关数据 test - 用于用户测试数据 information_schema - MySQL本身架构相关数据 2·创建数据库 #utf-8 CREATE DATABASE 数据库名称 DEFAULT CHARSET utf-8 COLLATE utf8_general_ci; #gbk CREATE DATABASE 数据库名称 DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci; 3·使用数据库 USE db_name; 显示当前使用的数据库中所有表:SHOW TABLES; 4·用户管理 创建用户 create user '用户名'@'IP地址' identified by '密码'; 删除用户 drop user '用户名'@'ip地址'; 修改用户 rename user '用户名'@'IP地址';to'新用户名'@'IP地址'; 修改密码 set password for '用户名'@'IP地址' = password('新密码') 注:用户权限相关数据保存在mysql数据库的user表中,所以也可以直接对其进行操作(不建议) 5·授权管理 show grants for '用户名'@'IP地址' --查看权限 grant 权限 on数据库.表 to '用户名'@'IP地址' -- 权限 revoke 权限 on数据库.表 from '用户名'@'IP地址' --取消权限 all.privileges 除grant外的所有权限 select 仅查权限 select,insert 查和插入权限 ..... usage 无访问权限 alter 使用alter table alter routine 使用alter procedure 和 drop procedure create 使用create table create routine 使用create procedure create temporary tables 使用create temporary tables create user 使用create user,drop user,reanme user和revoke all privileges create view 使用create view delete 使用delete drop 使用drop table execute 使用call和存储过程 file 使用select info onto outfile 和 load data infile grant option 使用grant 和 revoke index 使用index insert 使用insert lock tables 使用lock table process 使用show full processlist select 使用select show databases 使用show databases show vies 使用show view update 使用update reload 使用flush shutdown 使用mysqladmin shutdown(关闭MySQL) replication 服务器位置的访问 replication slave 由复制从属使用 #对于数据库 对于目标数据库以及内部其他: 数据库名.* 数据库中的所有 数据库名.表 指定数据库中的某张表 数据库名.存储过程 指定数据库中的存储过程 *.* 所有数据库 #对于用户和IP 用户名@IP地址 用户只能在改IP下才能访问 用户名@192.168.1.% 用户名只能在改IP段下才能访问(统配符%表示任意) 用户名@% 用户可以再任意IP下访问(默认IP地址为%) #示列 grant all privileges on db1.tb1 TO '用户名'@'IP' grant select on db1.* TO '用户名'@'IP' grant select,insert on *.* TO '用户名'@'IP' revoke select on db1.tb1 from '用户名'@'IP' 四丶数据表基本 1丶创建表 create table 表名( 列名 类型 是否可以为空 列名 类型 是否可以为空 )ENGINE=InnoDB DEFAULT CHARSET=utf8 是否可以为空,null表示空,非字符串 not null - 不可空 null - 可空 默认值,创建列表示可以指定默认值,当插入数据时如果未主动设置,则自动添加默认值 create table tbl( nid int not null defalut 2, num int not null ) 自增,如果为某列设置自增列,插入数据时无需设置此列,默认将自增(表中只能有一个自增列) create table tbl( nid int not null auto_increment primary key, num int null ) 或 create table tbl( nid int not null auto_increment, num int null, index(nid) ) 注意:1,对于自增列,必须是索引(含主键) 2,对于自增可以设置步长和起始值 show session variables like 'auto_inc%'; set session auto_increment_increment=2; set session auto_increment_offset=10; show global variables like 'quto_inc%'; set global auto_increment_increment=2; set global auto_increment_offset=10; 主键,一种特殊的唯一索引,不允许有空值,如果主键使用单个列,则它的值必须唯一,如果是多列,则其组合必须唯一· create table tbl( nid int not null auto_increment primary key, num int null ) 或 create table tbl( nid int not null, num int not null, primary key(nid,num) ) 外键,一个特殊的索引,只能是指定内容 creat table color( nid int not null primary key, name char(16) not null ) create table fruit( nid int not null primary key, smt char(32) null, color_id int not null, constraint fk_cc foreign key (color_id) refences color(nid) ) 2丶删除表 drop table 表名 3丶清空表 delete from 表名 truncate table 表名 4丶修改表 添加列:alter table 表名 modify column 列名 类型; 删除列:alter table 表名 drop column 列名 修改列: alter table 表名 modify column 列名 类型; ---类型 alter table 表名 change 原列名 新列名 类型; -- 列名,类型 添加主键: alter table 表名 add primary key(列名); 删除主键: alter table 表名 drop primary key; alter table 表名 modify 列名 int, drop primary key; 添加外键:alter table 从表 add constaint 外键名称(形如:FK_从表_主表) foreign key (外键字段) references 主表(主键字段); 删除外键:alter table 表名 drop foreign key 外键名称 修改默认值:ALTER TABLE testalter_tbl ALTER i SET DEFAULT 10000; 删除默认值:ALTER TABLE testalter_tbl ALTER i DROP DEFAULT; 5丶基本数据类型 MySQL的数据类型大致分为:数值,时间和字符串 bit[(M)] 二进制位(101001),m表示二进制位的长度(1-64),默认m=1 tinyint[(m)] [unsigned] [zerofill] 小整数,数据类型用于保存一些范围的整数数值范围: 有符号: -128 ~ 127. 无符号: 0 ~ 255 特别的: MySQL中无布尔值,使用tinyint(1)构造。 int[(m)][unsigned][zerofill] 整数,数据类型用于保存一些范围的整数数值范围: 有符号: -2147483648 ~ 2147483647 无符号: 0 ~ 4294967295 特别的:整数类型中的m仅用于显示,对存储范围无限制。例如: int(5),当插入数据2时,select 时数据显示为: 00002 bigint[(m)][unsigned][zerofill] 大整数,数据类型用于保存一些范围的整数数值范围: 有符号: -9223372036854775808 ~ 9223372036854775807 无符号: 0 ~ 18446744073709551615 decimal[(m[,d])] [unsigned] [zerofill] 准确的小数值,m是数字总个数(负号不算),d是小数点后个数。 m最大值为65,d最大值为30。 特别的:对于精确数值计算时需要用此类型 decaimal能够存储精确值的原因在于其内部按照字符串存储。 FLOAT[(M,D)] [UNSIGNED] [ZEROFILL] 单精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。 无符号: -3.402823466E+38 to -1.175494351E-38, 0 1.175494351E-38 to 3.402823466E+38 有符号: 0 1.175494351E-38 to 3.402823466E+38 **** 数值越大,越不准确 **** DOUBLE[(M,D)] [UNSIGNED] [ZEROFILL] 双精度浮点数(非准确小数值),m是数字总个数,d是小数点后个数。 无符号: -1.7976931348623157E+308 to -2.2250738585072014E-308 0 2.2250738585072014E-308 to 1.7976931348623157E+308 有符号: 0 2.2250738585072014E-308 to 1.7976931348623157E+308 **** 数值越大,越不准确 **** char (m) char数据类型用于表示固定长度的字符串,可以包含最多达255个字符。其中m代表字符串的长度。 PS: 即使数据小于m长度,也会占用m长度 varchar(m) varchars数据类型用于变长的字符串,可以包含最多达255个字符。其中m代表该数据类型所允许保存的字符串的最大长度,只要长度小于该最大值的字符串都可以被保存在该数据类型中。 注:虽然varchar使用起来较为灵活,但是从整个系统的性能角度来说,char数据类型的处理速度更快,有时甚至可以超出varchar处理速度的50%。因此,用户在设计数据库时应当综合考虑各方面的因素,以求达到最佳的平衡 text text数据类型用于保存变长的大字符串,可以组多到65535 (2**16 − 1)个字符。 mediumtext A TEXT column with a maximum length of 16,777,215 (2**24 − 1) characters. longtext A TEXT column with a maximum length of 4,294,967,295 or 4GB (2**32 − 1) characters. enum 枚举类型, An ENUM column can have a maximum of 65,535 distinct elements. (The practical limit is less than 3000.) 示例: CREATE TABLE shirts ( name VARCHAR(40), size ENUM('x-small', 'small', 'medium', 'large', 'x-large') ); INSERT INTO shirts (name, size) VALUES ('dress shirt','large'), ('t-shirt','medium'),('polo shirt','small'); set 集合类型 A SET column can have a maximum of 64 distinct members. 示例: CREATE TABLE myset (col SET('a', 'b', 'c', 'd')); INSERT INTO myset (col) VALUES ('a,d'), ('d,a'), ('a,d,a'), ('a,d,d'), ('d,a,d'); DATE YYYY-MM-DD(1000-01-01/9999-12-31) TIME HH:MM:SS('-838:59:59'/'838:59:59') YEAR YYYY(1901/2155) DATETIME YYYY-MM-DD HH:MM:SS(1000-01-01 00:00:00/9999-12-31 23:59:59 Y) TIMESTAMP YYYYMMDD HHMMSS(1970-01-01 00:00:00/2037 年某时) ·更多参考 http://dev.mysql.com/doc/refman/5.7/en/data-type-overview.html http://www.runoob.com/mysql/mysql-data-types.html 五丶表内容操作 1丶增 insert into 表 (列名,列名...) values (值,值,值...) insert into 表 (列名,列名...) values (值,值,值...),(值,值,值...) insert into 表 (列名,列名...) select (列名,列名...) from 表 2丶删 delete from 表 delete from 表 where id=1 and name='alex' 3丶改 update 表 set name = 'alex' where id>1 4丶查 select * from 表 select * from 表 where id > 1 select nid,name,gender as gg from 表 where id > 1 5丶其他 a、条件 select * from 表 where id > 1 and name != 'alex' and num = 12; select * from 表 where id between 5 and 16; select * from 表 where id in (11,22,33) select * from 表 where id not in (11,22,33) select * from 表 where id in (select nid from 表) b、通配符 select * from 表 where name like 'ale%' - ale开头的所有(多个字符串) select * from 表 where name like 'ale_' - ale开头的所有(一个字符) c、限制 select * from 表 limit 5; - 前5行 select * from 表 limit 4,5; - 从第4行开始的5行 select * from 表 limit 5 offset 4 - 从第4行开始的5行 d、排序 select * from 表 order by 列 asc - 根据 “列” 从小到大排列 select * from 表 order by 列 desc - 根据 “列” 从大到小排列 select * from 表 order by 列1 desc,列2 asc - 根据 “列1” 从大到小排列,如果相同则按列2从小到大排序 e、分组 select num from 表 group by num select num,nid from 表 group by num,nid select num,nid from 表 where nid > 10 group by num,nid order nid desc select num,nid,count(*),sum(score),max(score),min(score) from 表 group by num,nid select num from 表 group by num having max(id) > 10 特别的:group by 必须在where之后,order by之前 f、连表 无对应关系则不显示 select A.num, A.name, B.name from A,B Where A.nid = B.nid 无对应关系则不显示 select A.num, A.name, B.name from A inner join B on A.nid = B.nid A表所有显示,如果B中无对应关系,则值为null select A.num, A.name, B.name from A left join B on A.nid = B.nid B表所有显示,如果B中无对应关系,则值为null select A.num, A.name, B.name from A right join B on A.nid = B.nid g、组合 组合,自动处理重合 select nickname from A union select name from B 组合,不处理重合 select nickname from A union all select name from B View Code
概述 对于web应用程序:用户浏览器发送请求.服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML),渲染并显示浏览器上· Ajax和Form表单提交数据的的好处有以下两种: Form表单提交数据的时候,呈现在页面上是刷新整个页面· Ajax提交数据的时候,只把有用的数据给提交过去,其余的不变· 1:传统的web应用 一个简单操作需要重新加载全局数据 2:AJAX ajax,Asynchronous JavaScript and XML(异步的JavaScript和XML),一种创建交互式网页应用的网页开发技术方案· · 异步的JavaScript: 使用[JavaScript语言]以及相关[浏览器提供类库]的功能向服务端发送请求,当服务端处理请求之后,[自动执行某个JavaSript的回调函数]· PS:以上请求和响应的整个过程是(偷偷)进行的,页面上无任何感知· ·XML XML是一种标记语言,是Ajax在和后台交互时传输数据的格式之一· 利用AJAX可以做: 1丶注册时,输入用户名自动检测用户是否已经存在· 2丶登录时,提示用户名密码错误· 3丶删除数据行时,将行ID发送到后台,后台在数据库中删除,数据库删除成功后,在页面DOM中将数据行业删除· "伪"AJAX <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div> <p>请输入要加载的地址:<span id="currentTime"></span></p> <p> <input id="url" type="text" /> <input type="button" value="刷新" onclick="LoadPage();"> </p> </div> <div> <h3>加载页面位置:</h3> <iframe id="iframePosition" style="width: 100%;height: 500px;"></iframe> </div> <script type="text/javascript"> //页面加载完成之后自动执行这个函数 window.onload= function(){ var myDate = new Date(); //创建一个时间对象 = 获取当前时间 document.getElementById('currentTime').innerText = myDate.getTime(); //把它的时间获取到 }; //LoadPage是由刷新触发的,一点刷新就执行LoadPage函数 function LoadPage(){ var targetUrl = document.getElementById('url').value; //输入什么值就获取都什么值 document.getElementById("iframePosition").src = targetUrl; //输入什么URL“iframePosition”标签的src就等于什么 } </script> </body> </html> 原生AJAX ajax主要就是使用[XmlHttpRequest]对象未完成请求的操作,该对象在主浏览器中均存在(除早期的IE),AJAX首次出现IE5.5存在(Active控件)· 1丶XmlHttpRequest对象介绍 xmlHttpRequest对象的主要方法: 1·void open(String metthod, String url, Boolen async) #用于创建请求 #参数: method:请求方式(字符串类型),如:POST,GET,DELETE... url:要请求的地址(字符串类型) async:是否异步(布尔类型) 2·viod send(String body) #用于发送请求 #参数 body:要发送的数据(字符串类型) 3·void setRequestHeader(String header,String value) #用于设置请求同 #参数: header:请求同的key(字符串类型) value:请求头的value(字符串的类型) 4· Strig getAllResponseHerders() #获取所有响应头 #返回值: 响应头数据(字符串类型) 5·String getResponseHeader(String header) #获取响应头中指定header的值 #参数: header:响应头的key(字符串类型) #返回值: 响应头中指定的header对应的值 6· void abort() #终止请求 XmlHttpRequest对象的主要属性 : (数字类型)1. Number readyState 状态值(整数) 详细: 0-未初始化,尚未调用open()方法; 1-启动,调用了open()方法,未调用send()方法; 2-发送,已经调用了send()方法,未接收到响应; 3-接收,已经接收到部分响应数据; 4-完成,已经接收到全部响应数据; 2. Function onreadystatechange 当readyState的值改变时自动触发执行其对应的函数(回调函数) 3. String responseText 服务器返回的数据(字符串类型) 4. XmlDocument responseXML 服务器返回的数据(Xml对象) 5. Number states 状态码(整数),如:200、404... 500(服务器错误) 404(没找到) 200系列的(都属正常) 6. String statesText 状态文本(字符串),如:OK、NotFound... 2丶跨浏览器支持 ·XmlHttpRequest IE7+,Firefox,Chrome,Opera,etc· ·ActiveXObject("Microsoft.XMLHTTP") IE6,IE5 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <h1>XMLHttpRequest - Ajax请求</h1> <input type="button" onclick="XmlGetRequest();" value="Get发送请求" /> <input type="button" onclick="XmlPostRequest();" value="Post发送请求" /> <script src="/statics/jquery-1.12.4.js"></script> <script type="text/javascript"> //创建xhr对象 function GetXHR(){ var xhr = null; //默认xhr = null if(XMLHttpRequest){ //如果(XMLHttpRequest)为真的话表示当前浏览器有这个东西 xhr = new XMLHttpRequest(); //通过 new创建一个对象 }else{ //否则的话 xhr = newActiveXobject("Miacosoft.XMLHttp"); //就用ActiveXobject这个插件用xhr去创建 } return xhr; //这样的话xhr就可以兼容这个浏览器了,兼容浏览器它给的返回值 } //就是一个可以发送那么一个ajax请求的的对象,拿到这个对象我们就可以发请求了 function XhrPostRequest(){ ver xhr = GetXHR(); //获取对象 //定义回调函数 xhr.obnreadystatechange = function(){ //执行成功之后的一个回调,这次请求执行成功了就会自动执行函数, //只是定义了,完成之后才会执行,没完成就不会执行这个函数 if(xhr.readyState == 4){ //readyStat == 4 表示已经接收完毕 //已经接收到全部响应数据,执行以下操作 var data = xhr.responseText; //返回的文本内容 console.log(data); //打印 } }; //指定连接方式和地址----文件夹 xhr.open("POST","/test/",true); //打开这个链接,以post方式发送URL:/test/ //设置请求头 xhr.setRequestHeade("Content-Type","application/x-www-form-urlencong="utf-8"); //发送请求 xhr.send(); //发送 } } </script> </body> </html> JQuery Ajax jQuery其实就是一个Javascript的类库,其将复杂的功能做了上层封装,使得开发者可以在基础上写更少的代码实现更多的功能· · jQuery不是生产者,而是大自然的搬运工· · jQuery Ajax本质 XML HttpRequest 或 ActiveXobject 注:2.+版本不再支持IE9以下的浏览器 $.get({ url:"地址", data:"{"k1":"v1"}", //传输的数据 dataType:"json", // 这样写的话就会在内部执行字符串转成字典 success:function(xx){ //执行成功之后,就会自动执行个xx obj = JSON.parse(xx) //把字符串转换成字典 } }) $.getjson() //写着一句,相当于dataType在内部设置成json了 $.getscript() //写着一句,相当于dataType在内部设置成script了 $.post({ url:"地址", data:"{"k1":"v1"}", //传输的数据 success:function(xx){ //执行成功之后,就会自动执行个xx } }) $.ajax({ url:"地址", type:"post", //表示要发post请求 ..... }) //本质上get和post都会调用ajax方法 jQuery.get(...) 所有参数: url:待载入页面的url地址 data:待发送 key、value参数 success:载入成功时回调函数 dataType:返回内容格式,xml,json,script,text,html jQuery.post(....) 所有参数: url:带载入页面的url地址 data:待发送 key/value 参数 success:载入成功时回调函数 dataType:返回内容格式,xml,json,script,text,html jQyery.getScript(....) 所有参数: url;待载入页面的url地址 data:待发送key/value参数 success:载入成功时回调函数 jQuery.ajax(....) 部分参数: url:请求地址 type:请求方式,GET丶POST(1.9.0之后用method) headers:请求头 data:要发送的数据 contentType:即将发送信息至服务器的内容编码类型 (默认:"application/x-www-form-urlencoded;charset = utf-8") async:是否 异步 timeout:设置请求超时时间(毫秒) bempletet:完成之后执行回调函数(全局) su发送请求前执行回调函数(全局) coccess:成功之后执行的回调函数(全局) error:失败之后执行的回调函数(全局) accepts:通过请求头发送给服务器,告诉服务器当前客户端可接受的数据类型 dataType:将服务器端返回的数据转换成指定类型 “xml”:将服务器端返回的内容转换成xml格式 “text”:将服务器端返回的内容转换成普通文本格式 “html”:将服务器端返回的内容换换成普通文本格式,在插入DOM中时,如果包含Jvascript标签,则会尝试去执行 “script”:尝试将返回值当做javascript去执行,然后再将服务器端返回的内容转换成普通文本格式 “json”:将服务器端返回的内容转换成相应的Javascript对象 ‘jsonp’:JSONP格式 使用 JSONP 形式调用函数时,如"myurl?callback = ?" jQuery 将自动替换 ? 为正确的函数名, 以执行回调函数 如果不指定,jQuery 将自动根据HTTP包MIME信息返回相应类型(an XML MIME type will yield XML, in 1.4 JSON will yield a JavaScript object, in 1.4 script will execute the script, and anything else will be returned as a string converters: 转换器,将服务器端的内容根据指定的dataType转换类型,并传值给success回调函数 $.ajax({ accepts: { mycustomtype: 'application/x-some-custom-type' }, // Expect a `mycustomtype` back from server dataType: 'mycustomtype' // Instructions for how to deserialize a `mycustomtype` converters: { 'text mycustomtype': function(result) { // Do Stuff return newresult; } }, }); <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="button" onclick="XmlSendRequest();" value='Ajax请求' /> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function JqSendRequest(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'GET', dataType: 'text', success: function(data, statusText, xmlHttpRequest){ console.log(data); } }) } </script> </body> </html> 跨域AJAX 由于浏览器存在同源策略机制,同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档属性· 特别的:由于同源策略是 浏览器的限制,所有请求的发送和响应是可以进行,只不过浏览器不接受罢了· 浏览器同源策略并不是对所有的请求均制约: ·制约:XMLHttpRequese ·不叼:img,iframe,script灯具有src属性的标签 跨域,跨域名访问,如:http://www.c1.com 域名向 http://www.c2.com域名发送请求。 1丶JSONP实现跨域请求 JSONP(JSONP - JSON with Padding是JSON的一种 “使用模式”),利用 script标签src属性(浏览 器允许script标签跨域) <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="button" onclick="Jsonp1();" value='提交'/> </p> <p> <input type="button" onclick="Jsonp2();" value='提交'/> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function Jsonp1(){ var tag = document.createElement('script'); tag.src = "http://c2.com:8000/test/"; document.head.appendChild(tag); document.head.removeChild(tag); } function Jsonp2(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'GET', dataType: 'JSONP', success: function(data, statusText, xmlHttpRequest){ console.log(data); } }) } </script> </body> </html> 2丶CORS 随着技术的发展,现在的浏览器可以支持主动设置从而允许跨域请求,既:跨域走远共享(CORS,Cross-Origin Resource Sharing),基本质是设置响应头,使得浏览器允许跨域请求· *简单请求OR非简单请求 条件: 1丶请求方式:HEAD,GET,POST 2丶请求头信息: Accept Accept - Language Content - Language Last - Event - ID Content - Type 对应的值是以下三个中的任意一个 application/x- www - form - urlencoded multipart/form - data text/plain 注意:同时满足以上两个条件时,则 是简单请求,否则为复杂请求 *简单请求和非简单请求的区别? 1·简单请求:一次请求 2·非简单请求:两次请求,在发送数据之前会会先发一次请求用于做“预检”,只有“预检”通过后才再发送一次请求用于数据传输· *关于“预检”* 请求方式:OPTIONS "预检":其实做检查,检查如果通过则允许传输数据,检查不通过则不再发送真正想要的发送的消息· 如何“预检”: 如果复杂请求是PUT等请求,则服务端需要设置允许某请求,否则“预检”不通过 Access-Control-Request-Method 如果复杂请求设置了请求头,则服务端需要设置允许某请求头,否则“预检”不通过 Access-Control-Request-Method 基于cors实现AJAX请求: 1丶支持跨域,简单请求 服务器设置响应头:Access-Control-Allow-Origin = “域名”或“*” <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="submit" onclick="XmlSendRequest();" /> </p> <p> <input type="submit" onclick="JqSendRequest();" /> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function XmlSendRequest(){ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4) { var result = xhr.responseText; console.log(result); } }; xhr.open('GET', "http://c2.com:8000/test/", true); xhr.send(); } function JqSendRequest(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'GET', dataType: 'text', success: function(data, statusText, xmlHttpRequest){ console.log(data); } }) } </script> </body> </html> HTML import tornado.web import tornado.ioloop class MainHandler(tornado.web.RequestHandler): def get(self): self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") self.write('{"status": true, "data": "seven"}') Tornado 2丶支持跨域,复杂请求 由于复杂请求时,首先会发送“预检”请求,如果‘预检’成功,则发送真实数据· ·‘预检’请求时,允许请求方则 需要服务器 设置响应头:Access-Control-Request-Method ·‘预检’请求时,允许请求头则需要服务器设置响应头;Access-Control-Request-Headers ·‘预检’缓存时间,服务器设置响应头:Access-Control-Max-Age <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="submit" onclick="XmlSendRequest();" /> </p> <p> <input type="submit" onclick="JqSendRequest();" /> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function XmlSendRequest(){ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4) { var result = xhr.responseText; console.log(result); } }; xhr.open('PUT', "http://c2.com:8000/test/", true); xhr.setRequestHeader('k1', 'v1'); xhr.send(); } function JqSendRequest(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'PUT', dataType: 'text', headers: {'k1': 'v1'}, success: function(data, statusText, xmlHttpRequest){ console.log(data); } }) } </script> </body> </html> import tornado.web import tornado.ioloop class MainHandler(tornado.web.RequestHandler): def put(self): self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") self.write('{"status": true, "data": "seven"}') def options(self, *args, **kwargs): self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") self.set_header('Access-Control-Allow-Headers', "k1,k2") self.set_header('Access-Control-Allow-Methods', "PUT,DELETE") self.set_header('Access-Control-Max-Age', 10) 3丶跨域获取响应头 默认获取到的所有响应头只有基本信息,如果想要获取自定义的响应头,则需要服务器端设置Access-Contorl-Expose-Headers <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="submit" onclick="XmlSendRequest();" /> </p> <p> <input type="submit" onclick="JqSendRequest();" /> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function XmlSendRequest(){ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4) { var result = xhr.responseText; console.log(result); // 获取响应头 console.log(xhr.getAllResponseHeaders()); } }; xhr.open('PUT', "http://c2.com:8000/test/", true); xhr.setRequestHeader('k1', 'v1'); xhr.send(); } function JqSendRequest(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'PUT', dataType: 'text', headers: {'k1': 'v1'}, success: function(data, statusText, xmlHttpRequest){ console.log(data); // 获取响应头 console.log(xmlHttpRequest.getAllResponseHeaders()); } }) } </script> </body> </html> HTML class MainHandler(tornado.web.RequestHandler): def put(self): self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") self.set_header('xxoo', "seven") self.set_header('bili', "daobidao") self.set_header('Access-Control-Expose-Headers', "xxoo,bili") self.write('{"status": true, "data": "seven"}') def options(self, *args, **kwargs): self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") self.set_header('Access-Control-Allow-Headers', "k1,k2") self.set_header('Access-Control-Allow-Methods', "PUT,DELETE") self.set_header('Access-Control-Max-Age', 10) Tornado 4·跨域传输cookie 在跨域请求中,默认情况下,HTTP Authentication信息,Cookie头以及用户的SSL证书无论在预检请求中或是在实际请求都是不会被发送· 如果想要发送: ·浏览器端:XMLHttpRequest的withCredentials为true ·服务器端:Access-Control-Allow-Credentials为true ·注意:服务器响应的Access-Control-Allow-Origin 不能是通配符 * <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <p> <input type="submit" onclick="XmlSendRequest();" /> </p> <p> <input type="submit" onclick="JqSendRequest();" /> </p> <script type="text/javascript" src="jquery-1.12.4.js"></script> <script> function XmlSendRequest(){ var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function(){ if(xhr.readyState == 4) { var result = xhr.responseText; console.log(result); } }; xhr.withCredentials = true; xhr.open('PUT', "http://c2.com:8000/test/", true); xhr.setRequestHeader('k1', 'v1'); xhr.send(); } function JqSendRequest(){ $.ajax({ url: "http://c2.com:8000/test/", type: 'PUT', dataType: 'text', headers: {'k1': 'v1'}, xhrFields:{withCredentials: true}, success: function(data, statusText, xmlHttpRequest){ console.log(data); } }) } </script> </body> </html> HTML import tornado.web import tornado.inloop class MainHandler(tornado.web.RequestHandler): def put(self): self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") self.set_header('Access-Control-Allow-Credentials', "true") self.set_header('xxoo', "seven") self.set_header('bili', "daobidao") self.set_header('Access-Control-Expose-Headers', "xxoo,bili") self.set_cookie('kkkkk', 'vvvvv'); self.write('{"status": true, "data": "seven"}') def options(self, *args, **kwargs): self.set_header('Access-Control-Allow-Origin', "http://www.xxx.com") self.set_header('Access-Control-Allow-Headers', "k1,k2") self.set_header('Access-Control-Allow-Methods', "PUT,DELETE") self.set_header('Access-Control-Max-Age', 10) Tornado
jQuery就是一个js的库· 主要分为两部分: 1·寻找元素 (选择器,筛选器) 2·操作元素 (CSS的操作,属性的操作,文本的处理) 选择器 基本 #id #id //用于搜索的,通过元素的id属性中给定的值 描述:(查找ID为myDiv的元素) HTML代码: <div id="notMe"><p>id = "notMe"</p></div> <div id="myDiv">id="myDiv"</div> jQuery代码: $("#myDiv"); 结果: [<div id="myDiv">id="myDiv"</div>] element element //一个用于搜索的元素·指向DOM节点的标签名 描述:查找一个DIV元素· 实列: HTML代码: <div>DIV1</div> <div>DIV2</div> <div>SPAN</div> jQuery代码: $("div"); 结果: [<div>DIV1</div>,<div>DIV2</div>] .class .class //一个用于搜索的类,一个元素可以有多个类,只要有一个符合就能被匹配到· 描述: 查找所有类是“maClass”的元素 实列: HTML代码: <div class = "notMe">div class="notMe"</div> <div class="myClass">div class = "myClass"</div> <span class="myClass">span class="myClass"</span> jQuery代码: $(".myClass"); 结果: [<div class="myClass">div class="myClass"</div>] [<span class="myClass">span class="myClass"</span>] (*)匹配所有元素 HTML代码: <div>DIV</div> <span>SPAN</span> <p>P</p> jQuery代码: $("*") 结果: [<div>DIV</div>] [<span>SPAN<span>] [<p>P<p>] selector1,selector2,selectorN //概述 //将每一个选择器匹配到的元素合并后一起返回· //你可以指定任意多个选择器,并将匹配到的元素合并到一个结果内· selector1 //一个有效的选择器 selector2 //另一个有效的选择器 selectorN //任意多个有效的选择器 //描述 //找到匹配任意一个类的元素 HTML代码: <div>div</div> <p class="maClass">p class="myClass"</p> <span>span</span> <p class="notMyClass">p class="notMyClass"</p> jQuery代码: $("div,span,p.myClass") 结果: [<div>div</div>,<p class="myClass">p class="myClass"</p>,<span>span</span>] 层级 ancestor descendant //概述 //在给定的祖先元素下匹配所有的后代元素 ancestor //任何一个有效选择器 descendant //用以匹配元素的选择器,并且它是第一个选择器的后代元素 //描述 //找到表单中所有的(input)标签 HTML代码 <form> <label>Name:</label> <input name="name"> <fieldset> <label>Newsletter:</label> <input name="newsletter"/> </fieldset> </form> <input name="none"> jQuery代码 $("form input") 结果 [<input name="name"/>,<input name="newsletter"/>] parent > child //概述 //在给定的父元素下匹配所有的子元素 parent //任何有效选择器 child //用以匹配元素的选择器,并且它是第一个选择的子元素· //描述 匹配表单中所有的自己input元素 HTML代码 <form> <label>Name:</label> <input name="name"/> <fieldset> <label>Newsletter:</label> <input name="newsletter"/> </fieldset> </form> <input name="none"/> jQuery代码 $("form > input") 结果 [<input name="name"/>] prev + next //概述 //匹配所有紧接在prev元素后的next元素 prev //任何有效选择器 next //一个有效选择器并且紧接着第一个选择器 //描述 //匹配所有跟在label后面的input元素 HTML代码 <form> <label>Name:</label> <input name="name"/> <fieldset> <label>Newsletter:</label> <input name="newsletter"/> </fieldset> </form> <input name="none"/> prev ~siblings //概述 //匹配prev元素之后的所有siblings元素 prev //任何有效选择器 siblings //一个选择器,并且它作为第一个选择器的同辈 //描述 //找到所有与表单同辈的(inout)元素 HTML代码 <form> <label>Name:</label> <input name="name"/> <fieldset> <label>Newsletter:</label> <input name="newsletter"/> </fieldset> </form> <input nme="none"/> 基本筛选器 基本筛选器一定要注意前边的冒号(:) :first //获取第一个元素 //描述 //获取第一个元素 实列: HTML代码 <ul> <li>list item 1</li> <li>list item 2</li> <li>list item 3</li> <li>list item 4</li> <li>list item 5</li> </ul> jQuery代码 $("li:first"): 结果 [<li>list item 1</li>] :not(selector) //概述 //去除所有与给定时器匹配的元素 //在jQuery1.3中.已经支持复杂选择器了(列如:not(div a)和:not(div,a)) selector //用于筛选的选择器 //描述 //查找所有未选中的inout元素 HTML代码 <input name="apple"/> <input name="fllower" checked="checked"/> jQuery代码 $("input:not(:checked)"/) 结果 [<input name="apple"/>] :even //概述 //匹配所有索引值为偶数的元素,从零开始 //描述 //查找表格的1,3,5...行(既索引值0,2,4...) HTML代码 <table> <tr><td>Header 1</td></tr> <tr><td>Value 1</td></tr> <tr><td>Value 2</td></tr> </table> jQuery代码 $("tr:even") 结果 [<tr><td>Header 1</td></tr>,<tr><td>Value 2</td></tr>] :odd //概述 //匹配所有索引值为基数的元素,从零开始计数 //描述 //查找表格的2,4,6行(既索引值1,3,5....) HTML代码 <table> <tr><td>Header 1</td></tr> <tr><td>Value 1</td></tr> <tr><td>Value 2</td></tr> </table> jQuery代码 $("tr:odd") 结果 [<tr><td>Value 1</td></tr>] :eq(index) //概述 //匹配一个给定的索引值的元素 index //从零开始计数 描述 查找第二行 HTML代码 <table> <tr><td>Header 1</td></tr> <tr><td>Value 1</tr></td> <tr><td>Value 2</tr></td> </table> jQuery代码 $("tr:eq(1)") 结果 [<tr><td>Value 1</tr></td>] :gt(index) //概述 //匹配所有大于给定索引值得元素 index //从零开始计数 描述 查找第二行第三行,既索引值是1和2,也就是比零打 HTML代码 <table> <tr><td>Header 1</tr></td> <tr><td>Value 1</tr></td> <tr><td>Value 2</tr></td> </table> jQuery代码 $("tr:gt(0)") 结果 [<tr><td>Value 1</td></tr>,<tr><td>Value 2 </td></tr>] :last() //概述 //获取最后一个元素 描述 获取匹配的最后一个元素 HTML代码 <ul> <li>list item 1</li> <li>list item 2</li> <li>list item 3</li> <li>list item 4</li> <li>list item 5</li> </ul> jQuery代码 $("li:last") 结果 [<li>list item 5</li>] :lt(index) //概述 //匹配所有小于给定索引值得元素 index 从零开始计数 描述 查找第一行第二行,既索引值是零和1,也就是比2小· HTML代码 <table> <tr><td>Header 1</tr></td> <tr><td>Value 1</tr></td> <tr><td>Value 2</tr></td> </table> jQuery代码 $("tr:lt(2)") 结果 [<tr><td>Header 1</tr></td>,<tr><td>Value 1</tr></td>] :header //概述 //匹配如:h1,h2,h3之类的标题元素 描述 给页面内所有标题加上背景颜色 HTML代码 <h1>Header 1</h1> <p>Contents 1</p> <h2>Header 2</h2> <p>Contents 2</p> jQuery代码 $(":header".css("background","#dddddd")); 结果 [<h1 style="background:#dddddd;">Header 1</h1>,<h2 style="background:#dddddd;">Header 2</h2>] 内容 :constains(text) //概述 //匹配包含给定文本的元素 text //一个用以查找的字符串 描述 查找所有包含"John"的div元素 HTML代码 <div>John Resig</div> <div>George Martin</div> <div>Malcom John Sinclair</div> jQuery代码 $("div:contains("John")") 结果 [<div>John Resig</div>,<div>Malcom John Sinclair</div>] :empty //概述 //匹配所有不包含子元素或者文本的空元素 描述 查找所有不包含子元素或者文本的空元素 HTML代码 <table> <tr><td>Value 1</td><td></td></tr> <tr><td>Value 2</td><td></td></tr> </table> jquery代码 $("td:empty") 结果 [<td></td>,<td></td>] :has(selector) //概述 //匹配含有选择器所匹配的元素的元素 selector 一个用于筛选的选择器 描述 给所有包含P元素的div元素添加一个text类 HTML代码 <div><p>Hello</p></div> <div>Hello Wyc</div> jQuery代码 $("div:has(p)").addClass("text"); 结果 [<div class="text"><p>Hello</p></div>] :parent //概述 //匹配含有子元素或者文本的元素 描述 查找所有包含有子元素或者文本的td元素 HTML代码 <teble> <tr><td>Value 1</td><td></td></tr> <tr><td>Value 2</td><td></td></tr> </table> jQuery代码 $("td:parent") 结果 [<td>Value 1</td>,<td>Value 2 </td>] :hidden //概述 //匹配所有不课件元素,或者type为hidden的元素 描述 查找隐藏的tr HTML代码 <table> <tr style="display:none"><td>Value 1</td></tr> <tr><td>Value 2</td></tr> </table> jQuery代码 $("tr:hidden") 结果 [<tr style="display:none"><td>Value 1</td></tr>] :visible //概述 //匹配所有可见的元素 描述 查找所有可见的tr元素 HTML代码 <table> <tr style="display:none"><td>Value 1</td></tr> <tr><td>Value 2</td></tr> </table> jQuery代码 $("tr:visible") 结果 [<tr><td>Value 2</td></tr>] 属性 attribute //概述 //匹配包含给定属性的元素·注意,在jQuery1.3中,前导的@符号已经被废除!如果想要兼容版本,只需要简单的去掉@符号即可· attribute 属性名 描述 查找所有含有id属性的div元素 HTML代码 <div> <p>Hello</P> </div> <div id="test2"></div> jQuery代码 $("div[id]") 结果 [<div id="test2"></div>] [attribute=value] //概述 //匹配给定的属性是某个特定值得元素 attribute 属性名 value 属性值,引导在大多数情况下是可选的·单在遇到诸如属性质包含"]"时,用以避免冲突· 描述 查找所有name属性是newsletter的inout元素 HTML代码 <input type="checkbox" name="newsletter" value="Hot Fuzz"/> <input type="checkbox" name="newsletter" value="Cold Fusion"/> <input type="checkbox" name="accept" value="Evil Plans"/> jQuery代码 $("input[name="newsletter"]").attr("checked",true); 结果 [<input type="checkbox" name="newsletter" value="Hot Fuzz" checkbox="true"/>,<input type="checkbox" name="nwesletter" value="Cold Fusion" check="true"/>] [attribute!=value] //概述 //匹配所有不含有指定的属性,或者属性不等于特定的值· //次选择器等价于:not([attr=value])要匹配含有特定属性但不等于特定值的元素,请使用[attr]:not([attr=value]) attribute 属性名 value 属性值·引导在大多数情况下是可选的·但在遇到诸如属性值包含"]"时,用以避免冲突· 描述 查找所有name属性不是newsletter的input元素 HTML代码 <input type="checkbox" name="newsletter" value="Hot Fuzz"/> <input type="checkbox" name="newsletter" value="Cold Fusion"/> <input type="checkbox" name="accept" value="Evil Plans"/> jQuery代码 $("input[name!="newsletter"]").attr("checkd",true);结果[<input type="checkbox" name="accept" value="Evil Plans" checked="true"/>] [attribute^=value] //概述 //匹配给定的属性是以某些值开始的元素 attribute 属性名 value 属性值·引导在大多数情况下是可选的·但在遇到诸如属性值包含"]"时,用以避免冲突· 描述 查找所有name以"news"开始的input元素 HTML代码 <input name="newsletter"/> <input name="milkman"/> <input name="newsboy"/> jQuery代码 $("input[name^="news"]") 结果 [<input name="newsletter"/>,<input name="newsboy"/>] [attribute$=value] //概述 //匹配给定的属性是以某些值结尾的元素 attribute 属性名 value 属性值·引导在大多数情况下是可选的·但在遇到诸入属性值包含"]"时,用以避免冲突· 描述 查找所有name以"letter"结尾的input元素 HTML代码 <input name="newsletter"/> <input name="milkman"/> <input name="jobletter"/> jQuery代码 $("input[name$="letter"]") 结果 [<input name="newsletter"/>,<input name="jobletter"/>] [attributee*=value] //概述 //匹配给定的属性是 包含某些值得元素 attribute 属性名 value 属性值·引导在大多数情况下是可选的·但在遇到诸入属性值包含"]"时,用以避免冲突· 描述 查找所有name包含"man"的input元素 HTML代码 <input name="man-news"/> <input name="milkman"/> <input name="letterman2"/> <input name="newmilk"/> jQuery代码 $("input[name*="man"]") 结果 [<inout name="man-news"/>,<input name="milkman"/>,<inout name="letterman2">] [selector1][selector2][selectorN] //概述 复合属性选择器,需要同时满足多个条件时使用· selector1 属性选择器 selector2 另一个属性选择器,用以进一步缩小范围 selectorN 任意多个属性选择器 描述 找到所有含有id属性,并且它的name属性是以man结尾的 HTML代码 <input id="man-news" name="man-news"/> <input name="milkman"/> <input id="letterman" name="new-letterman"/> <input name="newmilk"/> jQuery代码 $("input[id][name$="man"]") 结果 [<input id="letterman" name="new-letterman"/>] 子元素 :first-child //概述 匹配第一个子元素 类似的(:first)匹配第一个元素,而次选择符将为 每个父元素匹配一个子元素· 描述 在每一个ul中查找第一个li HTML代码 <ul> <li>John</li> <li>Karl</li> <li>Brandon</li> </ul> <ul> <li>Glen</li> <li>Tane</li> <li>Ralph</li> </ul> jQuery代码 $("ul li:first-child") 结果 [<li>John</li>,<li>Glen</li>] :last-child //概述 //匹配最后一个子元素 :last只匹配最后一个元素,而次选择符将为每一个父元素匹配到最后一个子元素· //描述 //在每个ul中查找最后一个li HTML代码 <ul> <li>11111</li> <li>22222</li> <li>33333</li> </ul> <ul> <li>44444</li> <li>55555</li> <li>66666</li> </ul> jQuery代码 $("ul li:last-child") 结果 [<li>33333</li>,<li>66666</li>] :nth-child //概述 //匹配其父元素下的第N个子或奇偶元素 :eq(index)匹配选择器指定序列的元素,而这个将为每一个元素匹配子元素· :nth-child从1开始的,而:eq()是从0开始的!可以使用:<br>nth-child(even)<br>:nth-child(odd)<br>:nth-child(3n)<br>:nth-child(2)<br>:nth-child(3n+1)<br>:nth-child(3n+2) index 要匹配元素的序号,从1开始 描述 在每个ul查找第2个li HTML代码 <ul> <li>11111</li> <li>22222</li> <li>33333</li> </ul> <ul> <li>44444</li> <li>55555</li> <li>66666</li> </ul> jQuery代码 $("ul li:nth-child(2)") 结果 [<li>22222</li>,<li>55555</li>] :only-child //概述 //如果某个是父元素中唯一的子元素,那将会被匹配· //如果父元素中含有其他元素,那将 不会被匹配·(注:这里的其它元素并不包含文本节点,如:<p><img/>网页</p>,用$('p img:only-child')是可以匹配) 描述 在ul中查找唯一子元素的li HTML代码 <ul> <li>11111</li> <li>22222</li> <li>33333</li> </ul> <ul> <li>44444</li> </ul> jQuery代码 $("ul li:only-child") 结果 [<li>44444</li>] 表单 input //概述 //匹配所有的input,textarea,select和button元素 描述 查找所有的input元素,下面这些元素都会被匹配 HTML代码 <form> <input type="button" value="Input Button"/> <input typee="checkbox"/> <input type="file"/> <input type="hidden"/> <input type="image"/> <input type="password"/> <input type="radio"/> <input type="reset"/> <input type="submit"/> <input type="text"/> <select><option>Option</option></select> <textarea></textarea> <button>Buttob</button> </form> jQuery代码 $(":input") 结果 [ <input type="button" value="Input Button"/>, <input type="checkbox" />, <input type="file" />, <input type="hidden" />, <input type="image" />, <input type="password" />, <input type="radio" />, <input type="reset" />, <input type="submit" />, <input type="text" />, <select><option>Option</option></select>, <textarea></textarea>, <button>Button</button>, ] :text //概述 //匹配所有单行文本框 描述 查找所有文本框 HTML代码 <form> <input type="text"/> <input type="checkbox"> <input type="radio"/> <input type="image"/> <input type="file"/> <input type="submit"/> <input type="reset"/> <input type="password"/> <input type="button"/> <select></select> <textarea></textarea> <button></button> </form> jQuery代码 $(":text") 结果 [<input type="text"/>] :password //概述 //匹配所有的密码框 描述 查找所有密码框 HTML代码 <form> <input type="text"/> <input type="checkbox"/> <input type="radio"/> <input type="image"/> <input type="file"/> <input type="submit"/> <input type="reset"/> <input type="password"> <inpur type="button"/> <select></select> <textarea></textarea> <button></button> </form> jQuery代码 $(":password") 结果 [<input type="password"/>] :radio //概述 //匹配所有单选按钮 描述 查找所有单选按钮 HTML代码 <form> <input type="text" /> <input type="checkbox" /> <input type="radio" /> <input type="image" /> <input type="file" /> <input type="submit" /> <input type="reset" /> <input type="password" /> <input type="button" /> <select><option/></select> <textarea></textarea> <button></button> </form> jQuery代码 $(":radio") 结果 [<input type=radion"/>] :checkbox //概述 //匹配所有复选框 描述 查找所有复选框 HTML代码 <form> <input type="text" /> <input type="checkbox" /> <input type="radio" /> <input type="image" /> <input type="file" /> <input type="submit" /> <input type="reset" /> <input type="password" /> <input type="button" /> <select><option/></select> <textarea></textarea> <button></button> </form> jQuery代码 $(":checkbox") 结果 [<input type="checkbox"/>] :submit //概述 //匹配所有提交按钮 描述 查找所有提交按钮 HTML代码 <form> <input type="text" /> <input type="checkbox" /> <input type="radio" /> <input type="image" /> <input type="file" /> <input type="submit" /> <input type="reset" /> <input type="password" /> <input type="button" /> <select><option/></select> <textarea></textarea> <button></button> </form> jQeury代码 $(":submit"/) 结果 [<input type="submit"/>] :image //概述 //匹配所有图像域 描述 匹配所有图像域 HTML代码 <form> <input type="text" /> <input type="checkbox" /> <input type="radio" /> <input type="image" /> <input type="file" /> <input type="submit" /> <input type="reset" /> <input type="password" /> <input type="button" /> <select><option/></select> <textarea></textarea> <button></button> </form> jQuery代码 $(":image") 结果 [<input type="image"/>] :reset //概述 //匹配所有的重置按钮 描述 查找所有的重置按钮 HTML代码 <form> <input type="text" /> <input type="checkbox" /> <input type="radio" /> <input type="image" /> <input type="file" /> <input type="submit" /> <input type="reset" /> <input type="password" /> <input type="button" /> <select><option/></select> <textarea></textarea> <button></button> </form> jQuery代码 $(":reset") 结果 [<input type="seret"/>] :button //概述 //匹配所有按钮 描述 查找所有按钮 HTML代码 <form> <input type="text" /> <input type="checkbox" /> <input type="radio" /> <input type="image" /> <input type="file" /> <input type="submit" /> <input type="reset" /> <input type="password" /> <input type="button" /> <select><option/></select> <textarea></textarea> <button></button> </form> jQuery代码 $(":button") 结果 [<input type="button">,<button></button>] :file //概述 //匹配所有文件域 描述 查找所有文件域 HTML代码 <form> <input type="text" /> <input type="checkbox" /> <input type="radio" /> <input type="image" /> <input type="file" /> <input type="submit" /> <input type="reset" /> <input type="password" /> <input type="button" /> <select><option/></select> <textarea></textarea> <button></button> </form> jQuery代码 $(":file") [<input type=":file"/>] 表单对象属性 :enabld //概述 //匹配所有可用元素 描述 查找所有可用的input元素 HTML代码 <form> <input name="email" disabled="disabled"/> <input name="id"/> </form> jQuery代码 $("input:emabled") 结果 [<input name="id"/>] :disabled //概述 //匹配所有不可用元素 描述 查找所有不可用的input元素 HTML代码 <form> <input name="email" disabled="disabled"/> <input name="id"/> </form> jQuery代码 $("input;disabled') 结果 [<input name="email" disabled="disabled"/>] :checked //概述 //匹配所有选中的被选中元素(复选框,单选框等,select中的option),对于select元素来说,获取选中推荐使用:selected 描述 查找说有选中的复选框元素 HTML代码 <form> <input type="checkbox" name="newsletter" checked="checked" value="Daily" /> <input type="checkbox" name="newsletter" value="Weekly" /> <input type="checkbox" name="newsletter" checked="checked" value="Monthly" /> </form> jQuery代码 $("input:checked") 结果 [<input type="checkbox" name="newsletter" checked="checked" value="Daily" />, <input type="checkbox" name="newsletter" checked="checked" value="Monthly" />] :selected //概述 //匹配所有选中的option元素 描述 查找所有选种的选项元素 HTML代码 <select> <option value="1">Flowers</option> <option value="2" selected="selected">Gardens</option> <option value="3">Trees</option> </select> jQuery代码 $("select option:selected") 结果 [<option value="2" selected="selected">Gaedens</option>] 属性 attr(name|porperties|key,value|fn) //概述 //设置或返回被选元素的属性值· name 属性名称 properties 作为属性的"名/值对"对象 key,value 属性名称,属性值 key,function(index,attr) 1·属性名称 2·返回属性值得函数,第一个参数为当前元素的索引值,第二个参数为原先的属性值· name描述: 返回文本中所有图像的src属性值· jQuery代码 $("img").attr("src") properties描述: 为所有图像设置src和alt属性· jQuery代码 $("img").attr({src:"test.jpg",alt:"Test Image"}); key,value描述: 为所有图像设置 src属性· jQuery代码 $("img").attr("src","test.jpg"); 参数key,回调函数描述: 把src属性的值设置为title属性的值· jQuery代码 $("img").attr("title",function(){return this.src}); removeAttr //概述 //从没一个匹配的元素中删除一个属性 1.6以下版本在IE6使用jQuery的removeAttr方法删除disabled是无效的· 1.7版本在IE6下已支持删除disabled· name 要删除的属性名 描述 将文本中图像的src属性删除 HTML代码 <img src="test.jpg"/> jQuery代码: $("img").removeAttr("src") 结果 [<img/>] prop //概述 //获取在匹配的元素集合中的第一个元素的属性值 //随着一些内置属性的DOM元素或window对象,如果试图将删除该属性,浏览器可能会产生错误,jQuery第一次分配undefined值的属性,而忽略了浏览器生成的任何错误· name 属性名称 properties 作为属性的"名、值对"对象 key,value 1·属性名称 2·返回属性值的函数·第一个参数为当前元素的索引值·第二个参数为原先的属性值· 参数name描述 选中复选框为,true没选中为false jQuery代码 $("input[type="checkbox"]").porp("checkbox"); 参数properties描述 禁用页面上的所有复选框 jQuery代码 $("input[type="checkbox"]").prop({ disabled: true }) 参数key,value描述 禁用和选项中所有页面上的复选框· jQuery代码 $("input[type="checkbox"]").prop("disabled",false) $("input[type="checkbox"]").prop("disacled",true) 参数key,回调函数描述: 通过函数来设置所有页面上的复选框被选中· jQuery代码 $("input[type="checkbox"]").prop("checked",function(i,val){ return !val }) removeProp(name) //概述 //用来删除由.prop()方法设置的属性集 //随着一写内置属性的DOM元素或window对象,如果试图将删除该属性,浏览器可能会产生错误.jQuery第一次分配undefined值得属性,而忽略了浏览器生成的任何错误· propertyName 要删除的属性名 描述 设置一个段落数字属性,然后将其删除· HTML代码 <p></p> jQuery代码 var $para=$("p"): $para.prop("luggageCode",1234): $para.append("The secret luggage code is:",String($parp.prop(luggageCode)),"."); $para.removeProp("luggageCode"); $para.append("Now the secret luggge code is:",String($para.prop("luggageCode")),".") 结果 The secret luggage code is: 1234. Now ths secret luggage code is: undefind. addClass(class|fn) //概述 //为每个匹配的元素添加指定的类名· class 一个或多个要添加到元素中的CSS类名,请用空格分开· function(index,class) 此函数返回一个或多个空格的class名.接受两个参数,index参数为对象在这个集合中索引值,class参数为这个对象原先的class属性值· 参数class描述 为匹配的元素加上"selected"类 jQuery代码 $("p").addClass("selected"); $("p").addClass("selected1 selected2"); 回调函数 描述: 给li加上不同的class HTML代码 <ul> <li>Hello</li> <li>Hello</li> <li>Hello</li> </ul> jQuery代码 //概述 //从所有匹配的元素中删除全部或者指定的类· class 一个或多个要删除的CSS类名,请用空格分开 function(index,class) 此函数必须返回一个或多个空格分隔的class名,接受两个参数,index参数为对象在这个集合的索引值,class参数为这个对象原先的class属性值. 参数class描述 删除匹配元素的所有类 jQuery代码 $("p").removeClass(); 回调函数描述: 删除最后一个元素上与前面重复的class jQuery代码 $("li:last").removeClass(function(){ return $(this).prev().attr("class"); }) $("ul li:last").addClass(function(){ return "item-" +$(this).index(): }): removeClass([class|fn]) //概述 //从所有匹配的元素中删除全部或者指定的类· class 一个或多个要删除的CSS类名,请用空格分开· function(index,class) 次函数必须返回一个或多个空格分隔的class名.接受两个参数,index参数为对在这个集合中的索引值,class参数为这个对象原先的class属性值· 参数class描述 从匹配的元素中删除"selected"类 jQuery代码 $("p").removeClass("selected"); 参数class描述 删除匹配元素的所有类 jQuery代码 $("p").removeClass(); 回调函数的描述 删除最后一个元素上与前面重复的class jQuery代码 $("li:last").removeClass(function(){ return $(this).prev().qttr("class"); }) toggleClass(class|fn[,sw]) //概述 //如果存在(不存在)就删除(添加)一个类· class CSS类名 class,switch 1·要切换的CSS类名 2·用于决定元素是否包含class的布尔值 switch 用于决定元素是否包含class的布尔值· function(index,class,wsitch)[,switch] 1·用来返回在匹配的元素集合中的每一个元素上用来切换的样式类名的一个函数·接收元素的索引位置和元素旧的样式类作为参数· 2·一个用来判断样式类添加还是移除的boolean值· 参数class描述 每点击三峡加上一个"highlight"类 HTML代码 <strong>jQuery代码</strong> jQuery代码 var count=0: $("p").click(function(){ $(this).toggleClass("highlight", count++ % 3 == 0); })l; 回调函数描述 根据父元素来设置class属性 jQuery代码 $("div.foo").toggleClass(function(){ if ($(tis).parent().is(".bar"){ return "happy"; }else{ return "sad"; } }); HTML代码/文本值 html([val|fn]) //概述 //取得第一个匹配元素的html内容·和个函数 不能用XML文档·但可以用于XHTML文档· //在一个HTML文档中,我们可以使用.html()方法来获取任意一个元素的内容·如果选择匹配多余一个的元素,那么只有第一个匹配元素的HTML内容会被获取· val 用于设定HTML内容的值 function(index,html) 此函数返回一个HTML字符串·接受两个参数,index为元素在集合 中的索引位置,html为原先的HTML值· 无参数的描述 返回p元素的内容 jQuery代码 $("p").html(); 参数val描述 设置所有p元素的内容 jQuery代码 $("p").html("Hello<b>world</b>!"); 回调函数描述 使用函数来设置所有匹配元素的内容 jQuery代码 $("p").html(function(n){ return "这个p元素的 index是:" +n; }) text([val|fn]) //概述 //取得所有匹配元素的内容 //结果是由所有匹配元素包含的文本内容组合起来的文本·这个方法对HTML文档对有效· val 用于设置元素内容的文本 function(index,text) 此函数返回一个字符串·接受两个参数,index为元素在集合中的索引位置,text为原先的text值· 无参数描述 设置所有p元素的文本内容 jQuery代码 $("p").text("Hello world"); 回调函数描述 使用函数来设置所有匹配元素的文本内容 jQuery代码 $("p").text(function(n){ return "这个p元素的index是:"+n; }) val([val|fn|arr]) //概述 //获得匹配元素的当前值 //jQuery 1.2中,可以 返回任意的值了.包括select.如果多选,将返回一个数组,其包含所选的值· val 要设置的值 function(index,value) 此函数返回一个要设置的值.接受两个参数,index为元素在集合中的索引位置,text为原先的text值· attay 用于 check/select的值 无参数描述 获取文本框的值 jQuery代码 $("input").val(); 参数val描述: 设定文本框的值 jQuery代码 $("input").val("hello world"); 回调函数描述 设定文本框的值 jQuery代码 $(input : text.items").val(funcction(){ return this.value + " " + this.className; }); 参数array描述 设定一个select和一 个多选的slect的值 HTML代码 <select id="single"> <option>Single</option> <option>Single2</option> </select> <select id="multiple" multiple="multiple"> <option selected="selected">Multiple</option> <option>Multiple2</option> <option selected="selected">Multiple3</option> </select><br/> <input type="checkbox" value="check1"/> check1 <input type="checkbox" value="check2"/> check2 <input type="radio" value="radio1"/> radio1 <input type="radio" value="radio2"/> radio2 jQuery代码 $("#single").val("Single2"); $("#multiple").val(["Multiple2", "Multiple3"]); $("input").val(["check2", "radio1"]); 筛选 过滤 eq //概述 //获取当前链式操作中第N个jQuery对象,返回jQuery对象,当参数大于等于0时为正向选取,比如0代表第一个,1代表第二个,当参数为负数时为反向选取·比如-1为倒数第一个,具体可以看一下实列 类似的有get(index),不过get(index)返回的是DOM对象· index //一个整数,指示元素基于0的位置,这个元素的位置是从0算起· -index //一个整数,指示元素的位置,从集合中的最后一个元素开始倒数·(-1算起) 实列 参数index描述 //获取匹配的第二个元素 HTML代码 <p> This is just a test.</p><p> So is this</p> Jquery代码 $("p").eq(1) 结果 [<p>This is just a test.</>] first //概述 //获取第一个元素 实列 //描述 //获取匹配的第一个元素 HTML代码 <ul> <li>list item1</li> <li>list item2</li> <li>list item3</li> </ul> jQuery代码 $('li').first() 结果 [<li>list item1</li>] last //概述 //获取最后一个元素 实列 //描述 // 获取匹配的最后一个元素 HTML代码 <ul> <li>list item1</li> <li>list item2</li> <li>list item3</li> </ul> jQuery代码 $("li").last() 结果 [<li>list item3</li>] has //概述 //检查当前的元素是否含有某个特定的类,如果有,则返回true· /这就是is("."+class). class 用于匹配的类名 实列 //描述 //给包含有某个类的元素进行一个动画. HTML代码 <div class="protected"></div><div></div> jQuery代码 $("div").click(functipn(){ if($(this).hasClass("protected")) $(this) .animate({left:-10}) .animate({left: 10}) .animate({left: -10}) .animate({left: 10}) .animate({left: 0}) }) filter(expr|obj|ele|fn) //概述 //筛选出与指定表达式匹配的元素集合· //和个方法用于缩小匹配的范围·用逗号分隔多个表达式· expr //字符串值·包含供匹配当前元素集合的选择器表达式· jQuery objext //现有的jQuery对象·以匹配当前的元素· element //一个用于匹配元素的DOM元素 function(index) //一个函数用来作为测试缘故的集合·它结束一个参数index·这是缘故在jQuery集合的索引·在函数,this指的是 当前的DOM元素· 实列 //参数selector描述 保留带有select类的元素 HTML代码 <p>Hello</p> <p>Hello Wyc</p> <p class="selected">Nihao</d> jQuery代码 $("p").filter(".selected") 结果 [<p class="selelcted">Nihao</p>]
javascript的作用域一直以来是前端开发中比较难理解的知识点,对于javascript的作用域主要记住几句话. 一丶"javascript中无块级作用域" 在java或C#中存在块级作用域,既:大括号也是一个作用域. public static void main () { if(1==1){ String name = "seven"; } System.out.println(name); } // 报错 java public static void Main() { if(1==1){ string name = "seven"; } Console.WriteLine(name); } // 报错 C# 在javascript语言中无块级作用域 function Main(){ if(1==1){ var name = 'seven'; } console.log(name); } // 输出: seven 补充;标题值所以添加双引号是应为javascript6中新引入了let关键字,用于指定变量属于块级作用域· 二丶javascript采用函数作用域 在javascript中每个函数作为一个作用域,在外部无法访问内部作用域中的变量· function Main(){ var innerValue = "server"; } Main(); console.log(innerValue); //报错;Uncaught ReferenceError: innerValue is not defined 三丶javascript的作用域链 由于javascript中的每一个函数作为一个作用域,如果出现函数嵌套函数,则就会出现作用域链· xo = "Wyc; function Func(){ var xo = "nihao"; function inner(){ var xo = "shijie"; console.log(xo); } inner(); } Func(); 如上述代码则出现三个作用域组成的作用域链,如果出现作用域链后,那么寻找变量时就会出现顺序,对于上述实列: 当执行console.log(xo)时,其寻找顺序为根据作用域链从内到外的优先级寻找,如果内层没有就逐步向上寻找,知道没找到抛出异常· 四丶javascript的作用域链 执行前已经创建 javascript的作用域在被执行之前已经创建,日前再去执行时只需要按照作用域链去寻找即可· 实列一: xo = "wyc"; function Func(){ var xo = "nihao"; function inner(){ console.log(xo); } return inner; } var ret = Func(); ret(); //输出结果 ; "nihao" 上述代码,在函数呗调用之前作用域链已经存在; · 全局作用域 --》 Func函数作用域 --》inner函数作用域 当执行[ret()]时,由于其代指的是inner函数,此函数的作用域链执行之前已经被定义为;全局作用域 --》Func函数作用域 --》inner'函数作用域,所以,在执行[ret();]时,会根据已经存在的作用链去寻找变量· 实列二: xo = "Wyc"; function Func(){ var xo = "nihao"; function inner(){ console.log(xo); } xo = "shijie"; return inner; } var ret = Func(); ret(); //输出结果: "shijie" 上述代码和实列一的目的相同,也是强调函数被调用函数之前作用域链就已经存在· · 全局作用域 -->Func函数作用域 -->inner函数作用域 不同的时,在执行[var ret = Func();]时,Func作用域中的xo变量已经由"nihao",被重置为"shijie",所以之后再执行[ret();]时,就只能找到"shijie"· 实列三: xo = "Wyc";<br> function Bar(){ console.log(xo); } function Func(){ var xo = "nihao"; return Bar; } var ret = Func(); ret(); //输出结果:Wyc 上述代码,在函数被执行之前已经创建了两条作用域链; ·全局作用域 --> Bar函数作用域 ·全局作用域 --> Func函数作用域 当执行[ret();]时,ret代指的Bar函数,而Bar函数的作用域链已经存在; 全局作用域 --> Bar函数作用域,所以,被执行时会根据已经存在的作用域链去寻找· 五丶声明提前 在javascript中如果不创建变量,直接去使用,则报错: console.log(xxoo); //报错:Uncaught ReferenceError:xxoo is not defined javascript中如果创建值而不赋值.则该值为 undefined,如: var xxoo; console.log(xxoo); //输出;undefined 在函数内如果这么写: function Foo(){ console.log(xo); var xo = "seven" } Foo(); //输出:undefined 上述代码,不报错而是输出 undefind,其原因是;javascript的函数在被执行之前.会将其中的变量全部声明,而不赋值.所以,相当于上述实列中,函数在"预编译"时,已经执行了var xo;所以上述代码中输出的是undefined·
全选,反选列子 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div> <input type="button" value = "全选" ondblclick="CheckAll()"> <input type="button" value="取消" ondbclick="CancleAll()"> <input type="button" value="反选" ondblclick="ReverseAll()"> </div> <table> <theard> <tr> <th>序号</th> <th>用户名</th> <th>年龄</th> </tr> </theard> <tbody id="tb"> <tr> <td><input class="c1" type="checkbox"></td> <td>Wyc</td> <td>17</td> </tr> <tr> <td><input class="c1" type="checkbox"></td> <td>Wyc</td> <td>18</td> </tr> <tr> <td><input class="c1" type="checkbox"></td> <td>Wyc</td> <td>19</td> </tr> </tbody> </table> <script> function CeckAll(){ var tb = document.getElementById("td"); var checks = tb.getElementsByClassName("c1"); for(var i=0;i<checks.length;i++){ var current_check = checks[i]; current_check.checked =true; } } function CancleAll(){ var tb = document.getElementById("tb"); var checks = tb.getElementsByClassName("c1"); for(var i=0;i<checks.length;i++){ var current_check = checks[i]; current_check.checked = false; } } function ReverseAll(){ var tb = document.getElementById("tb"); var checks = tb.getElementsByClassName("c1"); for(var i=0;i<checks.length;i++){ var current_check = checks[i]; if(current_check.checked){ current_check.check = false; }else{ current_check.checked = true; } } } </script> </body> </html> 列子
搜索框实列 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .gg{ color:#dddddd; (浅灰色) } .bb{ color:black; (黑色的字体) } </style> </head> <body> <input type="text" class="gg" value="请输入内容" onfocus="Focus(this);" onblur="Blur(this);"/> <script> function Focus(ths){ //查找第一种方式 //document //第二种方式 (this) //ths ths.className = "bb"; var current_val = ths.value; if(current_val == "请输入内容"){ ths.value = "" } } function Blur(ths){ var current_val = ths.value; if(current_val == "请输入内容" || current_val.trim().length == 0){ ths.value = "请输入内容"; ths.className == "gg"; } } </script> </body> View Code
文档对象模型(Document Objenct Model,DOM)是一种用于HTML和XML文档的编程接口.它给文档提供了一中结构化的表示方法,可以改变文档的内容呈现方式.我们最为关心的是,DOM把网页和脚本以及其他的编程语言联系了起来.DOM属于浏览器,而不是javascript语言规范的规定的核心内容· 一丶查找元素 1·直接查找 document.getElementById //根据ID获取一个标签 document.getElementsByName //根据name属性获取标签集合 document.getElementsByClassName //根据class属性获取标签集合 document.getElementsByTagName //根据标签名获取标签集合 2·简介查找 parentNode //父节点 childNodes //所有子节点 fistChild //第一个子节点 lastChild //最后一个子节点 nextSibling //下一个兄弟节点 previousSibling //上衣个兄弟节点 parentElement //父节点标签元素 children //所有子标签 firstElementChild //第一个子标签元素 lastElementChild //最后一个子标签元素 nextElementtSibling //下一个兄弟标签元素 previousElementSibling //上一个兄弟标签元素 二丶操作 1丶内容 innerText //文本 outerText innerHTML //HTML内容 innerHTML value //值 2丶属性 attrbutes //索取所有标签属性 setAttribute(key,value) //设置标签属性 getAttribute(key) //获取指定标签属性 /* var atr = document.createAttribute("class"); atr.nodeValue = "democlass"; document.detElementById("n1").setAttributeNode(atr); */ <!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <input type="bottob" value="全选" onclick="CheckAll();"/> <input type="bottob" value="取消" onclick="CheckAll();"/> <input type="button" value="反选" onclick="ReverseCheck();"/> <table border="1"> <thead> </therd> <tbody id="tb"> <tr> <td><input type="checkbox"/></td> <td>66666</td> <td>88888</td> </tr> <tr> <td><input type="checkbox"/></td> <td>66666</td> <td>88888</td> </tr> <tr> <td><input type="checkbox"/></td> <td>66666</td> <td>88888</td> </tr> </table> <script> function CheckAll(tha){ var tb = document.getElementById("tb"); var trs = tv.childNodes; for(var i=0;i<trs.lengt;i++){ var current_tr = trs[i]; if(current_tr.nodeType == 1){ var inp = current_tr.firstElementChild.getElementByTagName("input")[0]; inp.checked = true; } } } function CancelAll(ths){ var tb = document.getElementById('tb'); var trs = tb.childNodes; for(var i =0; i<trs.length; i++){ var current_tr = trs[i]; if(current_tr.nodeType==1){ var inp = current_tr.firstElementChild.getElementsByTagName('input')[0]; inp.checked = false; } } } function ReverseCheck(ths){ var tb = document.getElementById('tb'); var trs = tb.childNodes; for(var i =0; i<trs.length; i++){ var current_tr = trs[i]; if(current_tr.nodeType==1){ var inp = current_tr.firstElementChild.getElementsByTagName('input')[0]; if(inp.checked){ inp.checked = false; }else{ inp.checked = true; } } } } </script> View Code 3丶class操作 className //获取所有类名 classList.remove(cls) //删除指定类 classList.add(cls) //添加类 4丶标签操作 a·创建标签 //方式一 var tag = document.createElement("a") tag.innerText = "Wyc" tag.className = "c1" tag.href = "http://www.cnblogs.com/wuyongcong" //方式二 var tag = "<a class="c1" href = "http://www.cnblogs.com/wuyongcong">wuyongcong</a>" b·操作标签 //方式一 var obj = "<input type="text" />"; xxx.insertAdjacentHTML("beforeEnd",obj); xxx.insertAdjacentElement("afterBegin",document.createElement("p")) //注意:第一个参数只能是"beforeBegin","afterBegin","befoeEnd","afterEnd" //方式二 var tag = document.createElement("a") xxx.appendChild(tag) xxx.insertBefore(tag,xxx[1]) 5丶样式操作 var obj = document.getElementById("i1") obj.style.fontSize = "32px"; obj.style.backgroundColor = "blue"; <input onfocus="Focus(this);" onblur="Blur(this);" id="search" value="请输入关键字" style="color:gray;"/> <script> function Focus(ths){ ths.style.color = "black"; if(ths.value == "请输入关键字" || ths.value.trim() == ""){ ths.value = ""; } } function Blur(ths){ if(ths.value.trim() == ""){ ths.value.color = "gray"; }else{ ths.style.color = "black"; } } </script> View Code 6丶位置操作 //总文档高宽 document.documentElement.offsetHeight //当前文档占屏膜高宽 document.documentElement..clientHeight //自身高度 tag.offsetHeight //距离上级定位高度 tag.offsetTop //父定位标签 tag.offsetParent //滚动高度 tag.scrollTop /* clientHeight -> 课件区域: height + padding clienTop -> border高度 offsetHeight -> 可见区域:height + padding + border offsetTop -> 上级定位标签的高度 scrollHeight -> 全文高:height + padding scrollTop -> 滚动高度 特别的: document.documentElement代指文档根节点 */ 7丶提交表单 document.getElementById("form").submit() 8丶其他操作 console.log //输出框 alert //弹出框 confirm //确认框 // URL和刷新 location.href //获取URL location.href = "url" //重定向 location.reload() //重新加载 //定时器 setInterval //多次定时器 clearInterval //清除多次定时器 setTimeout //单次定时器 clearTimeout //清除单词定时器 三·事件 对于事件需要注意的要点: · this · event · 事件链以及跳出 this标签当前正在操作的标签,event封装了当前事件的内容·
JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应的代码,浏览器可以解释并作出相应的处理。 1·JavaScript代码存在形式 1 <!--方式一--> 2 <script type"text/javascript" src="js文件"></script> 3 4 5 <!--方式二 --> 6 <script type"text/javascript"> 7 js代码内容... 8 </script> 2·JavaScript代码存在位置 ·HTML的head中 ·HTML的body代码块底部(强烈推荐) 由于html代码是从上到下执行,如果Head中的js代码耗时严重,就会导致用户长时间无法看到页面,如果放置在body代码块底部,那么及时js代码耗时严重,也不会影响用户看到页面的效果,只是js实现特效慢而已。 1 如: 2 <script src="https://www.xxxx.com"></script> 3 <script> 4 alert("123"); 5 </script> 6 7 8 //alert(弹窗) 3·变量 ·全局变量 ·局部变量 JavaScript中变量的声明是一个非常容易出错的点,局部变量必须以个var开头,如果未使用var,则默人表示声明的是全局变量· 1 var name ="xxxx" //局部变量 2 age = 18 //全局变量 注:单行注释 // 多行注释 /* */ 4·基本数据类型 javascript 中的数据类型分为原始类型和对象类型: ·原始类型 ·数字 ·字符串 ·布尔值 ·对象类型 ·数组 ·"字典" ·... 特憋的,数字,布尔值,null,undefined,字符串是不可变的. null和undefined //null, undefined null,是JavaScript语言的关键字,它表示以个特殊的值,常用来描述"空值". undefined是一个特殊值,表示变量未定义. 1·数字(Number) JavaScript中不区分整数值和浮点数值,java中所有数字均使用浮点数值表示· 转换: ·parseIne(变量名) 将某个值转换成数字,不成功则返现NaN ·parseFloat(变量名)将某个值转换成浮点数,不成功则返现NaN 特殊值: ·NaN:非数字,可使用isNaN(num)来判断· ·Infinity:无穷大,可使用isFinite(num)来判断· 更多数值计算: 常量 Math.E 常量e,自然对数的底数· Math.LN10 10的自然对数· Math.LN2 2的自然对数· Math.LOG10E 以10为底的e的对数· Math.LOG2E 以2为底的e的对数· Math.PI 常量figs/U03C0.gif· Math.SQRT1_2 2的平方根除以1· Math.SQRT2 2的平方根· ##静态函数 Math.abs() 计算绝对值· Math.acos() 计算反余弦值· Math.asin( ) 计算反正弦值。 Math.atan( ) 计算反正切值。 Math.atan2( ) 计算从X轴到一个点的角度。 Math.ceil( ) 对一个数上舍入。 Math.cos( ) 计算余弦值。 Math.exp( ) 计算e的指数。 Math.floor( ) 对一个数下舍人。 Math.log( ) 计算自然对数。 Math.max( ) 返回两个数中较大的一个。 Math.min( ) 返回两个数中较小的一个。 Math.pow( ) 计算xy。 Math.random( ) 计算一个随机数。 Math.round( ) 舍入为最接近的整数。 Math.sin( ) 计算正弦值。 Math.sqrt( ) 计算平方根。 Math.tan( ) 计算正切值。 math 2·字符串(String) 字符串是由字符组成的数组,但在JavaScript中字符串是不可变的:可以访问字符串任意位置的文本,但是JavaScript并未提供修改已知字符串内容的方法· 常见功能: a = "huanyingguanglin" "huanyingguanglin" a.length (查看长度) 16 a = " wyc " " wyc " a.trim() (去除字符串的两边空格) "wyc" a.trimleft() (去除字符串的左边空格) a.trimright (去除字符串的右边空格) a = "nihao" "nihao" a.charAt(2) (返回字符串中的参数的字符)!参数可以定义,看字符串的长度定义 "h" a = "wyc""wyc"b = "nihao""nihao"a.concat(b) (字符串的拼接)"wycnihao" a = "wycnihao""wycnihao"a.indexOf("ni",2) (寻找子序列位置)3 a = "wycnihao""wycnihao"a.lastIndexOf("yc",2) (子序列位置 )1 a = "wycnihao""wycnihao"a.substring("yc",4) (根据索引获取子序列)"wycn" a = "wycnihao""wycnihao"a.slice(1,6) (切片,从字符串的1位置到6位置)"ycnih" a = "wycnihao""wycnihao"a.toLowerCase() (将字符串变小写)"wycnihao"a.toUpperCase() (将字符串变大写)"WYCNIHAO" a = "wycnihao""wycnihao"a.split("cn") (字符串的分割)["wy", "ihao"] a = "wycwyc9wycwyc""wycwyc9wycwyc"a.split(/(\d+)/) (字符串的分割,支持正则分割)["wycwyc", "9", "wycwyc"] a = "wycwycwyc""wycwycwyc"a.match(/w/) (全局匹配)["w"]a.match(/w/g) (匹配的元素后边加个g,表示把字符串里边所有的w全部匹配出来)["w", "w", "w"] a = "wycwycwyc" "wycwycwyc"a.search(/y/) (匹配出元素的位置)1 a = "wyc7wycwyc9""wyc7wycwyc9"a.replace(/(\d+)/g,"X") (将匹配到的数字全部替换为"X")"wycXwycwycX"a.replace(/(\d+)/g,"$&"+"L") (将匹配到的数字后边的元素替换为“L”) "wyc7Lwycwyc9L" a.replace(/(\d+)/g,"&") (将所有匹配到的数字替换成艾特符号“&”)"wyc&wycwyc&" a = "wyc7wycwyc9""wyc7wycwyc9"a.replace(/(\d+)\w+(\d+)/g,"$2$1") (将匹配到数字的7,9交换一下位置)"wyc97" a = "wyc7wycwyc9""wyc7wycwyc9"a.replace(/\d+/,"$`") (用于匹配左侧文本)"wycwycwycwyc9" a = "wyc7wycwyc9""wyc7wycwyc9"a.replace(/(\d+)\w+(\d+)/g,"$$") (直接量"$"符号)"wyc$" 3·布尔值 布尔类型仅包含真假,与python不同的是,python第一个字母是大写,("True","False"),则JavaScript里是小写("true","false") · == (比较值相等) · != (不等于) · === (比较值和类型相等) · !=== (不等于) · || (或) · && (且) 4·数组 JavaScript中的数组类似于python中的列表[] 常见功能: 1 obj.length //数组的大小 2 3 obj.push(ele) //尾部追加元素 4 5 obj.pop //尾部获取元素 6 7 obj.shift() //头部移除元素 8 9 obj.splice(start,deleteCount,value,......) //插入·删除或替换数组的元素 10 11 obj.splice(n,0,val) //指定位置插入元素 12 obj.splice(n,1,val) //指定位置替换元素 13 obj.splice(n,1) //指定位置删除元素 14 15 obj.slice() //切片 16 17 obj.reverse() //反转 18 19 onj.join(sep) //将数组元素链接起来以构建一个字符串 20 21 obj.concat(val,...) //连接数组 22 23 obj.sort() //对数组元素进行排序 //查看数组元素的长度 a = [11,22,33,44,55] [11, 22, 33, 44, 55] a.length 5 // 给数组尾部添加元素 a.push(66) 6 a [11, 22, 33, 44, 55, 66] //删除数组元素 [11, 22, 33, 44, 55, 66] ret = a.pop() 66 ret 66 a [11, 22, 33, 44, 55] //在数组头部添加元素 [11, 22, 33, 44, 55] a.unshift(77) 6 a [77, 11, 22, 33, 44, 55] //在数组头部移除元素 [77, 11, 22, 33, 44, 55] a.shift() 77 a [11, 22, 33, 44, 55] //splice即删除既添加 a [11, 22, 33, 44, 55] a.splice(1,0,"wyc") (表示在1的位置,0表示不删除,"wyc"表示在1的 位置添加进去) [] a [11, "wyc", 22, 33, 44, 55] //splice能添加多个元素 [11, "wyc", 22, 33, 44, 55] a.splice(1,0,"wyc","nihao") (splice,可以在数组一次里边添加多个元素 ) [] a [11, "wyc", "nihao", "wyc", 22, 33, 44, 55] //splice删除 [11, "wyc", "nihao", "wyc", 22, 33, 44, 55] a.splice(1,2) (表示从数组的第一个位置删除两个元素) ["wyc", "nihao"] a [11, "wyc", 22, 33, 44, 55] //splice替换 [11, "nihao", "wyc", 22, 33, 44, 55] a.splice(1,1,"hi") (表示在元素1的位置删除1在添加一个新的元素) ["nihao"] a [11, "hi", "wyc", 22, 33, 44, 55] //切片 a [11, "hi", "wyc", 22, 33, 44, 55] a.slice(1,2) ["hi"] //反转 [11, "hi", "wyc", 22, 33, 44, 55] a.reverse() (将数组元素反转过来) [55, 44, 33, 22, "wyc", "hi", 11] //将数组元素拼接起来(join) [55, 44, 33, 22, "wyc", "hi", 11] a.join("_") //将数组元素用下滑线拼接起来 "55_44_33_22_wyc_hi_11" //sort排序 [55, 44, 33, 22, "wyc", "hi", 11] a.sort() //将数组进行排序 [11, 22, 33, 44, 55, "hi", "wyc"] 四·其他 1丶序列化 ·JSON.stringify(obj) 序列化 ·JSON.parse(str) 反序列化 a = 3 3 JSON.stringify(a) (将a序列化成字符串) "3" JSON.parse(a) (将a在反序列化成整数) 3 序列化,反序列化 2丶转义 ·decodeURI() URI中为转义的字符 ·decodeURIComponent() URI组件中的未转义字符 ·encodeURI() URI中的转义字符 ·encodeURIComponent() 转义URI组件中的字符 ·escape() 对字符串的转义 ·unescape() 给转义字符串解码 ·URIError 由URI的编码和解码方法抛出 3丶eval JavaScript中的eval是python中eval和exec的合集,既可以编译代码也可以获取返回值· ·eval() ·EvalError 执行字符串中的JavaScript代码 4丶正则表达式 JavaScript中支持正则表达式,其主要提供了两个功能: ·test(string) 用于检测正则是否匹配 ·exec(string) 用于获取正则匹配的内容 注:定义正则表达式时,"g","i","m"分别表示去全局匹配,忽略大小写,多行匹配· 5丶时间处理 JavaScript中提供了时间相关的操作,时间操作中分为两种时间: ·时间统一时间 ·本地时间(东8区) 更多操作参见:http://www.shouce.ren/api/javascript/main.html 五丶语句和异常 1丶条件语句 javascript中支持两个条件语句分别是:if和switch if(条件){ }else if(条件){ }else{ } switch(name){ case"1": age = 123; break; case"2": age = 456; break default: age = 777; } 2丶循环语句 javascript中支持三种循环语句,分别是: var names = ["wyc","nihao"]; for(var i=0;i>names.lengith;i++){ console.log(i); console.log(name[i]); } 方式一 var name = ["wyc","nihao"] for (var index in name ){ console.log(index); console.log(name[index]); } 方式二 while(条件){ //break; //continue; } View Code 3丶异常处理 1 try{ 2 //这段代码从上到下运行,其中任何一个语句抛出异常该代码块就结束运行· 3 } 4 catch(e){ 5 //如果try代码中抛出异常,catch代码块中的代码就会被执行. 6 //e是一个局部变量,用来指向Error对象或者其他抛出的对象 7 } 8 finally{ 9 //无论try中代码是否有异常抛出(甚至是try代码块中有return语句),finally代码块中始终会被执行· 10 } View Code 注:主动跑出异常throw Error("xxxxx") 六丶函数 1·基本函数 javascript中函数基本可分为一下三类: //普通函数 function function(arg){ //创建函数 return true; } //匿名函数 var func = function(arg){ return "tony"; } //自动执行函数 (function(arg){ console.log(arg); })("123") View Code 注意:对于javascript中函数参数,十几参数的个数可能小于形参的个数,函数内的特殊值arguments中封装了所有的实际参数· 2·作用域 javascript中每个函数都有自己的的作用域,当出现函数嵌套时,就出现了作用域链,当内层函数使用变量时,会根据作用域链从内到外一层层的循环,如果不存在则异常· !切记:所有的作用域在创建函数且未执行的时候就已经存在了· 1 function f2(){ 2 var arg = 111; 3 function f3(){ 4 conlose.log(arg); 5 } 6 return f3(); 7 } 8 9 ret = f2(); //执行函数 10 ret(); function f2(){ var arg = [11,22]; function f3(){ console.log(arg); } arg = [44,55]; return f3; } ret = f2(); ret(); View Code 注:声明提前,在javascript引擎"预编译"时进行· 更多: 3丶闭包 [闭包],是指拥有多个变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分· 闭包是个函数,而他[记住了周围发生了什么]·表现为由[一个函数]体中定义了[另一个函数],由于作用域链只能从内向外找,默认外部无法获取函数内部变量.闭包、在外部获取函数内部的变量. function f1(){ var arg = [11,22]; function f2(){ return arg; } return f2; } ret = f2(); ret(); 面向对象· function Foo (name,age){ this.Name = name; this.Age = age; this.Func = function(arg){ return this.name + arg; } } var obj = new Foo("Wyc",19); var ret = obj.Func("nihao"); console.log(ret); 对于上述代码需要注意: · Foo充当的构造方法 在python构造方法代指的是(__init__) · thif 代指对象 · 创建对象是需要使用 new 上述代码中每个对象中均保存了一个相同的Func函数,从而浪费内存.使用原型和可以解决该问题. function Foo(name,age){ this.Name = name; this.Age = age; } Foo.prototype = { GetInfo:function(){ return this.Name + this.Age }, Func : function(arg){ return this.Name + arg; } }
购物数量添加: <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style> body{ margin: 0; } .left{ float: left; } .wrap{ width: 150px; height: 22px; border: 1px solid #ddd; /*background-color: red;*/ position: relative; left: 100px; top: 100px; } .wrap .minus{ height: 22px; width: 22px; line-height: 22px; text-align: center; cursor: pointer; } .wrap .plus{ height: 22px; width: 22px; line-height: 22px; text-align: center; cursor: pointer; /*当鼠标指的时候变样式*/ } .wrap .count input{ padding: 0; /*input是有padding的*/ border: 0; width: 104px; height: 22px; border-left: 1px solid #dddddd; border-right: 1px solid #dddddd; } </style> </head> <body> <div class="wrap"> <div class="minus left" onclick='Minus();'>-</div> <div class="count left"> <input id='count' type="text" /> </div> <div class="plus left" onclick='Plus();'>+</div> </div> <script type="text/javascript"> function Plus(){ var old_str = document.getElementById('count').value var old_int = parseInt(old_str); var new_int = old_int + 1 document.getElementById('count').value = new_int } function Minus(){ var old_str = document.getElementById('count').value var old_int = parseInt(old_str); var new_int = old_int - 1 document.getElementById('count').value = new_int } </script> </body> </html> cursor:pointer; /*鼠标尖头变小手*/ View Code
鼠标放进图片之后: 鼠标没放进图片之前: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .touch{ width: 200px; height: 200px; overflow: hidden; position: relative; } .touch .content{ position: absolute; top:0; height: 0; left: 0; bottom: 0; opacity: 0.6; color: black; text-align: center; visibility: hidden; } .touch:hover .content{ visibility: visible; } .touch .content .c1{ font-size: 32px; padding: 30px 0; } </style> </head> <body> <div class="touch"> <div><img src="2.jpg"></div> <div class="content"> <div class="c1">NiHao</div> <div class="c2">Wyc</div> </div> </div> </body> </html> # visibility: hidden; 透明度隐藏 View Code
列子: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel= stylesheet href="font-awesome/css/font-awesome.css"> <style> .user{ position: relative; width: 250px; } .user input{ height: 30px; width: 170px; padding-right: 30px; margin-left: 0px; } .user .ren{ position: absolute; top: 26px; left: 176px; } </style> </head> <body> <div class="user"> <a>login:<input type="text"></a> <span class="ren"><a class="icon-linux"></a></span> </div> </body> </html> ########### font-awesome:是一个第三方小图插件,导入进去之后找到自己想要的图片,class添加就OK了。 View Code
css 一、整体布局 1、创建一个html标签 2、创建三个div标签(分别是网页的头部,中间,和底部三部分) 3、一般都用class选择器 4、用css给body标签加个 margin:0(用于消除body边框和浏览器间的空白部分) 5、使div(块状)标签居中---------->先定义宽度,高度----------->margin:0 auto(自动离俩边距离相同) 6、list-style: none; 去除无序列表前面的符号(不能除去有序列表的) 7、padding:(1)上 (2)右 (3)下 (4)左 padding:(1)上下 (2) 左右 8、去掉a标签下面的下划线------------------>text-decoration = none 9、设置图片的高度用margin-top = xxxpx; 10、line-height = 行高 ------------>文本上下居中 11、text-again = center------------>文本左右居中 二、标签种类 dispaly:inline 变内联标签 ----------无法使用高度,宽度 display:block 变块级标签 display:inline-block 变内联标签 -----可以使用高度,宽度 三、页面中的小图标(实际上是通过一面墙上的洞看图片中的图标,我们可以通过调节洞的大小和图片的位置来显示不同的样式) 1、先定义洞口的大小 width:18px height:16px 2、通过backgroud-position:值1 值2 通过调整值1,值2的大小来移动位置来得到不同的图片 四、z-index 在同一位置定义俩标签(都钉住,那么后面的标签会把前面的标签覆盖掉,这样我们就可以用z-index=xx的大小来决定位置) <div style="position: fixed; left:0; right:0;height: 50px; "></div> <div style="position: fixed; left:0; right:0;height: 50px; "></div> 五、子类漂浮,父类背景消失问题(由于子类漂浮,无法支撑起父类) <meta charset="UTF-8"> <title>Title</title> <style> .w{ background-color: gold; } .w .item{ float: left; } </style> </head> <body> <div class="w"> <div class="item">111</div> <div class="item">222</div> </div> </body> </html> View Code 解决方法一:再新加一个标签,样式设置成clear = both <head> <meta charset="UTF-8"> <title>Title</title> <style> .w{ background-color: gold; } .w .item{ float: left; } </style> </head> <body> <div class="w"> <div class="item">111</div> <div class="item">222</div> <div style="clear: both"></div> </div> </body> </html> View Code 解决方法二:利用伪类 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .w{ background-color: gold; } .w .item{ float: left; } .w:after{ content: "777"; #在标签后面加一个内联标签 display: block; #设置成块级标签,让其换行 clear: both; visibility: hidden; #隐藏掉添加的部分 } </style> </head> <body> <div class="w"> <div class="item">111</div> <div class="item">222</div> </div> </body> </html> View Code 六·hover后加选择器点上去以后俩个不同的东西同时变化的情况 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <style> .c1{ width: 300px; height: 50px; border: 2px solid transparent; } .c1:hover{ #表示点上去以后c1变化 border: 2px solid rebeccapurple; # rebeccapurple为透明色 } .c1:hover .c2{ #表示点上去以后c1的变化的同时c2变化 color: #e20052; } </style> </head> <body> <div class="c1"> <span class="c2">123</span> <div class="c3">456</div> </div> </body> </html> View Code
Socket socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求。 socket起源于Unix,而Unix/Linux基本哲学之一就是“一切皆文件”,对于文件用【打开】【读写】【关闭】模式来操作。socket就是该模式的一个实现,socket即是一种特殊的文件,一些socket函数就是对其进行的操作(读/写IO、打开、关闭) socket和file的区别: file模块是针对某个指定文件进行【打开】【读写】【关闭】 socket模块是针对 服务器端 和 客户端Socket 进行【打开】【读写】【关闭】 import socket ip_port = ('127.0.0.1',9999) sk = socket.socket() sk.bind(ip_port) sk.listen(5) while True: print 'server waiting...' conn,addr = sk.accept() client_data = conn.recv(1024) print client_data conn.sendall('不要回答,不要回答,不要回答') conn.close() View Code import socket ip_port = ('127.0.0.1',9999) sk = socket.socket() sk.connect(ip_port) sk.sendall('请求占领地球') server_reply = sk.recv(1024) print server_reply sk.close( View Code WEB服务应用 import socket def handle_request(client): buf = client.recv(1024) client.send("HTTP/1.1 200 OK\r\n\r\n") client.send("Hello, World") def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost',8080)) sock.listen(5) while True: connection, address = sock.accept() handle_request(connection) connection.close() if __name__ == '__main__': main() View Code 更多功能 sk = socket.socket(socket.AF_INET,socket.SOCK_STREAM,0) sk.bind(address) s.bind(address) 将套接字绑定到地址。address地址的格式取决于地址族。在AF_INET下,以元组(host,port)的形式表示地址。 sk.listen(backlog) 开始监听传入连接。backlog指定在拒绝连接之前,可以挂起的最大连接数量。 backlog等于5,表示内核已经接到了连接请求,但服务器还没有调用accept进行处理的连接个数最大为5 这个值不能无限大,因为要在内核中维护连接队列 sk.setblocking(bool) 是否阻塞(默认True),如果设置False,那么accept和recv时一旦无数据,则报错。 sk.accept() 接受连接并返回(conn,address),其中conn是新的套接字对象,可以用来接收和发送数据。address是连接客户端的地址。 接收TCP 客户的连接(阻塞式)等待连接的到来 sk.connect(address) 连接到address处的套接字。一般,address的格式为元组(hostname,port),如果连接出错,返回socket.error错误。 sk.connect_ex(address) 同上,只不过会有返回值,连接成功时返回 0 ,连接失败时候返回编码,例如:10061 sk.close() 关闭套接字 sk.recv(bufsize[,flag]) 接受套接字的数据。数据以字符串形式返回,bufsize指定最多可以接收的数量。flag提供有关消息的其他信息,通常可以忽略。 sk.recvfrom(bufsize[.flag]) 与recv()类似,但返回值是(data,address)。其中data是包含接收数据的字符串,address是发送数据的套接字地址。 sk.send(string[,flag]) 将string中的数据发送到连接的套接字。返回值是要发送的字节数量,该数量可能小于string的字节大小。即:可能未将指定内容全部发送。 sk.sendall(string[,flag]) 将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常。 内部通过递归调用send,将所有内容发送出去。 sk.sendto(string[,flag],address) 将数据发送到套接字,address是形式为(ipaddr,port)的元组,指定远程地址。返回值是发送的字节数。该函数主要用于UDP协议。 sk.settimeout(timeout) 设置套接字操作的超时期,timeout是一个浮点数,单位是秒。值为None表示没有超时期。一般,超时期应该在刚创建套接字时设置,因为它们可能用于连接的操作(如 client 连接最多等待5s ) sk.getpeername() 返回连接套接字的远程地址。返回值通常是元组(ipaddr,port)。 sk.getsockname() 返回套接字自己的地址。通常是一个元组(ipaddr,port) sk.fileno() 套接字的文件描述符