对于所有的web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端。
一个简单的web程序:
#!/usr/bin/env python #coding:utf-8 import socket def handle_request(client): buf = client.recv(1024) client.send("HTTP/1.1 200 OK ") client.send("Hello, Seven") def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(('localhost',8000)) sock.listen(5) while True: connection, address = sock.accept() handle_request(connection) connection.close() if __name__ == '__main__': main()
python web程序一般会分为服务器程序和应用程序。服务器程序负责对socket服务器进行封装,并在请求到来时对请求的各种数据进行整理。应用程序则负责具体的逻辑处理。为了方便应用程序的开发,就出现了众多的web框架。例如Django,Flask,web.py等。
不同的框架有不同的开发方式,但是无论如何,开发出的应用程序都要和服务器程序配合,再能为用户提供服务。这样,服务器程序就需要为不同的框架提供不同的支持。这样混乱的局面无论对服务器还是框架,都是不好的。对服务器来说,需要支持各种不同框架,对框架来说只有支持它的服务器才能被开发出的应用使用。这个时候,标准化就变的尤为重要。我们可以设立一个标准,只要服务器程序支持这个标准,框架也支持这个标准,那么他们就可以配合使用。一旦标准确定,双方各自实现。这样,服务器可以支持更多支持标准的框架,框架也可以使用更多支持标准的服务器。
WSGI
web server gateway interface 是一种规范,它定义了使用python编写的web app与web server 之间的接口格式,实现 web app与 web server间的解耦。
python标准库提供的独立的wsgi服务器称为wsgiref
#!/usr/bin/env python #coding:utf-8 from wsgiref.simple_server import make_server def RunServer(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) return '<h1>Hello, web!</h1>' if __name__ == '__main__': httpd = make_server('', 8000, RunServer) print "Serving HTTP on port 8000..." httpd.serve_forever()
自定义web框架
通过python标准库提供的wsgiref模块开发一个自己的web框架
#!/usr/bin/env python #coding:utf-8 from wsgiref.simple_server import make_server def index(): return 'index' def login(): return 'login' def routers(): urlpatterns = ( ('/index/',index), ('/login/',login), ) return urlpatterns def RunServer(environ, start_response): start_response('200 OK', [('Content-Type', 'text/html')]) url = environ['PATH_INFO'] urlpatterns = routers() func = None for item in urlpatterns: if item[0] == url: func = item[1] break if func: return func() else: return '404 not found' if __name__ == '__main__': httpd = make_server('', 8000, RunServer) print "Serving HTTP on port 8000..." httpd.serve_forever()
MVC 和 MTV
MVC : model view controller
model:模型,表示应用程序核心(比如数据库记录列表),是应用程序中用于处理应用程序数据逻辑的部分,通常模型对象负责在数据库中存取数据。
view:视图,显示数据(数据库记录),是应用程序中处理数据显示的部分,通常视图是依据模型数据创建的
controller:控制器,处理输入(写入数据库记录),是应用程序中处理用户交互的部分,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MTV : model template view
model :负责业务对象和数据库的关系映射(ORM)
template:负责如何把页面展示给用户(html)
view:负责业务逻辑,并在适当时调用 model 和 template
Django
一,创建django程序
1,命令行: django-admin startproject sitename
常用命令:
python manage.py runserver 0.0.0.0 # 启动程序
python manage.py startapp appname # 新建一个项目
python manage.py syncdb
python manage.py makemigrations # 把数据库类转换为原生SQL语句
python manage.py migrate # 执行SQL语句
二,django程序目录
manage.py # 命令文件
templates # 存放静态文件的目录
urls.py # URL引导
settings.py # 主配置文件
models.py # 创建数据库文件
views.py # 主程序文件
admin.py # 后台管理文件
三,Django流程介绍
四,配置文件
1,URL(urls.py)
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), ] # 正则匹配
# 可命名的正则
# 即 把正则匹配到的值 /(?P<year>[0-9]{4})/ 赋值给 year这个变量名,后面的类似
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), ]
# 注:这里匹配到的所有内容都是字符串类型,这里有多少个正则匹配,在向主程序的时候就需要传入多个个参数
from django.conf.urls import include, url urlpatterns = [ url(r'^community/', include('django_website.aggregator.urls')), url(r'^contact/', include('django_website.contact.urls')), ]
# 引入文件,文件跳转,即访问Community 的时候会跳转到 django_website.aggregator.urls 文件处理
from django.conf.urls import include, url from . import views urlpatterns = [ url(r'^(?P<page_slug>[w-]+)-(?P<page_id>w+)/', include([ url(r'^history/$', views.history), url(r'^edit/$', views.edit), url(r'^discuss/$', views.discuss), url(r'^permissions/$', views.permissions), ])), ]
#一次可以定义多个URL,使用url()的方式
from django.conf.urls import url from . import views urlpatterns = [ url(r'^blog/(?P<year>[0-9]{4})/$', views.year_archive, {'foo': 'bar'}), ]
# 方法一: # main.py from django.conf.urls import include, url urlpatterns = [ url(r'^blog/', include('inner'), {'blogid': 3}), ] # inner.py from django.conf.urls import url from mysite import views urlpatterns = [ url(r'^archive/$', views.archive), url(r'^about/$', views.about), ] # 方法二: # main.py from django.conf.urls import include, url from mysite import views urlpatterns = [ url(r'^blog/', include('inner')), ] # inner.py from django.conf.urls import url urlpatterns = [ url(r'^archive/$', views.archive, {'blogid': 3}), url(r'^about/$', views.about, {'blogid': 3}), ]
# include() 另外deepin方法
# 注:以上URL匹配的方式是从第一条向下,匹配到一条之后就不再向下匹配,所以尽量把精确匹配放到上面,模糊匹配放到下面。
2,Views(views.py)
返回一个字符串:
from django.http import HttpResponse def my_view(request): #request 关键字,必须写这个,后面可以跟参数 if request.method == 'GET': return HttpResponse('result')
返回一个html文档:
from django.shortcuts import render,HttpResponse def test_view(request): return render(request,'index.html') # render 返回html的关键字 def index(request): if request.method == 'GET': user_infos = [ {'username1':'name1','age':'age1'}, {'username2':'name2','age':'age2'}, {'username3':'name3','age':'age3'}, {'username4':'name4','age':'age4'}, ] return render(request, 'app01/index.html',{'user_objs':user_infos}) #user_objs 为字典的键名,在 app01/index 内可以通过 这个名字来访问 user_infos列表内的值 else: #post return HttpResponse("transfered 100000 to alex....success.")
从数据中取值:
def book(request): if request.method == 'POST': print(request.POST) book_name = request.POST.get('name') # 从前端取值(单个数据) publisher_id = request.POST.get('publisher_id') print('==>',request.POST.get('author_ids')) author_ids = request.POST.getlist('author_ids') # getlist 多个值 列表的形式 #print(dir( request.POST)) print(book_name,publisher_id,author_ids) new_book = models.Book( name=book_name, publisher_id = publisher_id, publish_date = '2016-05-22' ) new_book.save() #保存数据 new_book.authors.add(*author_ids) # 写入数据库 #new_book.authors.add(1,2,3,4) books = models.Book.objects.all() #从数据中取值所有数据,Book 为表名 publisher_list = models.Publisher.objects.all() author_list = models.Author.objects.all() return render(request,'app01/book.html',{'books':books, 'publishers':publisher_list, 'authors':author_list }) #以字典的方式返回给前端页面
3,数据库(settings.py)
# 文件形式 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.sqlite3', 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), } } #数据库形式 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql', 'NAME':'dbname', 'USER': 'root', 'PASSWORD': 'xxx', 'HOST': '', 'PORT': '', } }
在settings中配置当前APP,不然Django无法找到自定义的simple_tag
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'app01', #新创建的APPname )
五:数据库操作说明
字段说明(下面会用到):
- AutoField:自增列 = int(11) , 如果没有的话,默认会生成一个名称为id的列,如果要显示自定义的自增列,必须将给列设置为主键 primary_key=True
- CharField:字符串字段,必须使用 max_length 参数来限制字符串长度
- BooleanField:布尔类型=tinyint(1) ,不能为空 Blank=True
- ComaSepararedIntegerField:用逗号分割的数字=varchar,继承CharField,必须使用 max_lenght 参数
- DateField:日期类型 date,对于参数 auto_now=True 每次更新都会更新这个时间。auto_now_add 则只有第一次创建添加,之后的更新不再改变
- DateTimeField:日期类型 datetime 同DateField参数
- Decimal: 十进制小数类型=decimal,必须指定整数位 max_digits和 小数位 decimal_places
- EmailFiled:字符串类型(正则表达邮箱)=varchar,对字符串进行正则匹配
- FloatFiled:浮点类型=double
- IntegeFiled:整型
- BigIntegerField:长整型
integer_field_ranges = { 'SmallIntegerField': (-32768, 32767), 'IntegerField': (-2147483648, 2147483647), 'BigIntegerField': (-9223372036854775808, 9223372036854775807), 'PositiveSmallIntegerField': (0, 32767), 'PositiveIntegerField': (0, 2147483647), }
参数说明:
- null=True 数据库中字段是否可以为空
- blank=True Django的Admin添加数据时是否允许为空值
- primary_key=False 主键,对AutoField 设置主键后,就会代替原来的自增 ID 列
- auto_now 自动创建,无论添加或修改,都是当前操作的时间
- auto_now_add 自动创建,永远是创建时的时间
choices GENDER_CHOICE = ( (u'M', u'Male'), (u'F', u'Female'), ) gender = models.CharField(max_length=2,choices = GENDER_CHOICE)
- max_lenght 最大长度
- default 默认值
- verbose_name Admin中字段的显示名称
- name|db_column 数据库中的字段名称
- unique=True 不允许重复
- db_index=True 数据库索引
- editable=True 在Admin里是否可编辑
- error_messages=None 错误提示
- auto_created=False 自动创建
- help_text 在Admin中提示帮助信息
- validators=[]
- upload-to
表关系:
- ForeignKey(ColorDic) 一对多
- OneToOneField(OneModel) 一对一
- ManyToManyField(Author) 多对多
数据库操作:
- 增加:创建示例,并调用 save()
- 更新:1,获取实例,再sava 2 ,update(指定列)
- 删除: 1, filter().delete() 2, all().delete()
- 获取: 单个 =get(id-1) 所有 =all()
- 过滤: filteer(name=’xx’);filter(name_contains=’’);(id_in = [1,2,3]);
icontains(大小写无关的LIKE),startswith和endswith, 还有range(SQLBETWEEN查询)'gt', 'in', 'isnull', 'endswith', 'contains', 'lt', 'startswith', 'iendswith', 'icontains','range', 'istartswith'
- 排序: order_by(“name”)=asc; order_by(“-name”)=desc
- 返回第n-m条,第n条[0];前两条[0:2]
- 指定映射:values
- 数量:counter()
- 聚合:from django.db.models import Min,Max,Sum objects.all().aggregate(Max('guest_id'))
- 原始SQL
cursor = connection.cursor() cursor.execute('''SELECT DISTINCT first_name ROM people_person WHERE last_name = %s""", ['Lennon']) row = cursor.fetchone()