个人所有文章整理在此篇,将陆续更新收录:知无涯,行者之路莫言终(我的编程之路)
[1].Python的原生版Socket
[2].python自带的模块:`wsgiref`的简单使用
[3].Python和Idea的爱恨情,pip装了模块但不能用,或飘红了但能用
[4].随手一说 jinja2
[5].django的简单介绍
[6].django中使用MySQL数据库
客户端 通过url 查询IP和端口号 建立TCP/IP连接 将请求信息及数据 发送给服务端 并制定资源地址
服务端 接收请求及数据 根据资源地址 进行处理 返回响应信息及数据 给客户端
socket.accept()
方法会阻塞下面语句的继续,当有连接时便会接触阻塞
import socket
if __name__ == '__main__':
socket = socket.socket() # 生成socket对象
socket.bind(("127.0.0.1", 8089)) # 绑定IP和端口
socket.listen() # 监听
conn, addr = socket.accept() # 获取连接 -- 阻塞方法
data = conn.recv(1024 * 8) # 接收客户端数据
conn.send(b"HTTP/1.0 200\r\n") # 响应头
conn.send(b"\r\n") # 空行
conn.send(b"hello from server") # 响应数据
print(data)
socket.close()
conn.close()
抓一下包,看一下请求与响应
|--- 抓包获取的客户端请求数据-----------------
GET http://127.0.0.1:8089/ HTTP/1.1
Host: 127.0.0.1:8089
Connection: keep-alive
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9
|--- 抓包获取的服务端响应数据---------------------
HTTP/1.0 200
hello from server
不作处理返回原样,也就是整个html的文件字符
import os
import socket
if __name__ == '__main__':
socket = socket.socket() # 生成socket对象
socket.bind(("127.0.0.1", 8089)) # 绑定IP和端口
socket.listen() # 监听
path = os.path.dirname(__file__) + "/lizi.html"
//读取文件 存储在str变量
f = open(path, encoding="utf-8")
str = ''
for line in iter(f): # 迭代遍历
str += line
conn, addr = socket.accept() # 获取连接 -- 阻塞方法
data = conn.recv(1024 * 8) # 接收客户端数据
conn.send(b"HTTP/1.0 200\r\n") # 响应头
conn.send(b"\r\n") # 空行
conn.send(str.encode()) # 响应数据
print(data)
socket.close()
conn.close()
如果要告诉浏览器这是html ,需要一个响应头 :
content-type:text/html; charset=utf-8
就这么简单,然后一个页面就能被浏览器渲染了,所以说一个网站运行起来倒不是什么费劲的事,但优化是要来老命...
...
conn.send(b"HTTP/1.0 200\r\n") # 响应头
conn.send(b"content-type:text/html; charset=utf-8\r\n") # 响应头
conn.send(b"\r\n") # 空行
conn.send(str.encode()) # 响应数据
...
lizi.html
是静态界面,如何实现动态效果? 服务端可以对静态界面进行加工再返还给服务端
import os
import socket
if __name__ == '__main__':
socket = socket.socket() # 生成socket对象
socket.bind(("127.0.0.1", 8089)) # 绑定IP和端口
socket.listen() # 监听
path = os.path.dirname(__file__) + "/lizi.html"
f = open(path, encoding="utf-8")
res = ''
for line in iter(f): # 迭代遍历
res += line
conn, addr = socket.accept() # 获取连接 -- 阻塞方法
data = conn.recv(1024 * 8) # 接收客户端数据
# 服务器对客户端的请求数据进行加工,控制转换后发送给客户端
data = str(data, encoding="utf-8")
li = data.split("\r\n")
firstLine = li[0]
liFirstLine = firstLine.split(" ")
param = liFirstLine[1].replace("/", '')
res = res.replace("张风捷特烈", param)
conn.send(b"HTTP/1.0 200\r\n") # 响应头
conn.send(b"content-type:text/html; charset=utf-8\r\n") # 响应头
conn.send(b"\r\n") # 空行
conn.send(res.encode()) # 响应数据
socket.close()
conn.close()
如果说上面的是远古时期的时期时代,只能用打磨的石头当武器,随着社会发展,冷兵器也将到来
python服务端的框架就相当于刀剑的江湖
wsgiref
负责与客户端的socket通信,用起来比自己写的爽一些
import os
from wsgiref.simple_server import make_server
def readfile(path):
with open(path, "rb") as f:
return f.read()
def lizi(src):
path = os.path.dirname(__file__) + src
return readfile(path)
def runServer(evn, rep):
rep('200 OK', [('Content-Type', 'text/html; charset=utf-8')])
url = evn['PATH_INFO']
return [lizi(url)] # 注意这里返回列表...掉坑了
if __name__ == '__main__':
httpd = make_server('127.0.0.1', 8089, runServer)
httpd.serve_forever()
也许是python版本换了之后弄的挺乱,pip装的包竟然IDEA竟然找不到...
看一下Python的配置classpath 里有好多东西,删了会怎样?
然后我就全删了
结果print 函数都飘红了,神奇的是
一点击能正常运行
。也就是 classpath 里找不到print 函数
但Python运行环境还是在那的,虽然飘红但能运行。怎么让它不飘红 classpath 加回去呗
添加stdlib的classpath
如果现在使用外来包会怎么样
拿Jinja2来看,首先确保安装了它
J:\Python>pip freeze
cycler==0.10.0
Django==2.1.7
et-xmlfile==1.0.1
jdcal==1.4
Jinja2==2.10
...
还是飘红但能用
---->[net\date.html]---------模板-------
Title
now time :{{time}}
{% for name in names %}
- {{name}}
{% endfor %}
---->[net\ServerLever5.py]---------服务代码-------
import time
from jinja2 import Template
from wsgiref.simple_server import make_server
def date():
with open('date.html', "r") as f:
res = f.read()
tpl = Template(res)
dest = tpl.render({"time": getTime(), "names": ["捷特", "龙少", "巫缨"]})
return [bytes(dest, encoding="utf8")]
def getTime():
now = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(time.time()))
return now
def runServer(evn, rep):
rep('200 OK', [('Content-Type', 'text/html; charset=utf-8')])
return date()
if __name__ == '__main__':
httpd = make_server('127.0.0.1', 8089, runServer)
httpd.serve_forever()
飘红看起来碍眼,而且没提示,怎么办?
查看H:\\PythonDK\\lib\\site-packages
将他加到classpath
|--- 查看python文件夹
J:\Python>python -m site
sys.path = [
'J:\\Python',
'H:\\PythonDK\\python37.zip',
'H:\\PythonDK\\DLLs',
'H:\\PythonDK\\lib',
'H:\\PythonDK',
'H:\\PythonDK\\lib\\site-packages',
]
USER_BASE: 'C:\\Users\\Administrator\\AppData\\Roaming\\Python' (doesn't exist)
USER_SITE: 'C:\\Users\\Administrator\\AppData\\Roaming\\Python\\Python37\\site-packages' (doesn't exist)
ENABLE_USER_SITE: True
OK 不飘红,有提示,能运行 继续开心地敲代码吧,如果哪飘红就找找classpath在哪
django
安装依赖
pip3 install django
J:\Python\NetAll>pip3 install django
Collecting django
Downloading https://files.pythonhosted.org/packages/c7/87/fbd666c4f87591ae25b7bb374298e8629816e87193c4099d3608ef11fab9/Django-2.1.7-py3-none-any.whl (7.3MB)
100% |████████████████████████████████| 7.3MB 521kB/s
Requirement already satisfied: pytz in h:\pythondk\lib\site-packages (from django) (2018.9)
Installing collected packages: django
Successfully installed django-2.1.7
|--- 控制行 ( 如果错误:配置环境变量 python目录\Scripts )
C:\Users\Administrator>django-admin
Type 'django-admin help ' for help on a specific subcommand.
Available subcommands:
[django]
check
compilemessages
createcachetable
dbshell
diffsettings
dumpdata
flush
inspectdb
loaddata
makemessages
makemigrations
migrate
runserver
sendtestemail
shell
showmigrations
sqlflush
sqlmigrate
sqlsequencereset
squashmigrations
startapp
startproject
test
testserver
django-admin startproject toly_web
先直接在
urls.py
里测试一下django的作用, 开启服务:python manage.py runserver 8000
---->[toly_web/urls.py]--------------------
from django.shortcuts import HttpResponse
from django.urls import path
def lizi(req): # req--请求的封装对象
return HttpResponse("Hello World From Server -- lizi")
def toly(req): # req--请求的封装对象
return HttpResponse("Hello World From Server -- toly")
# 路径和函数的映射集
urlpatterns = [
path('toly/', toly),
path('lizi/', lizi),
]
这里新建一个templates文件夹盛放html页面
def readfile(path):
with open("./templates/" + path, "r", encoding="utf-8") as f:
return f.read()
def lizi(req): # req--请求的封装对象
return HttpResponse(readfile('lizi.html'))
当然上那样写也可以,不过不方便,还要自己读文件,settings中有TEMPLATES文件夹的设置
配置一下就可以用django内置的文件渲染函数
---->[toly_web/settings.py]-------------------------------
# 模板相关
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')], # 修改模板的路径
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
使用起来很简单
from django.shortcuts import HttpResponse, render
def lizi(req): # req--请求的封装对象
return render(req, 'lizi.html')
由于Html需要引入静态文件(js,css,图片,文件等),最好也配置一个静态文件的文件夹
springboot,react等框架,一般来说都是static文件夹盛放静态文件,这个没必要标新立异...
---->[toly_web/settings.py]-------------------------------
STATIC_URL = '/static/' # 引用静态文件是的开头部分
STATICFILES_DIRS=[ # 指定文件夹名称
os.path.join(BASE_DIR, 'static')
]
也就是将处理逻辑和url分文件写,控制职责
---->[toly_web/urls.py]--------------------------
from django.urls import path
from toly_web.pagers import toly, lizi, photo
# 路径和函数的映射集
urlpatterns = [
path('toly/', toly),
path('lizi/', lizi),
path('photo/', photo),
]
---->[toly_web/pagers.py]--------------------------
from django.shortcuts import HttpResponse, render
def readfile(path):
with open("./templates/" + path, "r", encoding="utf-8") as f:
return f.read()
def lizi(req): # req--请求的封装对象
return HttpResponse(readfile('lizi.html'))
def photo(req): # req--请求的封装对象
return render(req, 'photo.html')
def toly(req): # req--请求的封装对象
return HttpResponse("Hello World From Server -- toly")
简单来说django帮我们解决了客户端和服务端的通信问题,和服务端的开启为题
我们需要关注的是业务的处理逻辑和路径的指定,网络访问框架基本都是这个套路
代码就不贴了,不想写样式的弄四个框也行
|--- url 指向 : http://127.0.0.1:8000/register/
|--- 提交跳转路径 :http://127.0.0.1:8000/add_user/
会出现下面的错误,将setting的这句话注释起来即可
add_user
如何获取用户的输入数据
def add_user(req):
post = req.POST
print(post)
return HttpResponse(post)
|--- 结果是一个QueryDict
|--- 获取用户输入数据 -------------------------------
from django.http import HttpResponse
def add_user(req):
post = req.POST
print(post)
username = req.POST.get('username', None)
email = req.POST.get('email', None)
pwd = req.POST.get('pwd', None)
pwd_conform = req.POST.get('pwd_conform', None)
res = ' username= ' + username + ' \r\nemail= ' + email + ' \r\npwd= ' + pwd + '\r\npwd_conform=' + pwd_conform
return HttpResponse(res)
django和 jinja2里的用法差不多 :html里--
{{变量名}}
使用,如下
def add_user(req):
post = req.POST
print(post)
username = req.POST.get('username', None)
email = req.POST.get('email', None)
pwd = req.POST.get('pwd', None)
pwd_conform = req.POST.get('pwd_conform', None)
if pwd == pwd_conform:
# return render(req, "photo.html")
return redirect("/photo") # 重定向
else:
return render(req, "register.html", {'err': "两次密码不一致", "username": username, "email": email})
服务失败
服务成功
做安卓的对app的理解会深很多
记得末尾不要加;
--- MySQL敲多了容易敲错...
python manage.py startapp IGallery
相当于安装吧...
# Application definition
# app 相关配置 --- 安装--------------
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'IGallery.apps.IgalleryConfig', # 全类名
]
将页面放入相应资源中,在views里写函数
---->[IGallery/views.py]-------------------------------
from django.shortcuts import render
def gallery(req):
return render(req, '3dg.html')
|-- 添加路由 -------------
from IGallery import views
path('gallery/', views.gallery),
ORM
Object Relational Mapping
感觉有点MyBatis的感觉
# settings配置 数据库相关
DATABASES = {
'default': {
# 'ENGINE': 'django.db.backends.sqlite3', # 哇,sqlite3
# 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'ENGINE': 'django.db.backends.mysql', # 用mysql
'HOST': '127.0.0.1', # ip
'PORT': '3306', # 端口
'NAME': 'datatype', # 数据库名
'USER': 'root', # 用户名
'PASSWORD': 'xxxxxx', # 密码
}
}
连接数据库 : 安装 pymysql
---->[toly_web/__init__.py]-----------------
import pymysql
# 用pymysql代替MySQLdb
pymysql.install_as_MySQLdb()
创建表
---->[IGallery/models.py]---------------创建实体类-----------
class PicUser(models.Model):
id = models.AutoField(primary_key=True) # 自增长主键
username = models.CharField(null=False, max_length=20) # 非空用户名
password = models.CharField(null=False, max_length=24) # 非空密码
|--- 执行命令 ---------------------校验改动--------------
J:\Python\toly_web>python manage.py makemigrations
Migrations for 'IGallery':
IGallery\migrations\0001_initial.py
- Create model PicUser
|--- 执行命令 ---------------------执行改动---------------
J:\Python\toly_web>python manage.py migrate
Operations to perform:
Apply all migrations: IGallery, admin, auth, contenttypes, sessions
Running migrations:
Applying IGallery.0001_initial... OK
Applying contenttypes.0001_initial... OK
Applying auth.0001_initial... OK
Applying admin.0001_initial... OK
Applying admin.0002_logentry_remove_auto_add... OK
Applying admin.0003_logentry_add_action_flag_choices... OK
Applying contenttypes.0002_remove_content_type_name... OK
Applying auth.0002_alter_permission_name_max_length... OK
Applying auth.0003_alter_user_email_max_length... OK
Applying auth.0004_alter_user_username_opts... OK
Applying auth.0005_alter_user_last_login_null... OK
Applying auth.0006_require_contenttypes_0002... OK
Applying auth.0007_alter_validators_add_error_messages... OK
Applying auth.0008_alter_user_username_max_length... OK
Applying auth.0009_alter_user_last_name_max_length... OK
Applying sessions.0001_initial... OK
|--- mysql查看创建的表 ---------------------------
mysql> SHOW TABLES;
+----------------------------+
| Tables_in_datatype |
+----------------------------+
| auth_group |
| auth_group_permissions |
| auth_permission |
| auth_user |
| auth_user_groups |
| auth_user_user_permissions |
| django_admin_log |
| django_content_type |
| django_migrations |
| django_session |
| igallery_picuser |
+----------------------------+
mysql> DESC igallery_picuser;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(20) | NO | | NULL | |
| password | varchar(24) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
还用刚才的注册表单
def add_user(req):
...
if pwd == pwd_conform:
PicUser.objects.create(username=username, password=pwd) # 插入数据
...
else:
...
def list_user(req):
res = PicUser.objects.all() # 获取对象 [o1,o2,03]
return render(req, "user_list.html", {"user_list": res})
|--- html 表格 --------------------------
id值
用户名
密码
{% for user in user_list %}
{{ user.id }}
{{ user.username }}
{{ user.password }}
{% endfor %}
OK ,本文挺杂乱的,基本的服务端框架也就这样,PHP , Java的SpringBoot ,React ,Vue
核心都是模板填充数据,或只提供数据服务,整体梳理一下,细节方面,再说...