基础1部分的笔记(Django基本操作)

上节回顾:
   - 登录注册验证
		默认事件先执行:
			checkbox
		自定义先执行
			a
			submit
			...
		<form>

			<input type='type' />
			<input type='password' />
			<input type='submit' />

		</form>

		$(':submit').click(function(){

			$(':text,:password').each(function(){
				...
				return false;
			})
			return false;
		})

		input,checbox

    ================================== 验证 ================================
	JS: 验证

		 各种验证

			$(':submit').click(function(){

				$(':text,:password').each(function(){
					...
					return false;
				})
				return false;
			})

	后端:python实现

	业务处理
	....

3种组件
	========》 适合全站,但功能少
	BootStrap
		- css:v3.bootcss.com/css
		- js
	学习 BootStrap 规则

	一、响应式
		@media

	二、图标、字体
		@font-face

	三、基本使用
		js:依赖于jQuery
		css: !important;

	四、模板:http://www.niftyadmin.cn/index.html 原价56,现价39
			https://item.taobao.com/item.htm?id=575025805791

	========》 仅适合后台管理

	jQueryUI *
		- css
		- js
	学习 jQueryUI 规则

	EasyUI
		- css
		- js

	学习 jQueryUI 规则
	============ Ajax操作 ================

	附件:https://bxslider.com/ 插件轮播

WEB框架
	MVC
		Model       View       Controller
		数据库   模板文件    业务处理

	MTV

		Model    Template     View
		数据库   模板文件    业务处理

	############## WEB:MVC、MTV

Django
	# 安装 (必须python3)
	pip3 install django或者用pycharm创建

	# 配置环境变量
	C:\Python35\Scripts
	如果没有配置环境变量,只能在python3的安装目录Scripts下创建工程 django-admin.exe startproject 【工程名称】
	如果配置了环境变量,可以在自己目录下创建工程 django-admin startproject 【工程名称】

	# 创建Django工程(在pycharm根目录下创建,可避免from import飘红)
	django-admin startproject 【工程名称】

		mysite
			- mysite        # 对整个程序进行配置
				- init      # python3中可有可无,python2中导入模块需要__init__文件(包)
				- settings  # 配置文件
				- url       # URL与函数(类)对应关系
				- wsgi      # 遵循WSIG规范(封装socketserver),uwsgi + nginx==>上线
							支持的wsgi接口都要哪些?
						    'cgi': CGIServer,
						    'flup': FlupFCGIServer,
						    'wsgiref': WSGIRefServer,
						    'waitress': WaitressServer,
						    'cherrypy': CherryPyServer,
						    'paste': PasteServer,
						    'fapws3': FapwsServer,
						    'tornado': TornadoServer,
						    'gae': AppEngineServer,
						    'twisted': TwistedServer,
						    'diesel': DieselServer,
						    'meinheld': MeinheldServer,
						    'gunicorn': GunicornServer,
						    'eventlet': EventletServer,
						    'gevent': GeventServer,
						    'geventSocketIO':GeventSocketIOServer,
						    'rocket': RocketServer,
						    'bjoern' : BjoernServer,
						    'auto': AutoServer,
			- manage.py     # 管理Django程序:
								- python manage.py
								- python manage.py startapp xx 创建app
								- python manage.py makemigrations  创建数据库  orm:关系对象映射
								- python manage.py migrate     类自动生成数据表

	# 运行Django功能(进入工程目录)
	python manage.py runserver 127.0.0.1:8001
	未加环境变量:C:\Python35\python.exe manage.py runserver 127.0.0.1:8001

	chouti
		- chouti
			- 配置
		- 主站 app
		- 后台管理 app

	# 创建app
	python manage.py startapp cmdb
	python manage.py startapp openstack
	python manage.py startapp xxoo....

	app:
		migrations     数据修改表结构(插入数据、修改数据不记录)
		admin          Django为我们提供的后台管理
			(1)创建数据库类
			(2)生成数据库表:
				python manage.py makemigrations
				python manage.py migrate
			(3)配置:
				admin.site.register(models.UerInfo(数据库创建的类))
				admin.site.register(models.UerType(数据库创建的类))
			(4)创建数据
				python manage.py createsuperuser
		apps           配置当前app,添加到INSTALLED_APPS列表中
		models         ORM,写指定的类  通过命令可以创建数据库结构
		tests          单元测试
		views          业务代码

	1、配置模板的路径
		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',
						],
					},
				},
			]
	2、配置静态目录
		static

		STATICFILES_DIRS = (
			os.path.join(BASE_DIR, 'static'),  ==》 注意,
		)

		<link rel="stylesheet" href="/static/commons.css" />
	3、app路径配置添加 INSTALLED_APPS = []

内容整理
	1. 创建Django工程
			django-admin startproject 工程名

	2. 创建APP
		cd 工程名
		python manage.py startapp cmdb

	3、静态文件
		project.settings.py

		STATICFILES_DIRS = (
			os.path.join(BASE_DIR, "static"),
		)

	4、模板路径

		DIRS ==>    [os.path.join(BASE_DIR,'templates'),]

	5、settings中

		middlerware

			# 注释 csrf

	6、定义路由规则
		url.py

			"login" --> 函数名

	7、定义视图函数
		app下views.py

			def func(request):
				# request.method   GET / POST

				# http://127.0.0.1:8009/home?nid=123&name=alex
				# request.GET.get('',None)   # 获取url请求发来的数据

				# request.POST.get('',None)

				返回数据:return 一定要用Django的函数
				# return HttpResponse("字符串"或字节bytes)
				# return render(request, "HTML模板的路径")
				# return redirect('/只能填URL')     / : 域名
		Ctrl+S:修改业务代码时,自动保存重启服务
		拓展:res=HttpResponse('Ok')--->res['name']='uson'这种方式会把name加入到响应头信息中
	8、模板渲染
		特殊的模板语言

			-- {{ 变量名 }}

				def func(request):
					return render(request, "index.html", {'current_user': "alex"})


				index.html

				<html>
				..
					<body>
						<div>{{current_user}}</div>
					</body>

				</html>

				====> 最后生成的字符串

				<html>
				..
					<body>
						<div>alex</div>
					</body>

				</html>
			-- For循环
				def func(request):
					return render(request, "index.html", {'current_user': "alex", 'user_list': ['alex','eric']})


				index.html

				<html>
				..
					<body>
						<div>{{current_user}}</div>

						<ul>
							{% for row in user_list %}

								{% if row == "alex" %}
									<li>{{ row }}</li>
								{% endif %}

							{% endfor %}
						</ul>

					</body>

				</html>

			#####索引#################
				def func(request):
					return render(request, "index.html", {
								'current_user': "alex",
								'user_list': ['alex','eric'],
								'user_dict': {'k1': 'v1', 'k2': 'v2'}})


				index.html

				<html>
				..
					<body>
						<div>{{current_user}}</div>

						<a> {{ user_list.1 }} </a>
						<a> {{ user_dict.k1 }} </a>
						<a> {{ user_dict.k2 }} </a>

					</body>

				</html>

			###### 条件

				def func(request):
					return render(request, "index.html", {
								'current_user': "alex",
								"age": 18,
								'user_list': ['alex','eric'],
								'user_dict': {'k1': 'v1', 'k2': 'v2'}})


				index.html

				<html>
				..
					<body>
						<div>{{current_user}}</div>

						<a> {{ user_list.1 }} </a>
						<a> {{ user_dict.k1 }} </a>
						<a> {{ user_dict.k2 }} </a>

						{% if age %}
							<a>有年龄</a>
							{% if age > 16 %}
								<a>老男人</a>
							{% else %}
								<a>小鲜肉</a>
							{% endif %}
						{% else %}
							<a>无年龄</a>
						{% endif %}
					</body>

				</html>

XXOO管理:
	MySQL
	SQLAlchemy
	主机管理(8列):
		IP
		端口
		业务线
		...

	用户表:
		用户名
		密码

	功能:
		1、 登录
		2、主机管理页面
			- 查看所有的主机信息(4列)
			- 增加主机信息(8列) ** 模态对话框
		3、查看详细
			url:
				"detail" -> detail

			def detail(reqeust):
				nid = request.GET.get("nid")
				v = select * from tb where id = nid
				...
		4、删除
			del_host -> delete_host

			def delete_host(request):
				nid = request.POST.get('nid')
				delete from tb where id = nid
				return redirect('/home')

上节内容回顾:
	1、Django请求生命周期
		-> URL对应关系(匹配) -> 视图函数 -> 返回用户字符串
		-> URL对应关系(匹配) -> 视图函数 -> 打开一个HTML文件,读取内容

	2、创建django projcet

		django-admin startproject mysite

		..

		mysite
			mysite
				- 配置文件
				- url.py
				- settings.py

		cd mysite
		python manage.py startapp cmdb

		mysite
			mysite
				- 配置文件
				- url.py
				- settings.py
			cmdb
				- views.py
				- admin.py
				- models.py # 创建数据库表

	3、配置

		模板路径
		静态文件路径
		# CSRF

	4、编写程序

		a. url.py

			/index/    ->   func

		b. views.py

			def func(request):
				# 包含所有的请求数据
				...
				return HttpResponse('字符串')
				return render(request, 'index.html', {''})
				retrun redirect('URL')

		c. 模板语言
			return render(request, 'index.html', {'li': [11,22,33]})

			{% for item in li %}
				<h1>{{item}}</h1>
			{% endfor %}

			***********  索引用点 **********
			<h2> {{item.0 }} </h2>
		潜规则(一般规定):
			get:获取数据
			post:提交数据

一、路由系统,URL
	1、url(r'^index/', views.index),
	  url(r'^home/', views.Home.as_view()),
	2、url(r'^detail-(\d+).html', views.detail),
	3、url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)

	   PS:
			def detail(request, *args,**kwargs):
				pass

	   实战:
			a.
				url(r'^detail-(\d+)-(\d+).html', views.detail),

				def func(request, nid, uid):

					pass

				def func(request, *args):
					args = (2,9)


				def func(request, *args, **kwargs):
					args = (2,9)

			b.
				url(r'^detail-(?P<nid>\d+)-(?P<uid>\d+).html', views.detail)

				def func(request, nid, uid):
					pass

				def funct(request, **kwargs):
					kwargs = {'nid': 1, 'uid': 3}

				def func(request, *args, **kwargs):
					kwargs = {'nid': 1, 'uid': 3}
	4、 name

		对URL路由关系进行命名, ***** 以后可以根据此名称生成自己想要的URL *****

		url(r'^asdfasdfasdf/', views.index, name='i1'),
		url(r'^yug/(\d+)/(\d+)/', views.index, name='i2'),
		url(r'^buy/(?P<pid>\d+)/(?P<nid>\d+)/', views.index, name='i3'),


		def func(request, *args, **kwargs):
			from django.urls import reverse

			url1 = reverse('i1')                              # asdfasdfasdf/
			url2 = reverse('i2', args=(1,2,))                 # yug/1/2/
			url3 = reverse('i3', kwargs={'pid': 1, "nid": 9}) # buy/1/9/


		xxx.html

			{% url "i1" %}               # asdfasdfasdf/
			{% url "i2" 1 2 %}           # yug/1/2/
			{% url "i3" pid=1 nid=9 %}   # buy/1/9/

		注:
			# 当前的URL
			request.path_info
	5、多级路由

		project/urls.py
			from django.conf.urls import url,include
			from django.contrib import admin

			urlpatterns = [
				url(r'^cmdb/', include("app01.urls")),
				url(r'^monitor/', include("app02.urls")),
			]

		app01/urls.py
			from django.conf.urls import url,include
			from django.contrib import admin
			from app01 import views

			urlpatterns = [
				url(r'^login/', views.login),
			]

		app02/urls.py
			from django.conf.urls import url,include
			from django.contrib import admin
			from app02 import views

			urlpatterns = [
				url(r'^login/', views.login),
			]

	6、默认值(欠)

	7、命名空间(欠)

