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


    昨日内容回顾

    第一部分:权限相关
        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)
    View Code

    一、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。比如之前写的博客系统

    点击加号

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

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

    举例:

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

     修改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),
    ]
    View Code

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

    from django.shortcuts import render
    
    # Create your views here.
    def index(request):
        return render(request,"index.html")
    View Code

    在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="1">深圳</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>
    View Code

    启动django项目,访问首页

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

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

    修改urls.py,增肌路径

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

    修改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('添加成功')
    View Code

    在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=" 200px;height: 300px;border: 1px solid #dddddd">
                <input type="text" name="city">
                <input type="submit" value="提交">
            </div>
        </form>
    </body>
    </html>
    View Code

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

     

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

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

    怎么让它自动关系呢?使用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>
    View Code

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

    看下面一段代码

    (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')
    View Code

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

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

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

    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="1">深圳</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>
    View Code

    修改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();
    })()
    View Code

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

    那么既然可以调用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)
    View Code

    修改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();
    })()
    View Code

    修改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="1">北京</option>
                <option value="2">上海</option>
                <option value="3">深圳</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>
    View Code

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

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

    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':'33'})
    
        print(request.POST)
        # 假设数据已经添加成功了,这里要获取添加的id和title
        content = {'id':4,'title':'成都'}
        # 渲染页面,用来将参数传给index.html
        return render(request, 'pop_response.html',content)
    View Code

    在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="1">北京</option>
                <option value="2">上海</option>
                <option value="3">深圳</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>
    View Code

    重启django,刷新页面

    发现id没有被渲染出来

    但是index.html渲染出来了

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

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

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

    总结:

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

    二、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)
    View Code

    它等同于原生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
    );
    View Code

    使用2个命令,生成表

    python manage.py makemigrations
    python manage.py migrate

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

    author表

    authordetail表

    父类和子类都生成了单独的数据表,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),
    ]
    View Code

    修改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')
    View Code

    重启django,访问首页

    查看Pycharm控制台输出:

    <QuerySet [{'age': 23, 'name': 'xiao', 'id': 1}]>
    <QuerySet [{'gf': '韩雪', 'author_ptr_id': 1, 'tel': '2345', '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')
    View Code

    重启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='25')
        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="25",gf="蒋婷婷",tel="2534")
        obj2 = models.Author.objects.filter(name="zhang").values()
        print(obj2)
        return HttpResponse('ok')
    View Code

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

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

    使用Navicat打开2个表

    author表

    authordetail表

    三、crm业务开发

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

    拷贝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',
    ]
    View Code

    使用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="班级(期)") # 11
        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)
    View Code

    使用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)
    View Code

    配置路由信息

    修改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),
    ]
    View Code

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

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



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

    完整代码,请参考

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

    未完待续...

  • 相关阅读:
    分析 ajax 请求并抓取 “今日头条的街拍图”
    requests + 正则表达式 获取 ‘猫眼电影top100’。
    爬虫基础(暂缓更新)
    Git 操作笔记:分布式版本控制系统
    python补充
    python基础
    8.最佳电影聚类分析
    文本分析 笔记
    7.文档聚类
    5.词项相似度分析
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/9581125.html
Copyright © 2020-2023  润新知