python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

时间:2023-03-28 09:11:57

昨日内容回顾

第一部分:权限相关
1. 权限基本流程
用户登录成功后获取权限信息,将【权限和菜单】信息写入到session。
以后用户在来访问,在中间件中进行权限校验。
为了提升用户体验友好度,在后台通过inclusion_tag动态生成一个二级菜单。
2. 使用权限
- 用户登陆:权限和菜单的初始化; init_permission
- 配置中间件
- 配置白名单
- 配置session中使用到的key
- load rbac
- menu ,inclusion_tag 生成菜单
- filter,可以在if后做条件,粒度控制到按钮。
第二部分:stark组件
1. 如何使用
- 在app中编写 stark.py
- 在stark.py中进行定制
- 默认配置:
site.register(models.UserInfo)
- 自定义配置:
class UserConfig(StarkConfig):
list_display = [] # 表格式列表上显示的字段
def get_list_display():
pass
order_by = [] # 排序
action_list=[] # 批量操作
search_list = [] # 模糊搜索
list_filter = [] # 组合搜索
add_btn # 是否显示添加按钮
model_form_class # 自定义ModelForm def extra_url(self): # 自定义扩展 URL
pass def get_urls(self): # 自定义URL
pass def changelist_view(self,request):
pass def add_view(self,request):
pass def change_view(self,request):
pass def del_view(self,request):
pass site.register(models.UserInfo,UserConfig)

一、popup

什么是popup

popup英文翻译叫 弹出窗口。

弹窗是一个非常流行的对话框,弹窗可以覆盖在页面上展示。

弹窗可用于显示一段文本,图片,地图或其他内容。

注意:popup弹窗,是由浏览器生成的!

在前端里面的,有一个模态框。那是由Html生成的!跟popup弹框不一样!

window.open

popup实际上,是调用了js中的window.open方法

open() 方法用于打开一个新的浏览器窗口或查找一个已命名的窗口。

语法

window.open(URL,name,features,replace)

注意:如果name重名,只会打开一个

窗口特征(Window Features)

这里只列举,下面例子中,会用到的参数

status=yes|no|1|0 是否添加状态栏。默认是 yes。
height=pixels 窗口文档显示区的高度。以像素计。
width=pixels 窗口的文档显示区的宽度。以像素计。
toolbar=yes|no|1|0 是否显示浏览器的工具栏。默认是 yes。
resizable=yes|no|1|0 窗口是否可调节尺寸。默认是 yes。

其他更多参数,请参考链接:

http://www.w3school.com.cn/jsref/met_win_open.asp

在django admin中,就用到了popup。比如之前写的博客系统

点击加号

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

它弹出了一个网页框。注意:它是单页面的!不能像浏览器一样,在当前页面,新开一个窗口。

不能收藏!URL地址也不能修改!

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

举例:

新建一个项目,注意:django版本为1.11

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

修改urls.py,增加路径

from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
]

修改views.py,增加视图函数

from django.shortcuts import render

# Create your views here.
def index(request):
return render(request,"index.html")

在templates目录下,创建文件index.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>添加页面</h1>
<form>
<p><input type="text"></p>
<p>
<select id="city">
<option>北京</option>
<option>上海</option>
<option value="">深圳</option>
</select>
<input type="button" value="+" onclick="popUp();">
</p>
</form>
<script>
function popUp() {
{#弹窗#}
window.open("http://www.py3study.com/",'x1',"status=1, height=500, width=500, toolbar=0, resizable=0")
}
</script>
</body>
</html>

启动django项目,访问首页

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

点击加号按钮,弹窗页面。它是一个单页面!

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

弹窗的内容,可以定制吗?当然可以!

修改urls.py,增肌路径

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
url(r'^pop/', views.pop),
]

修改views.py,增肌视图函数

from django.shortcuts import render,HttpResponse

# Create your views here.
def index(request):
return render(request,"index.html") def pop(request):
if request.method == "GET":
return render(request,"add_city.html") print(request.POST)
return HttpResponse('添加成功')

在templates目录下,创建文件add_city.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>创建城市</h1>
<form method="post">
{% csrf_token %}
<div style="width: 200px;height: 300px;border: 1px solid #dddddd">
<input type="text" name="city">
<input type="submit" value="提交">
</div>
</form>
</body>
</html>

刷新页面,重新点击加号按钮,效果如下:

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

点击提交之后,效果如下:

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

但是窗口并没有自动关闭!它应该自动关闭,并跳转到首页才对!

怎么让它自动关系呢?使用windows.close()

由于windows.close()是js代码,需要使用html文件来执行才行!