二、视图
	1、获取用户请求数据
		request.GET
		request.POST
		request.FILES
		PS:
			GET:获取数据
			POST:提交数据

	2、checkbox等多选的内容
		request.POST.getlist()
	3、上传文件
		# 上传文件,form标签做特殊设置
		obj = request.FILES.get('fafafa')
		obj.name
		f = open(obj.name, mode='wb')
		for item in obj.chunks(): 迭代器
			f.write(item)
		f.close()

	4、FBV & CBV
	   function base view

		url.py
			index -> 函数名

		view.py
			def 函数(request):
				...
		====》
		/index/ -> 函数名

		/index/ -> 类

		====》

		建议:两者都用

	5、装饰器
		欠

三、模板

四、ORM操作
	select * from tb where id > 1
	# 对应关系
	models.tb.objects.filter(id__gt=1)
	models.tb.objects.filter(id=1)
	models.tb.objects.filter(id__lt=1)

	创建类

	a. 先写类
		from django.db import models

		# app01_userinfo
		class UserInfo(models.Model):
			# id列,自增,主键
			# 用户名列,字符串类型,指定长度
			username = models.CharField(max_length=32)
			password = models.CharField(max_length=64)

	b. 注册APP

		INSTALLED_APPS = [
			'django.contrib.admin',
			'django.contrib.auth',
			'django.contrib.contenttypes',
			'django.contrib.sessions',
			'django.contrib.messages',
			'django.contrib.staticfiles',
			'app01',
		]
	c. 执行命令
		python manage.py  makemigrations
		python manage.py  migrate

	d. ********** 注意 ***********
		Django默认使用MySQLdb模块链接MySQL
		主动修改为pymysql,在project同名文件夹下的__init__文件中添加如下代码即可:
			import pymysql
			pymysql.install_as_MySQLdb()

	1. 根据类自动创建数据库表
		# app下的models.py

		python manage.py  makemigrations
		python manage.py  migrate

		字段:
			字符串类型
			数字
			时间
			二进制
			自增(primary_key=True)
		字段的参数:
			null               -> db是否可以为空
			default            -> 默认值
			primary_key        -> 主键
			db_column          -> 列名
			db_index           -> 索引
			unique			   -> 唯一索引
			unique_for_date    ->
			unique_for_month
			unique_for_year
			auto_now           -> 更新时,自动更新为当前时间
			auto_now_add       -> 创建时,自动生成时间

				# obj = UserGroup.objects.filter(id=1).update(caption='CEO')  更新的时间不生效
				# obj = UserGroup.objects.filter(id=1).first()    生效
				# obj.caption = "CEO"
				# obj.save()

			choices			  -> django admin中显示下拉框,避免连表查询
			blank             -> django admin是否可以为空
			verbose_name      -> django admin显示字段中文
			editable          -> django admin是否可以被编辑
			error_messages    -> 错误信息 (欠)
			help_text         -> django admin提示
			validators		  -> django form ,自定义错误信息(欠)


			创建 Django 用户:python manage.py createsuperuser

	2. 根据类对数据库表中的数据进行各种操作

		一对多:

			a. 外检
			b.
				外键字段_id
			c.
				models.tb.object.create(name='root', user_group_id=1)

			d.

				userlist = models.tb.object.all()
				for row in userlist:
					row.id
					row.user_group_id
					row.user_group.caption

	=================== 作业:用户管理 ====================
	1、用户组的增删改查
	2、用户增删该查
		- 添加必须是对话框
		- 删除必须是对话框
		- 修改,必须显示默认值

	3、比较好看的页面

	4、预习:
		http://www.cnblogs.com/wupeiqi/articles/5246483.html

课堂那些Low示例:

一级urls:

from django.contrib import admin
from django.urls import path, re_path, include

from cmdb import views

from django.conf.urls import url

# 一级路由
urlpatterns = [
    # 给每个app再创建一个urls文件
    # 测试访问地址:http://127.0.0.1:8008/cmdb/login
    # 测试访问地址:http://127.0.0.1:8008/monitor/login
    path('cmdb/', include('cmdb.urls')),     #cmdb:为一级目录    cmdb:为创建的app
    path('monitor/', include('app02.urls')), #monitor:为一级目录 app02:为创建的app

    ############################jsonp跨域发请求服务端示例##########################
    path('uson/', include('jsonp.urls')),
]

二级urls:

from django.contrib import admin
from django.urls import path, re_path

from cmdb import views

from django.conf.urls import url

# 二级路由
urlpatterns = [
    path(r'login', views.login),  # r: 防止转义,以login开头
    path(r'login2', views.login2),  # r: 防止转义,以login开头
    path(r'orm', views.orm),
    path(r'index2', views.index2),
    path(r'user_list2/', views.user_list2),
    re_path(r'userdetail-(?P<nid>\d+)/', views.userdetail2), #正则表达式:re_path
    re_path(r'userdel-(?P<nid>\d+)/', views.userdel2), #对应的url可以不写html,但需要一个函数处理
    re_path(r'useredit-(?P<nid>\d+)/', views.useredit2),

    path(r'orm2', views.orm2),
]

views:

from django.shortcuts import HttpResponse
# 免去open,close的所有文件操作
from django.shortcuts import render
from django.shortcuts import redirect

登录

 1 def login(request):
 2     # request:包含用户提交的所有信息
 3     # 获取用户提交的方法
 4     # print(request.method)
 5
 6     # return render(request, 'login.html') #request参数必须带上
 7     # settings文件里设置了自动去templates目录下找
 8
 9     msg_error = ''