在templates目录下,创建文件pop_response.html

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>正在关闭</title>
</head>
<body>
<script>
{#自执行函数#}
(function () {
window.close();
})()
</script>
</body>
</html>

自执行函数,也就是能够自动立即执行的函数

看下面一段代码

(function () {
window.close();
})()

在js中声明函数,使用function关键字。函数执行,必须要加括号执行。

所以上面一段代码,就是声明之后,立刻被执行了!

还有一种用途,用于做隔离。比如多个js文件之间相互调用时!

修改views.py,渲染pop_response.html

from django.shortcuts import render,HttpResponse

# Create your views here.
def index(request):
return render(request,"index.html") def pop(request):
if request.method == "GET":
return render(request,"add_city.html") print(request.POST)
return render(request, 'pop_response.html')

重启django,刷新页面,重新添加一次。效果如下:

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

那么问题来了,添加之后的数据,要在下拉框中展示。要实时更新,怎么搞?

注意:拉下框中的数据,是来源于数据库的。所以即使添加成功了,要刷新页面,才能加载出来!

popup,它能记住是由哪个页面触发弹窗的。它能调用原始页面的数据!使用opener调用

测试一下

修改index.html,增加tx方法

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>添加页面</h1>
<form>
<p><input type="text"></p>
<p>
<select id="city">
<option>北京</option>
<option>上海</option>
<option value="">深圳</option>
</select>
<input type="button" value="+" onclick="popUp();">
</p>
</form>
<script>
{#测试函数#}
function tx() {
alert('xxx');
}
function popUp() {
{#弹窗#}
window.open("/pop/",'x1',"status=1, height=500, width=500, toolbar=0, resizable=0")
}
</script>
</body>
</html>

修改pop_response.html,调用tx方法

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>正在关闭</title>
</head>
<body>
<script>
{#自执行函数#}
(function () {
//调用tx方法
opener.tx();
window.close();
})()
</script>
</body>
</html>
(function () {
window.close();
})()

刷新页面,重新添加一次,效果如下:

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

那么既然可以调用index.html的方法,就可以传值了

修改views.py,增加变量content,用来使用js传参给index.html

from django.shortcuts import render,HttpResponse

# Create your views here.
def index(request):
return render(request,"index.html") def pop(request):
if request.method == "GET":
return render(request,"add_city.html") print(request.POST)
# 假设数据已经添加成功了,这里要获取添加的id和title
content = {'id':4,'title':'成都'}
# 渲染页面,用来将参数传给index.html
return render(request, 'pop_response.html',content)

修改pop_response.html,调用tx方法,并传参。

注意:参数是字符串,要用引号括起来

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>正在关闭</title>
</head>
<body>
<script>
{#自执行函数#}
(function () {
//调用tx方法,参数必须是字符串
opener.tx('{{ id }}','{{ title }}');
window.close();
})()
</script>
</body>
</html>
(function () {
window.close();
})()

修改index.html,接收参数后,操作DOM

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>添加页面</h1>
<form>
<p><input type="text"></p>
<p>
<select id="city">
<option value="">北京</option>
<option value="">上海</option>
<option value="">深圳</option>
</select>
<input type="button" value="+" onclick="popUp();">
</p>
</form>
<script>
{#测试函数#}
function tx(cityId,cityTitle) {
//创建option标签
var tag = document.createElement('option');
//设置value
tag.value = cityId;
// 设置text属性
tag.innerText = cityTitle;
// 获取ID标签
var city = document.getElementById('city');
//最后一个位置添加option标签
city.appendChild(tag);
}
function popUp() {
{#弹窗#}
window.open("/pop/",'x1',"status=1, height=500, width=500, toolbar=0, resizable=0")
}
</script>
</body>
</html>

重启django,刷新页面,重新添加一次!效果如下:

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

注意:这里只是添加到浏览器了,并没有到数据库。所以刷新页面,数据会丢失!

django render传输的变量。变量只会在指定的文件渲染!如果这个文件包含了js,那么即使js使用{{  }} 语法,也不会渲染!

举例:

修改views.py,给index.html传一个id参数

from django.shortcuts import render,HttpResponse

# Create your views here.
def index(request):
return render(request,"index.html") def pop(request):
if request.method == "GET":
return render(request,"add_city.html",{'id':''}) print(request.POST)
# 假设数据已经添加成功了,这里要获取添加的id和title
content = {'id':4,'title':'成都'}
# 渲染页面,用来将参数传给index.html
return render(request, 'pop_response.html',content)

在app01目录下,创建static目录,在此目录下创建test.js

alert('{{id}}');

修改index.html,添加h6标签,引入js文件

{% load staticfiles %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{#测试js文件#}
<script src="{% static 'test.js' %}"></script>
</head>
<body>
<h1>添加页面</h1>
<h6>'{{ id }}'</h6>
<form>
<p><input type="text"></p>
<p>
<select id="city">
<option value="">北京</option>
<option value="">上海</option>
<option value="">深圳</option>
</select>
<input type="button" value="+" onclick="popUp();">
</p>
</form>
<script>
{#测试函数#}
function tx(cityId,cityTitle) {
//创建option标签
var tag = document.createElement('option');
//设置value
tag.value = cityId;
// 设置text属性
tag.innerText = cityTitle;
// 获取ID标签
var city = document.getElementById('city');
//最后一个位置添加option标签
city.appendChild(tag);
}
function popUp() {
{#弹窗#}
window.open("/pop/",'x1',"status=1, height=500, width=500, toolbar=0, resizable=0")
}
</script>
</body>
</html>

重启django,刷新页面

发现id没有被渲染出来

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

但是index.html渲染出来了

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

在window.open中,name重名,只会打开1个

如果定义了多个window.open,会被浏览器拦截

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

只会弹出第一个,后续的都会被拦截!

总结:

主页面:
function xxxxxx(){ }
window.open('url','name','.....') popup页面:
opener.xxxxxx()
// widown.close() 补充:
js的自执行函数
用于做隔离:
(function(jq){
jq.xxx
})(jQuery)

二、Model类的继承

Django有三种继承的方式:

  • 抽象基类:被用来继承的模型被称为Abstract base classes,将子类共同的数据抽离出来,供子类继承重用,它不会创建实际的数据表;
  • 多表继承:Multi-table inheritance,每一个模型都有自己的数据库表;
  • 代理模型:如果你只想修改模型的Python层面的行为,并不想改动模型的字段,可以使用代理模型。

注意!同Python的继承一样,Django也是可以同时继承两个以上父类的!

关于这3种继承的方式,详情请参考链接:

https://www.cnblogs.com/feixuelove1009/p/8420751.html

本文主要讲解 多表继承

多表继承

这种继承方式下,父类和子类都是独立自主、功能完整、可正常使用的模型,都有自己的数据库表,内部隐含了一个一对一的关系。

举例

修改models.py

from django.db import models

# Create your models here.
class Author(models.Model): # 作者
name=models.CharField(verbose_name="姓名",max_length=32)
age=models.IntegerField(verbose_name="年龄") class AuthorDetail(Author): # 作者详情
gf=models.CharField(verbose_name="女朋友",max_length=32)
tel=models.CharField(verbose_name="作者电话",max_length=32)

它等同于原生sql语句

CREATE TABLE "Author" (
"id" integer NOT NULL PRIMARY KEY,
"name" varchar(32) NOT NULL,
"age" int(11) NOT NULL
); CREATE TABLE "AuthorDetail" (
"author_ptr_id" integer NOT NULL PRIMARY KEY REFERENCES "Author" ("id"),
"gf" varchar(32) NOT NULL,
"tel" varchar(32) NOT NULL
);

使用2个命令,生成表

python manage.py makemigrations
python manage.py migrate

使用Navicat打开数据库,查看表结构,并添加数据

author表

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

authordetail表

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

父类和子类都生成了单独的数据表,authordetail中存储了author的id,也就是通过OneToOneField链接在一起。继承关系通过表的JOIN操作来表示。在JPA中称作JOINED。这种方式下,每个表只包含类中定义的字段,不存在字段冗余,但是要同时操作子类和所有父类所对应的表。

author 里面的所有字段在 authordetail 中也是有效的,只不过数据保存在另外一张数据表当中。所以下面两个语句都是可以运行的:

models.Author.objects.filter(name='xiao')
models.AuthorDetail.objects.filter(name='xiao')

修改urls.py

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/', views.index),
]

修改views.py

from django.shortcuts import render,HttpResponse
from app01 import models # Create your views here.
def index(request):
obj1 = models.Author.objects.filter(name='xiao').values()
obj2 = models.AuthorDetail.objects.filter(name='xiao').values()
print(obj1)
print(obj2)
return HttpResponse('ok')

重启django,访问首页

查看Pycharm控制台输出:

<QuerySet [{'age': 23, 'name': 'xiao', 'id': 1}]>
<QuerySet [{'gf': '韩雪', 'author_ptr_id': 1, 'tel': '', 'age': 23, 'name': 'xiao', 'id': 1}]>

可以看出,authordetail 表打印出本表的字段以及父表author表的字段

如果你有一个 author,那么它同时也是一个 authordetail, 那么你可以使用子 model 的小写形式从 author 对象中获得与其对应的 authordetail 对象:

修改views.py

from django.shortcuts import render,HttpResponse
from app01 import models # Create your views here.
def index(request):
obj1 = models.Author.objects.filter(name='xiao').first()
print(obj1.authordetail)
return HttpResponse('ok')

重启django,访问首页

查看Pycharm控制台输出:

AuthorDetail object

但是,如果上例中的 obj1 并不是 authordetail (比如它仅仅只是 author 对象,或者它是其他类的父类),那么在引用 p.authordetail 就会抛开RelatedObjectDoesNotExist: Author has no authordetail. 异常:

def index(request):
obj1 = models.Author.objects.create(name='zhang',age='')
print(obj1.authordetail)
return HttpResponse('ok')

也就是说,创建author实例的同时不会创建authordetail,但是创建authordetail实例的同时会创建author实例:

修改views.py

from django.shortcuts import render,HttpResponse
from app01 import models # Create your views here.
def index(request):
obj1 = models.AuthorDetail.objects.create(name="zhang",age="",gf="蒋婷婷",tel="")
obj2 = models.Author.objects.filter(name="zhang").values()
print(obj2)
return HttpResponse('ok')

刷新页面,查看Pycharm控制体输出:

<QuerySet [{'age': 25, 'name': 'zhang', 'id': 2}]>

使用Navicat打开2个表

author表

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

authordetail表

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

三、crm业务开发

新建一个项目pro_crm,应用名为crm,注意:django版本为1.11

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

拷贝stark app

下载代码:

链接:https://pan.baidu.com/s/1fLOGH_3G7hPTvCYKX84UdQ 密码:m8rh

将里面的stark目录拷贝至 项目根目录中

注册stark app

修改settings.py,修改INSTALLED_APPS配置项

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'crm.apps.CrmConfig',
'stark.apps.StarkConfig',
]

使用stark组件

在目标app的根目录中创建stark.py

进入crm目录,创建stark.py

修改 crm-->models.py,增加表

# from rbac.models import UserInfo as RbacUserInfo
from django.db import models class Department(models.Model):
"""
部门表
"""
title = models.CharField(verbose_name='部门名称', max_length=16) def __str__(self):
return self.title class UserInfo(models.Model):
"""
员工表
"""
name = models.CharField(verbose_name='真实姓名', max_length=16)
phone = models.CharField(verbose_name='手机号', max_length=32) gender_choices = (
(1,'男'),
(2,'女'),
)
gender = models.IntegerField(verbose_name='性别',choices=gender_choices,default=1) depart = models.ForeignKey(verbose_name='部门', to="Department") def __str__(self):
return self.name class Course(models.Model):
"""
课程表
如:
Linux基础
Linux架构师
Python自动化
Python全栈
"""
name = models.CharField(verbose_name='课程名称', max_length=32) def __str__(self):
return self.name class School(models.Model):
"""
校区表
如:
北京昌平校区
上海浦东校区
深圳南山校区
"""
title = models.CharField(verbose_name='校区名称', max_length=32) def __str__(self):
return self.title class ClassList(models.Model):
"""
班级表
如:
Python全栈 面授班 5期 10000 2017-11-11 2018-5-11
"""
school = models.ForeignKey(verbose_name='校区', to='School')
course = models.ForeignKey(verbose_name='课程名称', to='Course')
semester = models.IntegerField(verbose_name="班级(期)") #
price = models.IntegerField(verbose_name="学费")
start_date = models.DateField(verbose_name="开班日期")
graduate_date = models.DateField(verbose_name="结业日期", null=True, blank=True)
tutor = models.ForeignKey(verbose_name='班主任', to='UserInfo', related_name='classes',limit_choices_to={'depart__title':'教质部'})
teachers = models.ManyToManyField(verbose_name='任课老师', to='UserInfo', related_name='teach_classes',limit_choices_to={'depart_id__in':[6,7]})
memo = models.CharField(verbose_name='说明', max_length=256, blank=True, null=True) def __str__(self):
return "{0}({1}期)".format(self.course.name, self.semester)

使用2个命令,生成表

python manage.py makemigrations
python manage.py migrate

修改crm-->stark.py,注册表Department

from stark.service.stark import site
from crm import models site.register(models.Department)

配置路由信息

修改urls.py,增加stark路由

from django.conf.urls import url
from django.contrib import admin
from stark.service.stark import site urlpatterns = [
url(r'^admin/', admin.site.urls),
# 导入stark组件的路由
url(r'^stark/', site.urls),
]

启动django项目,访问url: http://127.0.0.1:8000/stark/crm/department/list/

python 全栈开发,Day117(popup,Model类的继承,crm业务开发)

默认是没有数据的,需要添加!

由于时间关系,详细的步骤略...

完整代码,请参考

链接:https://pan.baidu.com/s/1K4YG5LY89aidRWK7j51DBg 密码:30jt

未完待续...