10     if request.method == 'POST':
11         # 获取用户名
12         username = request.POST['user'] #name='user'
13         # 获取密码
14         pwd = request.POST['pwd'] #name = 'pwd'
15
16         if username == 'uson' and pwd == 'akaedu':
17             # return redirect('https://www.baidu.com')
18             return redirect('/index')
19         else:
20             msg_error = '用户名或密码错误'
21
22     return render(request, 'login.html', {"msg_error": msg_error})
23     # 特殊字符:html中,{{ }} ,匹配msg_error
24     # kao, 很大问题:浏览器不清楚缓存,django总是无错报错
views
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>登录界面</title>
 6     <link rel="stylesheet" href="/static/commons.css" />
 7     <style>
 8         label{
 9             width: 80px;
10             display: inline-block;
11             text-align: right;
12         }
13         .lButton{
14             margin-left: 82px;
15         }
16     </style>
17 </head>
18 <body>
19     <div class="login">
20 {#        <form action="/login/" method="post">#} <!--path('login/', views.login),-->
21         <form action="/login" method="post"> <!--path('login', views.login),-->
22             <p>
23                 <label for="username" >用户名:</label>     <!-- 行内标签 -->
24                 <input id="username" name="user" type="text" />       <!-- 行内标签 -->
25             </p>
26             <p>
27                 <label for="pwd" >密 码:</label>
28                 <input id="pwd" name="pwd" type="password" />
29             </p>
30             <div class="lButton">
31                 <input type="submit" value="立即登录" />
32                 <span style="color: red;">{{ msg_error }}</span>
33             </div>
34         </form>
35     </div>
36
37     <script src="/static/jquery.min.js"></script>
38 </body>
39 </html>
login
 1 INFO_L = []
 2 # 必须是全局变量,每次追加才能保存数据
 3 # 否则,每次只能追加一行
 4 info_list = [
 5         {'name': 'alex', 'email': 'alex3714@126.com', 'gender': ''},
 6         {'name': 'uson', 'email': 'uson@126.com', 'gender': ''},
 7         {'name': 'cohui', 'email': 'cohui@126.com', 'gender': ''},
 8     ]
 9
10 def index(request):
11     # for i in range(20):
12     #     temp = {'name': 'alex' + str(i), 'email': 'alex3714@126.com', 'gender': '男'}
13     #     INFO_L.append(temp)
14
15     if request.method == "POST":
16         # 获取POST请求中用户提交的数据
17         u = request.POST.get('user', None)
18         e = request.POST.get('email', None)
19         g = request.POST.get('gender', None)
20         temp = {'name': u, 'email': e, 'gender': g}
21         info_list.append(temp)
22
23     # return render(request, 'index.html', {'info_list': info_list, 'info_l': INFO_L})
24     return render(request, 'index.html', {'info_list': info_list})
views
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>主页界面</title>
 6     <link rel="stylesheet" href="/static/commons.css" />
 7     <style>
 8         .lButton{
 9             padding: 0 0 10px 0;
10         }
11     </style>
12 </head>
13 <body>
14     <div class="login">
15         <form action="/index" method="post">
16             <p>
17                 <input id="username" name="user" type="text" placeholder="用户名" />
18             </p>
19             <p>
20                 <input id="email" name="email" type="text" placeholder="邮箱" />
21             </p>
22             <p>
23                 <input id="gender" name="gender" type="text" placeholder="性别" />
24             </p>
25             <div class="lButton">
26                 <input type="submit" value="立即添加" />
27             </div>
28         </form>
29         {# 模板语言for循环 #}
30         <table border="1">
31             {% for row in info_list %}
32                 <tr>
33                     <td>{{ row.name }}</td>
34                     <td>{{ row.email }}</td>
35                     <td>{{ row.gender }}</td>
36                 </tr>
37             {% endfor %}
38 {#            {% for r in info_l %}#}
39 {#                <tr>#}
40 {#                    <td>{{ r.name }}</td>#}
41 {#                    <td>{{ r.email }}</td>#}
42 {#                    <td>{{ r.gender }}</td>#}
43 {#                </tr>#}
44 {#            {% endfor %}#}
45         </table>
46     </div>
47     <script src="/static/jquery.min.js"></script>
48 </body>
49 </html>
index

多选、上传文件

 1 # 下拉框,多选,上传文件
 2 def reg(request):
 3     if request.method == "POST":
 4         # value = request.POST.get('gender', None) #单选,单值
 5         # value = request.POST.getlist('skill', None) #多选,多值
 6         obj = request.FILES.get('filename') #文件
 7         print(obj, type(obj), obj.name)
 8         #   2019年暑假衔接课课表及名单.pdf
 9         #  <class 'django.core.files.uploadedfile.InMemoryUploadedFile'>
10         from django.core.files.uploadedfile import InMemoryUploadedFile
11         # def chunks(self, chunk_size=None):
12         # def open(self, mode=None):
13         # def __str__  ===> return返回的是obj.name = 即实例化后传给了obj对象,所以obj=文件名;
14         # 另外:__str__优先于__repr__
15         import os
16         # 文件上传路径
17         filepath = os.path.join('upload', obj.name)
18         # 打开文件
19         f = open(filepath, mode='wb')
20         #一点一点上传内容,只要有yield,此时,chunks()是一个迭代器,内存中还不存在,next时才存在
21         for item in obj.chunks():
22             f.write(item)
23         f.close()
24
25     return render(request, 'reg.html')
views
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <form action="/reg" method="post" enctype="multipart/form-data">
 9         <div>
10             男:<input type="radio" name="gender" value="1" />
11             女:<input type="radio" name="gender" value="2" />
12         </div>
13         <div>
14             python开发:<input type="checkbox" name="skill" value="11" />
15             C开发:<input type="checkbox" name="skill" value="22" />
16             Java开发:<input type="checkbox" name="skill" value="33" />
17         </div>
18         <div>
19             <input type="file" name="filename" value="66" />
20         </div>
21         <input type="submit" value="提交" />
22     </form>
23 </body>
24 </html>
reg

 1 from django.views import View
 2 class Home(View):
 3     # http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']
 4     # 自定义功能
 5     def dispatch(self, request, *args, **kwargs):
 6         print('before')
 7
 8         # 继承父类的功能
 9         # 父类的dispatch(super...)去判断执行get还是post
10         result = super(Home, self).dispatch(request, *args, **kwargs)
11
12         print('after')
13         # get/post返回结果会给super, super(即dispatch)再把结果返回给用户
14         return result
15
16     # get和post执行之前,都会先执行dispatch方法
17     def get(self, request):
18         print('Get')
19         return render(request, 'home.html')   # 实际是返回给dispatch
20     def post(self, request):
21         print('POST')
22         return render(request, 'home.html')  # 实际是返回给dispatch
views
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <form action="/home/" method="post" enctype="multipart/form-data">
 9         <div>
10             男:<input type="radio" name="gender" value="1" />
11             女:<input type="radio" name="gender" value="2" />
12         </div>
13         <div>
14             python开发:<input type="checkbox" name="skill" value="11" />
15             C开发:<input type="checkbox" name="skill" value="22" />
16             Java开发:<input type="checkbox" name="skill" value="33" />
17         </div>
18         <div>
19             <input type="file" name="filename" value="66" />
20         </div>
21         <input type="submit" value="提交" />
22     </form>
23 </body>
24 </html>
home

html模板字典的循环

 1 list_dict = {
 2     'k1': 'root1',
 3     'k2': 'root2',
 4     'k3': 'root3',
 5     'k4': 'root4',
 6     'k5': 'root5',
 7     'k6': 'root6',
 8 }
 9 LIST_DICT_M = {
10     '0': {'name': 'uson', 'email': 'uson@126.com'},
11     '1': {'name': 'cohui', 'email': 'cohui@126.com'},
12     '2': {'name': 'fang', 'email': 'fang@126.com'},
13     '3': {'name': 'zhou', 'email': 'zhou@126.com'},
14     '4': {'name': 'han', 'email': 'han@126.com'},
15     '5': {'name': 'wei', 'email': 'wei@126.com'},
16 }
17 def dict(request):
18     return render(request, 'dict.html', {'list_dict': list_dict, 'LIST_DICT_M': LIST_DICT_M})
views
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     {{ list_dict.k1 }}  {# 取值:value #}
 9     <ul>
10         {% for foo in list_dict %}  {# 字典: list_dict = {k1:root} #}
11             <li>{{ foo }}</li>  {# foo = k1... #}
12         {% endfor %}
13         <p>##############</p>
14         {% for foo in list_dict.keys %} {# 默认就是keys #}
15             <li>{{ foo }}</li>  {# foo = k1... #}
16         {% endfor %}
17         <p>**************</p>
18         {% for foo in list_dict.values %} {# 默认就是keys #}
19             <li>{{ foo }}</li>  {# foo = root1... #}
20         {% endfor %}
21         <p>¥¥¥¥¥¥¥¥¥</p>
22         {% for foo in list_dict.items %}  {# key, value #}
23             <li>{{ foo }}</li>  {# foo = ('k6', 'root6')... #}
24         {% endfor %}
25          <p>$$$$$$$$$$$$$</p>
26         {% for k, foo in list_dict.items %}  {# key, value #}
27             <li>{{ k }} ¥ {{ foo }}</li>  {# foo = k6 ¥ root6... #}
28         {% endfor %}
29         <p style="color: red;">查看详情内容示例-1(动态)</p>
30         <p style="color: red;">&&&&&&&&&&&&&&</p>
31         {# 字典:LIST_DICT_M =  { 0: {name:uson, email: uson@126.com}  ...}  #}
32         {% for k, info in LIST_DICT_M.items %}
33             <li><a target="_blank" href="/details?nid={{ k }}">{{ info.name }}</a></li>  {# k = 0... #}
34         {% endfor %}
35         <p style="color: red;">url正则匹配,查看详情内容示例-2(静态)</p>
36         <p style="color: red;">$$$$$$$$$$$$$$$$$</p>
37         {% for k, info in LIST_DICT_M.items %}
38             <li><a target="_blank" href="/details-{{ k }}.html">{{ info.name }}</a></li>  {# k = 0... #}
39         {% endfor %}
40     </ul>
41 </body>
42 </html>
dict

路由命名

1 def rename(request, *args, **kwargs):
2     v = request.path_info
3     print(v) #/renamessdsfsd-2-8/
4     return render(request, 'rename.html', {'request.path_info': v})
views
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <form action="{% url 'det' nid=1 uid=2 %}" method="post" enctype="multipart/form-data">
 9         <div>
10             男:<input type="radio" name="gender" value="1" />
11             女:<input type="radio" name="gender" value="2" />
12         </div>
13         <div>
14             python开发:<input type="checkbox" name="skill" value="11" />
15             C开发:<input type="checkbox" name="skill" value="22" />
16             Java开发:<input type="checkbox" name="skill" value="33" />
17         </div>
18         <div>
19             <input type="file" name="filename" value="66" />
20         </div>
21         <input type="submit" value="提交" />
22     </form>
23 </body>
24 </html>
rename

models:

 1 from django.db import models
 2
 3 # Create your models here.
 4
 5 from django.db import models
 6
 7 # 创建用户组
 8 class UserGroup(models.Model):
 9     uid = models.AutoField(primary_key=True)
10     caption = models.CharField(max_length=32)
11
12 # 创建用户
13 class Userinfo(models.Model): #必须继承django的父类
14     # 默认隐藏了id列,自增,且为主键
15     name = models.CharField(max_length=32)
16     password = models.CharField(max_length=64)
17
18     # user_group = models.ForeignKey('UserGroup', to_field='uid', default=1, on_delete=1)   # to_field默认是主键
19     user_group = models.ForeignKey('UserGroup', to_field='uid', on_delete=1)   # to_field默认是主键
20     # user_group 自动生成为user_group_id
21
22     # email = models.EmailField()
23     # memo = models.TextField()
24     user_type_choice = (
25         (1, '黄金用户'),
26         (2, '钻石用户'),
27         (3, '普通用户'),
28     )
29     user_type_id = models.IntegerField(choices=user_type_choice, default=3)
30 # 添加APP
31 # python manage.py makemigrations
32 # python manage.py migrate
33 # 表名: cmdb_userinfo
34
35 # 使用navicat premium软件查看
36 # 数据库文件: D:/python/cohui/WebSiteOne/db.sqlite3
37 # 连接名:WebSiteOne
38 # 双击表名打开查看
models

orm基本操作

 1 # 数据库创建数据
 2 from cmdb import models #指定数据库文件名
 3 def orm(request):
 4     # 创建
 5     # 方法1
 6     # models.Userinfo.objects.create(name='uson', password='123')
 7     # 方法2
 8     # dict = {'name': 'cohui', 'password': '345'}
 9     # models.Userinfo.objects.create(**dict)
10     # 方法3
11     # obj = models.Userinfo(name='Uson', password='123')
12     # obj.save()
13     # return HttpResponse('orm')
14
15     #
16     result = models.Userinfo.objects.all()       # 1)   列表
17     result = models.Userinfo.objects.filter(name='uson')       # 2)   列表
18     # result = models.Userinfo.objects.filter(name='uson').first()   # 3) 对象(单条数据)
19     # result = models.Userinfo.objects.get(name='uson')  # 4) 对象(单条数据) 不存在,报错,try
20     # print(result)
21     # print(result.query) #可以查看该句的SQL语句:SELECT ...
22     #  <QuerySet [<Userinfo: Userinfo object (1)>,
23     #  [<Userinfo: Userinfo object (2)>, <Userinfo: Userinfo object (3)>]
24     # result: QuerySet类型 --》 Django --> [obj, ...],列表里是一个一个的对象
25     for row in result:
26         print(row.id, row.name, row.password)
27     # return HttpResponse('orm')
28
29     #
30     # models.Userinfo.objects.all().delete()
31     # models.Userinfo.objects.filter(password=123).delete()
32     # return HttpResponse('orm')
33
34     # 改、更新
35     # models.Userinfo.objects.update(password='666')
36     # models.Userinfo.objects.filter(name='uson').update(name='Cohui')
37     return HttpResponse('orm')
views

orm-登录验证

 1 # 登录验证(数据库) 示例
 2 def login2(request):
 3     msg_error = ''
 4     if request.method == 'POST':
 5         username = request.POST['user']
 6         pwd = request.POST['pwd']
 7         # if username == 'uson' and pwd == 'akaedu':
 8         #通过数据库验证
 9         obj = models.Userinfo.objects.filter(name=username, password=pwd).first()   # 3) 对象(单条数据)
10         # result = models.Userinfo.objects.get(name='uson')  # 4) 对象(单条数据) 不存在,报错,try
11         if obj:
12             return redirect('/cmdb/index2')
13         else:
14             msg_error = '用户名或密码错误'
15     return render(request, 'login2.html', {"msg_error": msg_error})
views
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>登录界面-2</title>
 6     <link rel="stylesheet" href="/static/commons.css" />
 7     <style>
 8         label{
 9             width: 80px;
10             display: inline-block;
11             text-align: right;
12         }
13         .lButton{
14             margin-left: 82px;
15         }
16     </style>
17 </head>
18 <body>
19     <div class="login">
20         <form action="/cmdb/login2" method="post">
21             <p>
22                 <label for="username" >用户名:</label>
23                 <input id="username" name="user" type="text" />
24             </p>
25             <p>
26                 <label for="pwd" >密 码:</label>
27                 <input id="pwd" name="pwd" type="password" />
28             </p>
29             <div class="lButton">
30                 <input type="submit" value="立即登录" />
31                 <span style="color: red;">{{ msg_error }}</span>
32             </div>
33         </form>
34     </div>
35     <script src="/static/jquery.min.js"></script>
36 </body>
37 </html>
login2

orm-用户列表

 1 def user_list2(request):
 2     if request.method == "GET":
 3         user_list_obj = models.Userinfo.objects.all()   #[obj, obj, ...]
 4         group_list_obj = models.UserGroup.objects.all()
 5         return render(request, 'user_list2.html', {'user_list_obj': user_list_obj, 'group_list_obj': group_list_obj})
 6     elif request.method == "POST":
 7         # 1)增加、查找 -示例
 8         u = request.POST.get('username')
 9         p = request.POST.get('password')
10         # 写到数据库
11         models.Userinfo.objects.create(name=u, password=p)
12         # 从数据库中,查找数据,显示到网页
13         obj = models.Userinfo.objects.all()
14         return render(request, 'user_list2.html', {'user_list_obj': obj})
views
  1 <!DOCTYPE html>
  2 <html lang="en">
  3
  4 <!--第一种布局方式:
  5     fixed + overflow
  6 -->
  7 <head>
  8     <meta charset="UTF-8">
  9     <title>Title</title>
 10     <style>
 11         body{
 12             margin: 0;
 13         }
 14         .pg-header{
 15             background-color: #a6e1ec;
 16             height: 48px;
 17             line-height: 48px;
 18         }
 19         .pg-body{
 20             /*height: 6000px;*/
 21             /*background-color: #d5d5d5;*/
 22             margin-top: 48px;
 23         }
 24         .pg-body .Lmenu{
 25             background-color: #d5d5d5;
 26             width: 200px;
 27
 28             /*第一种布局方式*/
 29             position: fixed;
 30             left: 0;
 31             bottom: 0;
 32             top: 48px;
 33             overflow: auto;
 34
 35             /*width: 20%;*/
 36             /*min-width: 200px;*/
 37         }
 38
 39         .pg-body .Lmenu .userlist{
 40         }
 41         .pg-body .Rcontent{
 42             background-color: #E6E6FA;
 43             /*width: 80%;*/
 44
 45             position: fixed;
 46             right: 0;
 47             top: 48px;
 48             bottom: 0;
 49             left: 200px;
 50             overflow: auto;
 51         }
 52         .pg-body .Rcontent .content{
 53             background-color: #E6E6FA;
 54         }
 55         .pg-footer{
 56         }
 57     </style>
 58 </head>
 59 <body>
 60     <div class="pg-header"></div>
 61     <div  class="pg-body">
 62         <!--左-->
 63         <div class="Lmenu">
 64             <div class="userlist"><a href="/cmdb/user_list2/">用户列表</a></div>
 65             <div class="userlist">用户管理</div>
 66         </div>
 67         <!--右-->
 68         <div class="Rcontent">
 69             <div class="content">
 70                 <div>
 71                     <form action="/cmdb/user_list2/" method="post">
 72                         <input type="text" name="username" />
 73                         <input type="password" name="password" />
 74                         <select name="usergroup">
 75                             {% for foo in group_list_obj %}
 76                                 <option value="{{ foo.uid }}">{{ foo.caption }}</option>
 77                             {% endfor %}
 78
 79                         </select>
 80                         <input type="submit" value="添加" />
 81                     </form>
 82                 </div>
 83                 <h1>用户列表</h1>
 84                 <ul>
 85                     {% for user in user_list_obj %}
 86                         <li>
 87                             <a href="userdetail-{{ user.id }}/">{{ user.name }}</a> |
 88                             <span>{{ user.user_group.caption }}</span> |
 89                             <a href="userdel-{{ user.id }}">删除</a> |
 90                             <a href="useredit-{{ user.id }}/">编辑</a> <!-- 在另一页面做修改 -->
 91                         </li>
 92 {#                        <li>{{ user.name }}</li>#}
 93                     {% endfor %}
 94                 </ul>
 95             </div>
 96         </div>
 97     </div>
 98     <div  class="pg-footer"></div>
 99 </body>
100 </html>
user_list2

orm-用户详细

1 def userdetail2(request, nid):
2     obj = models.Userinfo.objects.filter(id=nid).first() #obj
3     return render(request, 'userdetail2.html', {'obj': obj})
views
 1 <!DOCTYPE html>
 2 <html lang="en">
 3
 4 <!--第一种布局方式:
 5     fixed + overflow
 6 -->
 7 <head>
 8     <meta charset="UTF-8">
 9     <title>Title</title>
10     <style>
11         body{
12             margin: 0;
13         }
14         .pg-header{
15             background-color: #a6e1ec;
16             height: 48px;
17             line-height: 48px;
18         }
19         .pg-body{
20             /*height: 6000px;*/
21             /*background-color: #d5d5d5;*/
22             margin-top: 48px;
23         }
24         .pg-body .Lmenu{
25             background-color: #d5d5d5;
26             width: 200px;
27
28             /*第一种布局方式*/
29             position: fixed;
30             left: 0;
31             bottom: 0;
32             top: 48px;
33             overflow: auto;
34
35             /*width: 20%;*/
36             /*min-width: 200px;*/
37         }
38
39         .pg-body .Lmenu .userlist{
40         }
41         .pg-body .Rcontent{
42             background-color: #E6E6FA;
43             /*width: 80%;*/
44
45             position: fixed;
46             right: 0;
47             top: 48px;
48             bottom: 0;
49             left: 200px;
50             overflow: auto;
51         }
52         .pg-body .Rcontent .content{
53             background-color: #E6E6FA;
54         }
55         .pg-footer{
56         }
57     </style>
58 </head>
59 <body>
60     <div class="pg-header"></div>
61     <div  class="pg-body">
62         <!--左-->
63         <div class="Lmenu">
64             <div class="userlist"><a href="/cmdb/user_list2/">用户列表</a></div>
65             <div class="userlist">用户管理</div>
66         </div>
67         <!--右-->
68         <div class="Rcontent">
69             <div class="content">
70                 <h1>用户详细信息</h1>
71                 <ul>
72                     <li>{{ obj.id }}</li>
73                     <li>{{ obj.name }}</li>
74                     <li>{{ obj.password }}</li>
75                 </ul>
76             </div>
77         </div>
78     </div>
79     <div  class="pg-footer"></div>
80 </body>
81 </html>
userdetail2

orm-删除

1 def userdel2(request, nid):
2     # 2)删除 示例
3     models.Userinfo.objects.filter(id=nid).delete()
4     return redirect('/cmdb/user_list2/')
views

orm-编辑

 1 def useredit2(request, nid):
 2     # 3) 编辑
 3     if request.method == "GET":
 4         obj = models.Userinfo.objects.filter(id=nid).first()
 5         return render(request, 'user_edit2.html', {'obj': obj})
 6     elif request.method == 'POST':
 7         u = request.POST.get('name')
 8         p = request.POST.get('password')
 9         models.Userinfo.objects.filter(id=nid).update(name=u, password=p)
10         return redirect('/cmdb/user_list2') #跳转到列表页,而不是html页(编辑替换特殊字符页)
views
 1 前面都一样,部分html代码
 2         <!--右-->
 3         <div class="Rcontent">
 4             <div class="content">
 5                 <div>
 6                     <form action="/cmdb/useredit-{{ obj.id }}/" method="post">  <!--仅名字与url保持一致-->
 7 {#                        <input style="dispaly: none" type="text" name="id" value="{{ obj.id }}"/>#}
 8                         <input type="text" name="name" value="{{ obj.name }}" />
 9                         <input type="text" name="password" value="{{ obj.password }}" />
10                         <input type="submit" value="提交" />
11                     </form>
12                 </div>
13             </div>
14         </div>
user_edit2

orm-创建数据

1 # 给用户组创建数据
2 def orm2(request):
3     models.UserGroup.objects.create(caption='CEO')
4     return redirect('/cmdb/index2')
views

JsonP示例:

# 二级路由
urlpatterns = [
    path(r'jsonp', views.jsonp),
]
 1 from django.shortcuts import render, HttpResponse, redirect
 2
 3 # Create your views here.
 4 def jsonp(request):
 5     print(request.GET)  # <QueryDict: {'key': ['uson'], 'pwd': ['akaedu']}>
 6
 7     # return HttpResponse('OK') # 返回数据中js无法解析OK字符串
 8     # return HttpResponse('alert("12345")')
 9
10     func = request.GET.get('call') # 获取javascript的src链接,即js中会以此名作为函数解析
11     # content = func('uson学Python')  # X
12     content = "%s('uson学Python')" %(func,)        # 传字符串
13
14     return HttpResponse(content) # 返回到javascript标签内,根据函数名会自动进行解析
views
1 ALLOWED_HOSTS = [
2     'uson.com',
3 ]
settings

配置文件路径:

C:\Windows\System32\drivers\etc\hosts

基础2部分的笔记(ORM ajax基础)

1、Django请求的生命周期
	路由系统 -> 试图函数(获取模板+数据=》渲染) -> 字符串返回给用户

2、路由系统
	/index/                ->  函数或类.as_view()
	/detail/(\d+)          ->  函数(参数) 或 类.as_view()(参数)
	/detail/(?P<nid>\d+)   ->  函数(参数) 或 类.as_view()(参数)
	/detail/			   ->  include("app01.urls")
	/detail/    name='a1'  ->  include("app01.urls")
						   - 视图中:reverse
						   - 模板中:{% url "a1" %}

3、视图
	FBV:函数
		def index(request,*args,**kwargs):
			..

	CBV:类
		class Home(views.View):

			def get(self,reqeust,*args,**kwargs):
				..

	获取用户请求中的数据:
		request.POST.get
		request.GET.get
		reqeust.FILES.get()

		# checkbox,
		........getlist()

		request.path_info


		文件对象 = reqeust.FILES.get()
		文件对象.name
		文件对象.size
		文件对象.chunks()

		# <form 特殊的设置></form>


	给用户返回数据:
		render(request, "模板的文件的路径", {'k1': [1,2,3,4],"k2": {'name': '张扬','age': 73}})
		redirect("URL")
		HttpResponse(字符串)


4、模板语言
	render(request, "模板的文件的路径", {'obj': 1234, 'k1': [1,2,3,4],"k2": {'name': '张扬','age': 73}})

	<html>

	<body>
		<h1> {{ obj }} </h1>
		<h1> {{ k1.3 }} </h1>
		<h1> {{ k2.name }} </h1>
		{% for i in k1 %}
			<p> {{ i }} </p>
		{% endfor %}

		{% for row in k2.keys %}
			{{ row }}
		{% endfor %}

		{% for row in k2.values %}
			{{ row }}
		{% endfor %}

		{% for k,v in k2.items %}
			{{ k }} - {{v}}
		{% endfor %}

	</body>
	</html>

5、ORM
	a. 创建类和字段
		class User(models.Model):
			age = models.IntergerFiled()
			name = models.CharField(max_length=10)#字符长度

		Python manage.py makemigrations
		python manage.py migrate

		# settings.py 注册APP

	b. 操作
		增
			models.User.objects.create(name='qianxiaohu',age=18)
			dic = {'name': 'xx', 'age': 19}
			models.User.objects.create(**dic)


			obj = models.User(name='qianxiaohu',age=18)
			obj.save()
		删
			models.User.objects.filter(id=1).delete()
		改
			models.User.objects.filter(id__gt=1).update(name='alex',age=84)
			dic = {'name': 'xx', 'age': 19}
			models.User.objects.filter(id__gt=1).update(**dic)
		查
			models.User.objects.filter(id=1,name='root')
			models.User.objects.filter(id__gt=1,name='root')
			models.User.objects.filter(id__lt=1)
			models.User.objects.filter(id__gte=1)   大于等于
			models.User.objects.filter(id__lte=1)   小于等于

			models.User.objects.filter(id=1,name='root')
			dic = {'name': 'xx', 'age__gt': 19}
			models.User.objects.filter(**dic)      查询也可以传字典

			v1 = models.Business.objects.all()
			# QuerySet ,内部元素都是对象

			取固定列数
			# QuerySet ,内部元素都是字典
			v2 = models.Business.objects.all().values('id','caption')
			# QuerySet ,内部元素都是元组(取值注意顺序)
			v3 = models.Business.objects.all().values_list('id','caption')

			# 获取到的一个对象,如果不存在就报错
			models.Business.objects.get(id=1)
			对象或者None = models.Business.objects.filter(id=1).first()


			外键:
				v = models.Host.objects.filter(nid__gt=0)
				v[0].b.caption  ---->  通过.进行跨表

			values、values_list跨表操作(通过__):
				host_tuple = models.Host.objects.filter(nid__gt=0).values('nid', 'b__caption')
				for row in host_tuple:
            		print(row[nid], row[b__caption])
				host_tuple = models.Host.objects.filter(nid__gt=0).values_list('nid', 'b__caption')
				for row in host_tuple:
            		print(row[0], row[1])


		外键:
			class UserType(models.Model):
				caption = models.CharField(max_length=32)
		      id  caption
			# 1,普通用户
			# 2,VIP用户
			# 3, 游客

			class User(models.Model):
				age = models.IntergerFiled()
				name = models.CharField(max_length=10)#字符长度
				# user_type_id = models.IntergerFiled() # 没有约束,
				user_type = models.ForeignKey("UserType",to_field='id') # 约束,

			  name age  user_type_id
			# 张扬  18     3
			# 张A扬 18     2
			# 张B扬 18     2

6、Ajax
	$.ajax({
		url: '/host',
		type: "POST",
		data: {'k1': 123,'k2': "root"},
		headers: {"": ...}
		success: function(data){
			// data是服务器端返回的字符串
			var obj = JSON.parse(data);
		}
	})
	$.get(url='xx', data={}, function(){}, "json")、$.post()  本质上同$.ajax,只是改变一下type类型,但括号内不是传字典了
	$.get('', function(){}) 这种方式不能传递headers信息

	建议:永远让服务器端返回一个字典

	return HttpResponse(json.dumps(字典))

7、多对多:
    创建多对多:
		方式一:自定义关系表
			class Host(models.Model):
				nid = models.AutoField(primary_key=True)
				hostname = models.CharField(max_length=32,db_index=True)
				ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
				port = models.IntegerField()
				b = models.ForeignKey(to="Business", to_field='id')
			# 10
			class Application(models.Model):
				name = models.CharField(max_length=32)
			# 2

			class HostToApp(models.Model):
				hobj = models.ForeignKey(to='Host',to_field='nid')
				aobj = models.ForeignKey(to='Application',to_field='id')

			# HostToApp.objects.create(hobj_id=1,aobj_id=2)

		方式二:自动创建关系表(不能增加列,最多含id列,就是3列)
			class Host(models.Model):
				nid = models.AutoField(primary_key=True)
				hostname = models.CharField(max_length=32,db_index=True)
				ip = models.GenericIPAddressField(protocol="ipv4",db_index=True)
				port = models.IntegerField()
				b = models.ForeignKey(to="Business", to_field='id')
			# 10
			class Application(models.Model):
				name = models.CharField(max_length=32)
				r = models.ManyToManyField("Host")    主机对象“列表”,创建时,不是跟name一起创建,单独创建

			无法直接对第三张表进行操作

			# 第三张表操作(间接操作)
			obj = Application.objects.get(id=1)  ===》.first()
			obj.name

			obj.r.add(1)   (1,1)
			obj.r.add(2)   (1,2)
			obj.r.add(2,3,4) (1,2)(1,3)(1,4)
			obj.r.add(*[1,2,3,4])

			obj.r.remove(1)
			obj.r.remove(2,4)
			obj.r.remove(*[1,2,3])

			obj.r.clear() 删除所有1的对应数据

			obj.r.set([3,5,7]) 删除该id对应的所有关系,再添加set的关系id==》更新,保留

			# 所有相关的主机对象“列表” QuerySet
			obj.r.all()
			...

课堂那些Low示例:

urls:

# 二级路由
urlpatterns = [
    # path(r'login', views.login),  # r: 防止转义,以login开头

    # (1)单表操作
    # begins with a '^', or ends with a '$'
    url(r'^business$', views.business), #最好加上终止符$,否则永远都只匹配前面几个字母
    #     http://127.0.0.1:8008/monitor/business

    # (2)一对多表操作
    url(r'^host$', views.host),
    # url(r'^testajax$', views.testajax), #Ajax示例
    url(r'^testajax-(\w+)$', views.testajax), #Ajax示例   (ajax, add/edit)
    url(r'^host-del$', views.host_del),

    # (3)多对多表操作: Application 与 Host的关系表
    url(r'^app$', views.app),
    url(r'^app-ajax$', views.app_ajax),  #Ajax实现添加功能
    url(r'^app-ajax-edit$', views.app_ajax_edit),  #Ajax实现编辑功能
    url(r'^app-ajax-del$', views.app_ajax_del),  #Ajax实现删除功能

    url(r'^app_newurl_edit-(\d+)$', views.app_newurl_edit), #新URL方式实现编辑功能
]

models:

from django.db import models

# Create your models here.
class Business(models.Model):
    #id自增
    caption = models.CharField(max_length=32)
    # 新增英文列
    code = models.CharField(max_length=32, null=True)

class Host(models.Model):
    nid = models.IntegerField(primary_key=True) #自增
    hostname = models.CharField(max_length=32) #32个位字符,非字节
    ip = models.GenericIPAddressField(protocol='both', db_index=True) #索引
    port = models.IntegerField()

    # 单外键关联
    b = models.ForeignKey(to="Business", to_field='id', on_delete=models.CASCADE)
    # user=models.OneToOneField(User,on_delete=models.CASCADE)
    # --在老版本这个参数(models.CASCADE)是默认值
    '''
    on_delete有CASCADE、PROTECT、SET_NULL、SET_DEFAULT、SET()五个可选择的值
    CASCADE:此值设置,是级联删除。
    PROTECT:此值设置,是会报完整性错误。
    SET_NULL:此值设置,会把外键设置为null,前提是允许为null。
    SET_DEFAULT:此值设置,会把设置为外键的默认值。
    SET():此值设置,会调用外面的值,可以是一个函数。
    '''

class Application(models.Model):
    name = models.CharField(max_length=32)
    # 方式二:Django自动维护Host与Application
    r = models.ManyToManyField('Host')

# 方式一:创建第三张表维护Host与Application
'''
class HostToApp(models.Model):
    hobj = models.ForeignKey('Host', to_field='nid', on_delete=models.CASCADE)
    aobj = models.ForeignKey('Application', to_field='id', on_delete=models.CASCADE)
'''
 1 from app02 import models
 2
 3 # (0)单表操作************************************************
 4 def business(request):
 5     busi1 = models.Business.objects.all()
 6     # QuerySet 列表
 7     # [[obj(id,...)], [obj(id,...)]...]
 8     busi2 = models.Business.objects.all().values('id', 'caption')
 9     # QuerySet 字典
10     # [{'id':1, 'caption': 运维部}, {'id':1, 'caption': 运维部}, {}...]
11     busi3 = models.Business.objects.all().values_list('id', 'caption')
12     # QuerySet 元组
13     # [(1, 运维部), (1, 运维部), (1, 运维部),...]
14     return render(request, 'day20-app02/business.html', {'busi1': busi1, 'busi2': busi2, 'busi3': busi3})
单表操作
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6 </head>
 7 <body>
 8     <h1>业务线列表 (列表)</h1>
 9     <ul>
10         {% for foo in busi1 %}
11             <li>{{ foo.id }} - {{ foo.caption }} - {{ foo.code }}</li>
12         {% endfor %}
13
14     </ul>
15
16     <h1>业务线列表 (字典)</h1>
17     <ul>
18         {% for foo in busi2 %}
19             <li>{{ foo.id }} - {{ foo.caption }}</li>
20         {% endfor %}
21     </ul>
22
23     <h1>业务线列表 (元组)</h1>
24     <ul>
25         {% for foo in busi3 %}
26             <li>{{ foo.0 }} - {{ foo.1 }}</li>
27         {% endfor %}
28     </ul>
29 </body>
30 </html>
business
 1 # (1)一对多**************************************************
 2 # 模态框增加  √    Ajax增加  √
 3 # 新Url修改  X     Ajax修改  √
 4 #                 ajax删除  √
 5 ''' 6 def host(request):
 7     # *******************一对多块表操作的的三种方式************************
 8     # (1)对象
 9     host_obj = models.Host.objects.filter(nid__gt=0)
10     # print(host_obj)   #[<Host: Host object (1)>, <Host: Host object (2)>, <Host: Host object (3)>]
11     for row in host_obj:
12         print(row.nid, row.hostname, row.ip, row.port, row.b_id, row.b.caption, row.b.code, sep='\t\t')
13     # return HttpResponse('Host')
14
15
16     # (2)字典
17     host_dict = models.Host.objects.filter(nid__gt=0).values('nid', 'hostname', 'ip',
18                                                              'port', 'b_id', 'b__caption',
19                                                              'b__code')
20     # 跨表查询:__ --> str
21     for row in host_dict:
22         print(row['nid'], row['hostname'], row['ip'], row['port'], row['b_id'],
23               row['b__caption'], row['b__code'])
24
25     # (3)元组
26     # host_tuple = models.Host.objects.filter(nid__gt=0)  # 相当于.all()
27     host_tuple = models.Host.objects.filter(nid__gt=0).values_list('nid', 'hostname',
28                                                                    'ip', 'port', 'b_id',
29                                                                    'b__caption', 'b__code')
30     for row in host_tuple:
31         print(row[0], row[1], row[2], row[3], row[4], row[5], row[6])
32
33
34     return render(request, 'host.html', {'host_obj': host_obj, 'host_dict': host_dict,
35                                          'host_tuple': host_tuple})
36 '''
37 def host(request):
38     if request.method == "GET":
39         # *******************一对多块表操作的的三种方式************************
40         # (1)对象
41         host_obj = models.Host.objects.filter(nid__gt=0)
42         for row in host_obj:
43             print(row.nid, row.hostname, row.ip, row.port, row.b_id, row.b.caption, row.b.code, sep='\t\t')
44         # (2)字典
45         host_dict = models.Host.objects.filter(nid__gt=0).values('nid', 'hostname', 'ip',
46                                                                  'port', 'b_id', 'b__caption',
47                                                                  'b__code')
48         for row in host_dict:
49             print(row['nid'], row['hostname'], row['ip'], row['port'], row['b_id'],
50                   row['b__caption'], row['b__code'])
51         # (3)元组(取值注意顺序)
52         host_tuple = models.Host.objects.filter(nid__gt=0).values_list('nid', 'hostname',
53                                                                        'ip', 'port', 'b_id',
54                                                                        'b__caption', 'b__code')
55         for row in host_tuple:
56             print(row[0], row[1], row[2], row[3], row[4], row[5], row[6])
57
58
59         # 下拉框获取业务线的所有业务数据,通过主机表获取到的数据是有限的且是重复的
60         # 我们需要单独获取business的id
61         business_obj = models.Business.objects.all()
62
63         return render(request, 'day20-app02/host.html', {'host_obj': host_obj, 'host_dict': host_dict,
64                                              'host_tuple': host_tuple,
65                                              'business_obj': business_obj})
66     elif request.method == 'POST':
67         h = request.POST.get('hostname')
68         i = request.POST.get('ip')
69         p = request.POST.get('port')
70         b = request.POST.get('caption') #得到的是value值: b_id
71         # 创建数据
72         '''
73         models.Host.objects.create(hostname=h, ip=i, port=p,
74                                    # b=models.Business.objects.filter(id=b).first()
75                                    b=models.Business.objects.get(id=b) #对象=对象
76                                    )
77         '''
78         models.Host.objects.create(hostname=h, ip=i, port=p,
79                                    b_id=b,  # 数据=数据
80                                    )
81         # return render(request, 'host.html')
82         # 为了在提交数据后,页面显示新增数据和原先数据,可以两种方式:
83         # 1)把上面的GET代码,再复制过来,太麻烦,代码冗余
84         # 2)redirect到当前页面,get重新渲染
85         return redirect('/monitor/host') #url=能访问的链接地址
一对多操作
  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>Title</title>
  6     <link rel="stylesheet" href="/static/day20-app02/css.css" />
  7 </head>
  8 <body>
  9     <h1>*******************一对多块表操作的的三种方式************************</h1>
 10     <h1>主机列表(对象)</h1>
 11     <div>
 12         <input id="add-host" type="button" value="添加" />
 13     </div>
 14     <table border="1" style="text-align: center">
 15         <thead>
 16             <tr>
 17                 <!--<td>主机ID</td>-->
 18                 <td>主机名</td>
 19                 <td>主机IP</td>
 20                 <td>主机端口</td>
 21                 <!--<td>业务线ID</td>-->
 22                 <td>业务线部门</td>
 23                 <!--<td>业务线编码</td>-->
 24
 25                 <!-- 编辑 -->
 26                 <td>操作</td>
 27             </tr>
 28         </thead>
 29         <tbody>
 30         <!--
 31             {% for row in host_obj %}
 32                 <tr>{{ row.nid }}</tr>
 33                 <tr>{{ row.hostname }}</tr>
 34                 <tr>{{ row.ip }}</tr>
 35                 <tr>{{ row.port }}</tr>
 36                 <tr>{{ row.b_id }}</tr>
 37                 <tr>{{ row.b.caption }}</tr>
 38                 <tr>{{ row.b.code }}</tr>
 39             {% endfor %}
 40         -->
 41             {% for row in host_obj %}
 42             <tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
 43                 <!--<td>{{ row.nid }}</td>-->
 44                 <td>{{ row.hostname }}</td>
 45                 <td>{{ row.ip }}</td>
 46                 <td>{{ row.port }}</td>
 47                 <!--<td>{{ row.b_id }}</td>-->
 48                 <td>{{ row.b.caption }}</td>
 49                 <!--<td>{{ row.b.code }}</td>-->
 50
 51                 <!-- 编辑 -->
 52                 <td class="operate">
 53                     <span class="edithost">编辑</span>|<!--循环里面的事件,不能用id,id不能重复,只能用class-->
 54                     <a class="delete">删除</a>
 55                 </td>
 56             </tr>
 57             {% endfor %}
 58         </tbody>
 59     </table>
 60
 61     <h1>主机列表(字典)</h1>
 62     <table border="1" style="text-align: center">
 63         <thead>
 64             <tr>
 65                 <!--<td>主机ID</td>-->
 66                 <td>主机名</td>
 67                 <td>主机IP</td>
 68                 <td>主机端口</td>
 69                 <!--<td>业务线ID</td>-->
 70                 <td>业务线部门</td>
 71                 <!--<td>业务线编码</td>-->
 72             </tr>
 73         </thead>
 74         <tbody>
 75             {% for row in host_dict %}  <!-- python中的字典,在html中,对应的都是.取值-->
 76             <tr hid="{{ row.nid }}" bid="{{ row.b_id }}">
 77                 <!--<td>{{ row.nid }}</td>-->
 78                 <td>{{ row.hostname }}</td>
 79                 <td>{{ row.ip }}</td>
 80                 <td>{{ row.port }}</td>
 81                 <!--<td>{{ row.b_id }}</td>-->
 82                 <td>{{ row.b__caption }}</td>
 83                 <!--<td>{{ row.b__code }}</td>-->
 84             </tr>
 85             {% endfor %}
 86         </tbody>
 87     </table>
 88
 89     <h1>主机列表(元组)</h1>
 90     <table border="1" style="text-align: center">
 91         <thead>
 92             <tr>
 93                 <!--<td>主机ID</td>-->
 94                 <td>主机名</td>
 95                 <td>主机IP</td>
 96                 <td>主机端口</td>
 97                 <!--<td>业务线ID</td>-->
 98                 <td>业务线部门</td>
 99                 <!--<td>业务线编码</td>-->
100             </tr>
101         </thead>
102         <tbody>
103             {% for row in host_tuple %}  <!-- python中的字典,在html中,对应的都是.取值-->
104             <tr hid="{{ row.0 }}" bid="{{ row.4 }}">
105                 <!--<td>{{ row.0 }}</td>-->
106                 <td>{{ row.1 }}</td>
107                 <td>{{ row.2 }}</td>
108                 <td>{{ row.3 }}</td>
109                 <!--<td>{{ row.4 }}</td>-->
110                 <td>{{ row.5 }}</td>
111                 <!--<td>{{ row.6 }}</td>-->
112             </tr>
113             {% endfor %}
114         </tbody>
115     </table>
116
117     <!-- 以主机列表(对象)拓展,模态对话框 添加与删除可以共用,本示例分开做的模态对话框 -->
118     <div class="shade hide"></div>
119     <div class="modal hide">
120         <form action="/monitor/host" method="post">
121             <div class="add-host">
122                 <input type="text" placeholder="主机名" name="hostname" />
123             </div>
124             <div class="add-host">
125                 <input type="text" placeholder="主机IP" name="ip" />
126             </div>
127             <div class="add-host">
128                 <input type="text" placeholder="主机端口" name="port" />
129             </div>
130             <div class="add-host">
131                 <select name="caption">
132                     {% for row in business_obj %}
133                         <option value="{{ row.id }}">{{ row.caption }}</option>
134                     {% endfor %}
135                 </select>
136             </div>
137             <div>
138                 <input type="submit" value="提交">
139                 <input id="cancel" type="button" value="取消">
140                 <input id="ajax" type="button" value="Ajax悄悄提交">
141                 <span id="error" style="color: red;"></span>
142             </div>
143         </form>
144     </div>
145     <div class="edit-modal hide">
146         <form id="edit-form" action="/monitor/host" method="post">
147             <div class="edit-host">
148                 <input type="text" name="hostname" />
149                 <input style="display: none" type="text" name="hid" />
150             </div>
151             <div class="edit-host">
152                 <input type="text" name="ip" />
153             </div>
154             <div class="edit-host">
155                 <input type="text" name="port" />
156             </div>
157             <div class="edit-host">
158                 <select name="caption">
159                     {% for row in business_obj %}
160                         <option value="{{ row.id }}">{{ row.caption }}</option>
161                     {% endfor %}
162                 </select>
163             </div>
164             <div>
165                 <input type="submit" value="提交">
166                 <input class="cancel" type="button" value="取消">
167                 <input class="ajax" type="button" value="Ajax悄悄提交">
168                 <span class="error" style="color: red;"></span>
169             </div>
170         </form>
171     </div>
172
173
174     <script src="/static/day20-app02/jquery-1.12.4.js"></script>
175     <script>
176         $('#add-host').click(function(){
177            $('.shade, .modal').removeClass('hide')
178         });
179         $('#cancel').click(function(){
180            $('.shade, .modal').addClass('hide');
181         });
182         $('.cancel').click(function(){
183            $('.shade, .edit-modal').addClass('hide');
184         });
185
186         //Ajax提交示例
187
188         //初识ajax 示例
189         /*
190         $('#ajax').click(function () {
191             $.ajax({
192                //url: 'testajax',
193                url: '/monitor/testajax',
194                type: 'POST',
195                data: {'hostname': $('input[name="hostname"]').val(), 'ip': $('input[name="ip"]').val(),
196                         'port': $('input[name="port"]').val(),
197                         'caption': $('select[name="caption"]').val()},
198                success: function (data2) {
199                    //data2是服务端返回的字符串
200                    if(data2 === 'OK'){
201                        location.reload();
202                    }else{
203                        alert(data2);
204                    }
205                }
206             });
207         });
208         */
209         //ajax整理
210         $('#ajax').click(function () {
211             $.ajax({
212                 //url: 'testajax',
213                 url: '/monitor/testajax-add',
214                 type: 'POST',
215                 data: {'hostname': $('input[name="hostname"]').val(), 'ip': $('input[name="ip"]').val(),
216                         'port': $('input[name="port"]').val(),
217                         'caption': $('select[name="caption"]').val()},
218                 success: function (data2) {
219                    //data2是服务端返回的字符串<---python字典序列化后的字符串
220                    //data2 反序列化成字符串(对象:可以.获取值)
221                    var obj = JSON.parse(data2);
222                    if(obj.status){ //True
223                        {#console.log(obj);#}
224                        location.reload(); //刷新页面
225                    }else{  //False
226                        //获取html错误信息代码,text()
227                        //替换
228                        $('#error').text(obj.error_msg);
229                    }
230                }
231             });
232         });
233
234         //编辑 - 示例
235         $('.edithost').click(function(){
236            $('.shade, .edit-modal').removeClass('hide');
237
238            var nid = $(this).parent().parent().attr('hid'); //获取主键,用于ajax提交数据的
239             console.log("nid", nid);
240            $('#edit-form').children(':first').children(':last').val(nid);
241
242            var bid = $(this).parent().parent().attr('bid'); //获取主键
243             console.log("bid", bid);
244            $(this).parent().prevAll().each(function(){
245               var index = $(this).index();
246               var text = $(this).text();
247               console.log(index, text);
248               var selecttag = $('.edit-host').eq(index).children()[0].tagName;
249               console.log(selecttag);
250               if(selecttag === 'SELECT'){
251                   //var value = $(this).val();不是获取文字,而是获取编号bid
252                   $('.edit-host').eq(index).children(':first').val(bid); //select直接.val()获取值
253                   //val 实际就是option的value值:数字,不是文字
254               }else{
255                   $('.edit-host').eq(index).children(':first').val(text);
256               }
257               //console.log($('.edit-host').length)
258            });
259         });
260         $('.ajax').click(function () {
261             $.ajax({
262                 url: '/monitor/testajax-edit',
263                 type: 'POST',
264                 data: $('#edit-form').serialize(), //form把input,select...数据打包发至后台
265                 success: function (data2) {
266                     var obj = JSON.parse(data2);
267                     if (obj.status) { //True
268                         location.reload(); //刷新页面
269                     } else {  //False
270                         $('#error').text(obj.error_msg);
271                     }
272                 }
273             });
274         });
275
276         //删除 - 示例
277         $('.delete').click(function () {
278             var hid = $(this).parent().parent().attr('hid');
279             //删除确认
280             var v = confirm("请认真操作数据,本次为永久删除数据操作。");
281             if(v){
282                 //正在删除
283                 $.ajax({
284                     url: '/monitor/host-del',
285                     type: "POST",
286                     data: {'hid': hid},
287                     dataType: 'JSON',
288                     success: function (obj) {
289                         if(obj.status){
290                             location.reload();
291                         }else{
292                             alert('因为某种原因,无法删除。');
293                         }
294                     }
295                 });
296                 //console.log(hid);
297             }else{
298                 alert('已撤销数据删除操作!');
299             }
300         })
301     </script>
302 </body>
303 </html>
host
 1 # Ajax示例
 2 ''' #初识ajax
 3 def testajax(request):
 4     print(request.method)
 5     if request.method == "POST":
 6         h = request.POST.get('hostname')
 7         i = request.POST.get('ip')
 8         p = request.POST.get('port')
 9         b = request.POST.get('caption')
10         print(h, i, p ,b)
11         if h and len(h) > 3: #None不能直接len()
12             models.Host.objects.create(
13                 hostname=h,
14                 ip=i,
15                 port=p,
16                 b_id=b,
17             )
18             return HttpResponse('OK')
19         else:
20             return HttpResponse('太短了')
21 '''
22
23 # ajax整理,对上面用了Try    url(r'^testajax$', views.testajax), #Ajax示例
24 '''
25 def testajax(request):
26     import json
27     data_dict = {'status': True, 'error_msg': None, 'data': None}
28     if request.method == "POST":
29         try:
30             h = request.POST.get('hostname')
31             i = request.POST.get('ip')
32             p = request.POST.get('port')
33             b = request.POST.get('caption')
34             if h and len(h) > 3: #None不能直接len()
35                 models.Host.objects.create(
36                     hostname=h,
37                     ip=i,
38                     port=p,
39                     b_id=b,
40                 )
41                 # return HttpResponse(json.dumps(data_dict))
42             else:
43                 data_dict['error_msg'] = '太短了'
44                 data_dict['status'] = False
45                 # return HttpResponse(json.dumps(data_dict))
46         except Exception as e:
47             data_dict['error_msg'] = '不是太短了,有其他错误'
48             data_dict['status'] = False
49             # return HttpResponse(json.dumps(data_dict))
50         return HttpResponse(json.dumps(data_dict))
51 '''
52
53 # ajax整理,对上面的拓展(增改合并)    url(r'^testajax(\w+\d+)$', views.testajax), #Ajax示例
54 def testajax(request, type):
55     import json
56     data_dict = {'status': True, 'error_msg': None, 'data': None}
57     if request.method == "POST":
58         try:
59             h = request.POST.get('hostname')
60             i = request.POST.get('ip')
61             p = request.POST.get('port')
62             b = request.POST.get('caption')
63             if h and len(h) > 3: #None不能直接len()
64
65                 if type == 'add':
66                     models.Host.objects.create(
67                         hostname=h,
68                         ip=i,
69                         port=p,
70                         b_id=b,
71                     )
72                     # return HttpResponse(json.dumps(data_dict))
73                 elif type == 'edit':
74                     hid = request.POST.get('hid')
75                     models.Host.objects.filter(nid=hid).update(
76                         hostname=h,
77                         ip=i,
78                         port=p,
79                         b_id=b,
80                     )
81             else:
82                 data_dict['error_msg'] = '太短了'
83                 data_dict['status'] = False
84                 # return HttpResponse(json.dumps(data_dict))
85         except Exception as e:
86             data_dict['error_msg'] = '不是太短了,有其他错误'
87             data_dict['status'] = False
88             # return HttpResponse(json.dumps(data_dict))
89         return HttpResponse(json.dumps(data_dict))
90
91 # ajax删除
92 def host_del(request):
93     import json
94     host_dict = {'status': True, 'error_msg': None, 'data': None}
95     if request.method == 'POST':
96         hid = request.POST.get('hid')
97         print("Hid>>", hid)
98         models.Host.objects.filter(nid=hid).delete()
99         return HttpResponse(json.dumps(host_dict))
ajax一对多增删-基础
  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>Title</title>
  6     <link rel="stylesheet" href="/static/day20-app02/css.css" />
  7     <link rel="stylesheet" href="/static/font-awesome-4.7.0/css/font-awesome.min.css" />
  8     <style>
  9         /*这个只能写在这里,其他地方无效*/
 10         .apptohost{
 11             display: inline-block;
 12             padding: 3px 16px;
 13             background-color: green;
 14             color: white;
 15
 16             position: relative; /* 图标 */
 17         }
 18         .apptohost .font{
 19             display: none;
 20
 21             font-size: 0.8em;
 22             position: absolute;
 23             right: 3px;
 24             top: 3px;
 25         }
 26         .apptohost:hover .font{
 27             display: inline;
 28             cursor: pointer;
 29         }
 30     </style>
 31 </head>
 32 <body>
 33     <h1>Application与Host的多对多关系表</h1>
 34     <div>
 35         <input id="addapp" type="button" value="添加" />
 36     </div>
 37     <table border="1" style="text-align: center">
 38         <thead>
 39             <tr>
 40                 <th>应用名称</th>
 41                 <th>主机列表</th>
 42                 <th>操作</th>
 43             </tr>
 44         </thead>
 45         <tbody>
 46             <!-- 循环 -->
 47             {% for app in app_list %}
 48                 <tr aid="{{ app.id }}">
 49                     <td>{{ app.name }}</td>
 50
 51                     <!-- <td>{{ app.r.all }}</td> -->
 52                     <td>
 53                         {% for foo in app.r.all %} <!-- foo: 单个主机对象 -->
 54                             <span class="apptohost" hid="{{ foo.nid }}">{{ foo.hostname }} <i class="font fa fa-close"></i></span>
 55                         {% endfor %}
 56                     </td>
 57
 58                     <!-- 操作:编辑/删除 -->
 59                     <td>
 60                         <a class="edit">编辑</a> |
 61                         <a class="delete">删除</a>
 62                     </td>
 63
 64                 </tr>
 65             {% endfor %}
 66
 67         </tbody>
 68     </table>
 69
 70     <div class="shade hide"></div>
 71     <div class="modal hide">
 72         <form id="ajax-add-app" action="" method="post">
 73             <div class="add-app">
 74                 <input type="text" placeholder="应用名称名" name="appname" />
 75             </div>
 76             <div class="add-app">
 77                 <select name="host_list" multiple>
 78                     {% for row in host_list %}
 79                         <option value="{{ row.nid }}">{{ row.hostname }}</option>
 80                     {% endfor %}
 81                 </select>
 82             </div>
 83             <div>
 84                 <!-- <input type="submit" value="提交"> -->
 85                 <input id="cancel" type="button" value="取消">
 86
 87                 <input id="ajax" type="button" value="Ajax悄悄提交">
 88                 <span id="error" style="color: red;"></span>
 89             </div>
 90         </form>
 91     </div>
 92     <div class="edit-modal hide">
 93         <form class="ajax-edit-app" action="" method="post">
 94             <div class="edit-app">
 95                 <input type="text" name="appname" />
 96                 <input style="display: none" type="text" name="aid" />
 97             </div>
 98             <div class="edit-app">
 99                 <select name="host_list" multiple>
100                     {% for row in host_list %}
101                         <option value="{{ row.nid }}">{{ row.hostname }}</option>
102                     {% endfor %}
103                 </select>
104             </div>
105             <div>
106                 <!-- <input type="submit" value="提交"> -->
107                 <input class="cancel" type="button" value="取消">
108
109                 <input class="ajax" type="button" value="Ajax悄悄提交">
110                 <span class="error" style="color: red;"></span>
111             </div>
112         </form>
113     </div>
114     <div class="delete-modal hide">
115         <form class="ajax-delete-app" action="" method="post">
116             <div class="delete-app">
117                 应用名称:<span></span>
118                 <input style="display: none" type="text" name="aid" />
119             </div>
120             <div class="delete-app">
121                 关联的主机名:<span></span>
122             </div>
123             <div>
124                 <!-- <input type="submit" value="提交"> -->
125                 <input class="cancel" type="button" value="取消">
126
127                 <input class="ajax-del" type="button" value="Ajax悄悄删除">
128                 <span class="error" style="color: red;"></span>
129             </div>
130         </form>
131     </div>
132
133     <script src="/static/day20-app02/jquery-1.12.4.js"></script>
134     <script>
135         $('#addapp').click(function(){
136            $('.shade, .modal').removeClass('hide')
137         });
138         $('#cancel').click(function(){
139            $('.shade, .modal').addClass('hide');
140         });
141
142         //Ajax提交添加数据
143         /* //基础版
144         $('#ajax').click(function(){
145            $.ajax({
146                url: '/monitor/app-ajax',
147                type: 'POST',
148                data: $('#ajax-add-app').serialize(), //获取表单form的数据
149                success: function (data) {
150                    var obj = JSON.parse(data);
151                    if(obj.status){
152                        location.reload();
153                    }
154                    else{
155                        alert('输入有误!')
156                    }
157                }
158            });
159         });
160         */
161         //升级版
162         $('#ajax').click(function(){
163            $.ajax({
164                url: '/monitor/app-ajax',
165                type: 'POST',
166                data: $('#ajax-add-app').serialize(), //获取表单form的数据
167
168                //data: {'user': 'uson', 'pwd': [1,2,3]},
169                //traditional: true, //列表不同于字符串,必须添加参数:traditional
170
171                dataType: "JSON",
172                success: function (obj) {
173                    //obj:是字符串被序列化后的对象
174                    if(obj.status){
175                        location.reload();
176                    }
177                    else{
178                        alert('输入有误!')
179                    }
180                },
181                error: function () {
182                    alert("未发送至后台的未知错误!");
183                }
184            });
185         });
186
187         //Ajax提交编辑数据
188         $('.edit').click(function(){
189            $('.shade, .edit-modal').removeClass('hide');
190
191            //获取数据
192            var host_list = [];
193            //$(this).parent().prev().children() 找到关联的所有主机下拉列表, 每个循环找到hid
194            $(this).parent().prev().children().each(function () {
195                 //通过span标签,找到自定义属性hid
196                var nid = $(this).attr('hid');
197                host_list.push(nid);
198            });
199            //将获取到的关联id列表赋值,但先要找到模态框中的name=host_list的select标签
200            $('.ajax-edit-app select[name="host_list"]').val(host_list);
201            //找到application的id ===> aid
202            var aid = $(this).parent().parent().attr('aid');
203            $('.ajax-edit-app input[name="aid"]').val(aid);
204
205            // 再获取appname, 赋值
206            //var text = $(this).parent().prev(":last").text(); //误区:就是上一个
207            var text = $(this).parent().siblings().prev(":last").text();
208            //console.log("TEXT:", text);
209            $('.ajax-edit-app input[name="appname"]').val(text);
210         });
211         $('.cancel').click(function(){
212            $('.shade, .edit-modal, .delete-modal').addClass('hide');
213         });
214
215         //先获取数据,再赋值数据
216         //写在$('.edit').click(function(){})里面
217         $('.ajax').click(function(){
218            $.ajax({
219                url: '/monitor/app-ajax-edit',
220                type: 'POST',
221                data: $('.ajax-edit-app').serialize(), //获取表单form的数据
222                dataType: "JSON",
223                success: function (obj) {
224                    //obj:是字符串被序列化后的对象
225                    if(obj.status){
226                        location.reload();
227                    }
228                    else{
229                        alert('输入有误!')
230                    }
231                },
232                error: function () {
233                    // ajax的url错误:/monitor/app_ajax_edit
234                    // 后台问题,'Manager' object has no attribute 'filer'
235                    // data中.ajax-edit-app类型错误:TypeError: int() argument must be a string, a bytes-like object or a number, not 'list'
236                    // 后台getlist接收aid: ['5'], 错误提示同上
237                    // 后台查询数据类型错误  AttributeError: 'int' object has no attribute 'r'
238                    //                   OBJ>> Application object (4)
239                    alert("未发送至后台的未知错误!");
240                }
241            });
242         });
243
244         //ajax删除(点击X图标删除)
245         var hid = '';
246         var aid = '';
247         $('i').click(function(){
248            {#console.log(123);#}
249            $('.shade, .delete-modal').removeClass('hide');
250
251            //提取数据 同编辑,稍作修改
252            /*
253            var host_list = [];
254            $(this).parent().prev().children().each(function () {
255                var nid = $(this).attr('hid');
256                host_list.push(nid);
257            });
258            $('.ajax-delete-app select[name="host_list"]').val(host_list);
259            */
260            var text = $(this).parent().text();
261            hid = $(this).parent().attr('hid');
262            var app_name = $(this).parent().parent().prev().text();
263            aid = $(this).parent().parent().parent().attr('aid'); /*这里没用上,没用到form打包*/
264            $('.ajax-delete-app').children(':first').children(':first').text(app_name).parent().next().children(':first').text(text);
265            //console.log(aid);
266         });
267         //ajax删除
268         $('.ajax-del').click(function(){
269            $.ajax({
270                url: '/monitor/app-ajax-del',
271                type: 'POST',
272                data: {'appname': $('.ajax-delete-app').children(':first').children(':first').text(),
273                      //'hostname': $('.ajax-delete-app').children(':first').next().children(':first').text(),
274                        'hid': hid,
275                         'aid': aid},
276                dataType: "JSON",
277                success: function (obj) {
278                    if(obj.status){
279                        location.reload();
280                    }
281                    else{
282                        alert('输入有误!')
283                    }
284                },
285                error: function () {
286                    alert("未发送至后台的未知错误!");
287                }
288            });
289         });
290     </script>
291 </body>
292 </html>
app-ajax
  1 # (2)多对多**************************************************
  2 # 模态框增加   √    Ajax增加  √
  3 # 新Url修改   √     Ajax修改 √
  4 #                  Ajax删除  √
  5 # Application 多对多关系表 + 模态框方式添加数据
  6 def app(request):
  7     if request.method == 'GET':
  8         app_list = models.Application.objects.all()
  9         host_list = models.Host.objects.all() #外键关联,用于模板页面的下拉框获取,不用写死
 10         return render(request, 'day20-app02/app.html', {'app_list': app_list, 'host_list': host_list})
 11     elif request.method == 'POST':
 12         appname = request.POST.get('appname')
 13         host_list = request.POST.getlist('host_list') #下拉框
 14
 15         obj = models.Application.objects.create(name=appname)
 16         # r不用传,外键关联,该app创建完后是一个对象obj
 17         obj.r.add(*host_list)       #自动生成的外键关联
 18         return redirect('/monitor/app')
 19
 20 # Application 多对多关系表 + Ajax方式添加数据
 21 def app_ajax(request):
 22     import json
 23     app_dict = {'status': True, 'error_msg': None, 'data': None}
 24     if request.method == 'GET':
 25         print('get')
 26         app_list = models.Application.objects.all()
 27         host_list = models.Host.objects.all()
 28         return render(request, 'day20-app02/app-ajax.html', {'app_list': app_list, 'host_list': host_list})
 29     elif request.method == 'POST':
 30         print('post')
 31         user = request.POST.get('user')
 32         test_list = request.POST.getlist('pwd')
 33         print(user, test_list) #post    uson [] ===>
 34         #
 35         # appname = request.POST.get('appname')
 36         # host_list = request.POST.getlist('host_list')
 37         # print(appname, host_list)
 38         #
 39         # obj = models.Application.objects.create(name=appname)
 40         # # r不用传,该app创建完后是一个对象obj
 41         # obj.r.add(*host_list)
 42         #
 43
 44         return HttpResponse(json.dumps(app_dict))
 45
 46
 47 # Application 多对多关系表 + Ajax方式编辑数据
 48 def app_ajax_edit(request):
 49     import json
 50     app_dict = {'status': True, 'error_msg': None, 'data': None}
 51     if request.method == 'GET':
 52         print('get')
 53         app_list = models.Application.objects.all()
 54         host_list = models.Host.objects.all()
 55         return render(request, 'day20-app02/app-ajax.html', {'app_list': app_list, 'host_list': host_list})
 56     elif request.method == 'POST':
 57         print("app-ajax-edit>>", 'post')
 58         appname = request.POST.get('appname')
 59         host_list = request.POST.getlist('host_list')
 60         # 数据包里没有aid如何知道更新哪条数据
 61         aid = request.POST.get('aid')
 62         print("app-ajax更新数据》》", appname, host_list, aid)
 63
 64         # obj = models.Application.objects.filter(id=aid).update(name=appname)
 65         # 返回的不是对象,而是数字1
 66         # obj = models.Application.objects.filter(id=aid)
 67         # 返回的不是对象,而是列表[]
 68
 69         # obj = models.Application.objects.filter(id=aid).first()
 70         # 返回的才是对象
 71         obj = models.Application.objects.get(id=aid)
 72         # 返回的也是对象
 73         print("OBJ>>", obj)
 74         # r不用传,该app创建完后是一个对象obj
 75         obj.r.set(host_list) #更新数据,没有*
 76
 77         # obj.name = appname    # 无法修改
 78         models.Application.objects.filter(id=aid).update(name=appname)
 79
 80         return HttpResponse(json.dumps(app_dict))
 81         # return HttpResponse("OK")
 82
 83 # Application 多对多关系表 + Ajax方式删除数据
 84 def app_ajax_del(request):
 85     import json
 86     app_dict = {'status': True, 'error_msg': None, 'data': None}
 87     if request.method == 'GET':
 88         print('get')
 89         app_list = models.Application.objects.all()
 90         host_list = models.Host.objects.all()
 91         return render(request, 'day20-app02/app-ajax.html', {'app_list': app_list, 'host_list': host_list})
 92     elif request.method == 'POST':
 93         print("app-ajax-edit>>", 'post')
 94         appname = request.POST.get('appname')
 95         # hostname = request.POST.get('hostname')
 96         hid = request.POST.get('hid')
 97         aid = request.POST.get('aid')
 98         print("app-ajax更新数据》》", appname, hid, aid)
 99
100         obj = models.Application.objects.get(id=aid)
101         obj.r.remove(hid)
102         return HttpResponse(json.dumps(app_dict))
103         # return HttpResponse('OK')
ajax多对多-基础
 1 # Application 多对多关系表 + 新URL方式修改数据
 2 def app_newurl_edit(request, aid):
 3     # import json
 4     # app_dict = {'status': True, 'error_msg': None, 'data': None}
 5
 6     if request.method == 'GET':
 7         # print("url路径>>", request.path_info)
 8         app_list = models.Application.objects.all()
 9         host_list = models.Host.objects.all()
10
11         # 编辑数据
12         appobj = models.Application.objects.filter(id=aid).first()
13         print(appobj.r.all())
14
15         return render(request, 'day21-app03/newurl/app-edit.html',
16                       {'app_list': app_list, 'host_list': host_list,
17                        'appobj': appobj, 'aid': aid})
18     elif request.method == 'POST':
19         aid = request.POST.get('app')
20         host_list = request.POST.getlist('host') #下拉框
21         print(aid, host_list)
22         obj = models.Application.objects.filter(id=aid).first()
23         obj.r.set(host_list)
24         models.Application.objects.filter(id=aid).update(name=obj.name)
25
26         # app_dict['data'] = {'host_list': host_list, 'aid': aid}
27
28         return redirect('/monitor/app')
多对多新url修改
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <link rel="stylesheet" href="/static/day20-app02/css.css" />
 7 </head>
 8 <body>
 9     <h1>Application与Host的多对多关系表</h1>
10     <div>
11         <input id="addapp" type="button" value="添加" />
12     </div>
13     <table border="1" style="text-align: center">
14         <thead>
15             <tr>
16                 <th>应用名称</th>
17                 <th>主机列表</th>
18                 <th>操作</th>
19             </tr>
20         </thead>
21         <tbody>
22             <!-- 循环 -->
23             {% for app in app_list %}
24                 <tr aid="{{ app.id }}">
25                     <td>{{ app.name }}</td>
26
27                     <!-- <td>{{ app.r.all }}</td> -->
28                     <td>
29                         {% for foo in app.r.all %} <!-- foo: 单个主机对象 -->
30                             <span hid="{{ foo.nid }}">{{ foo.hostname }}</span>
31                         {% endfor %}
32                     </td>
33                     <td>
34                         <a class="new_edit" href="/monitor/app_newurl_edit-{{ app.id }}">新Url编辑</a>
35                     </td>
36                 </tr>
37             {% endfor %}
38
39         </tbody>
40     </table>
41
42     <div class="shade hide"></div>
43     <div class="modal hide">
44         <form action="/monitor/app" method="post">
45             <div class="add-app">
46                 <input type="text" placeholder="应用名称名" name="appname" />
47             </div>
48             <div class="add-app">
49                 <select name="host_list" multiple>
50                     {% for row in host_list %}
51                         <option value="{{ row.nid }}">{{ row.hostname }}</option>
52                     {% endfor %}
53                 </select>
54             </div>
55             <div>
56                 <input type="submit" value="提交">
57                 <input id="cancel" type="button" value="取消">
58                 <!--
59                 <input id="ajax" type="button" value="Ajax悄悄提交">
60                 <span id="error" style="color: red;"></span>
61                 -->
62             </div>
63         </form>
64     </div>
65
66     <script src="/static/day20-app02/jquery-1.12.4.js"></script>
67     <script>
68         $('#addapp').click(function(){
69            $('.shade, .modal').removeClass('hide')
70         });
71         $('#cancel').click(function(){
72            $('.shade, .modal').addClass('hide');
73         });
74
75         //Ajax提交编辑数据
76         $('.new_edit').click(function(){
77            var aid = $(this).parent().parent().attr('aid');
78            var host_list = [];
79            $(this).parent().prev().children().each(function () {
80                var hid = $(this).attr('hid');
81                host_list.push(hid);
82            });
83            var appname = $(this).parent().parent().children(':first').text();
84            $.ajax({
85               url: '/monitor/app_newurl_edit-' + aid,
86               //type: 'POST',
87               type: 'GET',
88
89               traditional: true,
90               data: {'aid': aid, 'appname': appname, 'host_list': host_list},
91               success: function(data){
92                   alert('新URL编辑页面跳转成功!');
93               }
94            });
95         });
96     </script>
97 </body>
98 </html>
app
 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <link rel="stylesheet" href="/static/day20-app02/css.css" />
 7 </head>
 8 <body>
 9     <h1>Application与Host的多对多关系表编辑界面</h1>
10     <form action="/monitor/app_newurl_edit-{{ aid }}" method="post">
11         <div>
12             <input type="submit" value="保存" />
13         </div>
14         <table border="1" style="text-align: center">
15             <thead>
16                 <tr>
17                     <th>应用名称</th>
18                     <th>主机列表</th>
19                 </tr>
20             </thead>
21             <tbody>
22                 <tr>
23                     <td>
24                         <select name="app">
25                             {% for app in app_list %}
26                                 {% if app.name == appobj.name %}
27                                     <option selected="selected" value="{{ app.id }}">{{ app.name }}</option>
28                                 {% else %}
29                                     <option value="{{ app.id }}">{{ app.name }}</option>
30                                 {% endif %}
31                             {% endfor %}
32                         </select>
33                     </td>
34                     <td>
35                         <select name="host" multiple>
36                             {% for host in host_list %}
37                                 {% if host in appobj.r.all %} <!-- 对象与对象 -->
38                                     <option selected="selected" value="{{ host.nid }}">{{ host.hostname }}</option>
39                                 {% else %}
40                                     <option value="{{ host.nid }}">{{ host.hostname }}</option>
41                                 {% endif %}
42                             {% endfor %}
43                         </select>
44                     </td>
45                 </tr>
46             </tbody>
47         </table>
48     </form>
49 </body>
50 </html>
app-edit
12-31 16:34