博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
crm
阅读量:5846 次
发布时间:2019-06-18

本文共 63027 字,大约阅读时间需要 210 分钟。

喜欢请打赏

扫描二维码打赏

支付宝打赏

 

课程大纲

Django知识点回顾

"""1.django请求生命周期    http协议:        四大特性:            1.基于scoket应用于应用层的协议            2.基于请求响应的协议            3.无连接            4.无状态    WSGI协议:wsgiref,uwsgi,werkzeug实现模块    中间件:默认七个中间件,五个可自定义方法,全局访问频率限制,权限限制等        process_request  请求刚进来时        process_view    经过url执行视图函数之前        process_template_response   视图函数中return render时触发        process_exception       视图函数中报错执行        process_response    返回相应响应时            urls.py:路由控制器    MTV:        views.py:            视图层:FBV,CBV                CBV可张开讲:from django.views import View                看一下源码                            返回结果必须是HttpResponse对象                    templates.py:            模板语法:变量相关{
{}},逻辑相关{%%} models.py: ORM操作 2.django session机制 request.session仅仅只是产生缓存,真正起作用还是中间件 3.form组件 auth认证 简单提一嘴4.django settings文件配置5.前后端传输数据编码格式 简单前后端传输页面代码搭建 http传输数据格式书写 三种常见编码格式总结 urlencoded form-data json 请求体数据格式推导(先瞎猜,再用事实验证) 请求首行作用ContentType参数作用 浏览器查看form表单默认提交方式以及组织数据格式 ajax提交数据(默认提交,json提交>>>前后端分离) request.POST无法解析>>>request.body存储原始数据 """

admin使用

"""打开博客园django-admin组件,介绍admin是啥    django自带的一个后台管理组件,快速的帮我们完成对数据的增删改查操作,我们这会是要学习admin的使用,并模仿它(及参考admin的源码)开发一套我们自己的后台管理工具    新建项目,直接访问,需要超级用户博客园拷贝图书馆管理系统表格,数据库迁移并注册到admin中后台模型表展示添加一条数据后先总结url的规律模型表路由规律总结    路由中都有admin是因为它是一个组件        推导另外一个模型表的url规律    总结:    admin为每一个注册了的模型表创建增删改查四条url你们用admin应该只到这一步吧,接下来我们继续往深里看所有表的展示页面是不是都是一样的,现在我想对某个表设置不一样的展示,咋弄?再来五大重点参数介绍    模型表继承admin.ModelAdmin        list_display >>> 演示这个效果之后 看一点源码 配置类概念>>>阐释配置类概念        为何要继承ModelAdmin        list_display_links    search_field    list_filter    actions        讲action时,复习一个前端知识,单选多选getlist()    1.启动源码    django启动,执行每一个app下的admin.py文件    原因:autodiscover_module('admin')单例模式复习    对照博客    重点在基于模块的单例模式上        诠释模块导入重复导入只加载一次的特性pyc地方        再写一个py文件,写一个函数里面调,然后去另外一个文件调函数    再来个坑:导类过来,实例化两次,求打印结果?2.admin注册源码摘取精髓部分class AdminSite(object):    def __init__(self, name='admin'):        self._registry = {}    def register(self, model_or_iterable, admin_class=None, **options):        if not admin_class:            admin_class = ModelAdmin        self._registry[model] = admin_class(model, self)site=AdminSite()# **************************源码**************************admin.site.register(Book)admin.site.register(Book,BookConfig)引出配置类作用,self._registry中数据存放格式打印_registry里面数据带他们看看  这里慢点讲!!!"""

3.url设计

"""1.url分发本质url(r'^index/', ([],None,None))  # 固定写法元祖里面三个参数2.一级,二级分发演示url(r'^stark/',([],None,None))第一次推导    url(r'^index/',([            url(r'^test01/',test01),            url(r'^test02/',test02)    ],None,None))第二次推导    url(r'^index/',([        url(r'^test01/',([            url(r'^test01_1',test01_1),             url(r'^test01_2',test01_2),            url(r'^test01_3',test01_3),        ],None,None)),        url(r'^test02/',test02)    ],None,None))自己生成注册了的模型表的urldef list_view(request):    return HttpResponse('list_view')def add_view(request):    return HttpResponse('add_view')def edit_view(request,id):    return HttpResponse('edit_view')def delete_view(request,id):    return HttpResponse('delete_view')def get_urls1():    tmp = [        url(r'^$',list_view),        url(r'^add/',add_view),        url(r'^edit/(\d+)/',edit_view),        url(r'^delete/(\d)/',delete_view)    ]    return tmpdef get_urls():    tmp = []    for class_model,config_obj in admin.site._registry.items():        app_label = class_model._meta.app_label        model_name = class_model._meta.model_name        tmp.append(            url(r'%s/%s/'%(app_label,model_name),(get_urls1(),None,None))        )    return tmpurlpatterns = [    url(r'^admin/', admin.site.urls),    url(r'^stark/',(get_urls(),None,None))]"""

CRM项目开始

"""组件也是应用,一个项目有多个应用,一个应用可以用在多个项目里1.admin启动源码(django配置文件整体梳理>>>注册的app中admin)2.autodiscover_modules应用3.新建django项目>>>stark应用>>>service文件夹4.admin源码摘取 + 配置类5.url设计    研究url(r'^admin/', admin.site.urls)源码    一级分发    二级分发(配置类介绍)6.总结回顾    解释一下二级分发那个self到底是谁    7.视图函数中self.model诠释8.展示各个模型表数据对象9.依据list_display详细展示数据对象    表单展示    表头展示        verbose_name介绍 model._meta.get_field('字段名').verbose_name    小bug调试,表头后端代码筛选__str__特殊情况        对象反射拿__str__不报错的原因>>>联想到迭代器__next__,嫌麻烦,可以写成next()        10.单张表的自定义数据列 选择 编辑 删除>>>拓展至全局配置    详细讲        先用户自定义 再转成全局配置        获取表头表单内部代码优化11.选择 编辑 删除标识性参数设置12.反向解析13.list_display_links        自定义编辑列根据list_display_links显隐展示"""

form与modelform

"""2.form组件介绍    演示form本质应用    class TestForm(forms.Form):        name = forms.CharField(max_length=32)        email = forms.EmailField()        age = forms.IntegerField()            python console中直接测试    from app01 import views    obj = views.TestForm({'name':'jason','email':'123','age':18})    obj.is_valid()  # 校验数据    False    obj.cleaned_data  # 合格的放入这个里面    {'name': 'jason', 'age': 18}    obj.errors  # 不合格的放入errors中    {'email': ['Enter a valid email address.']}        继续演示几种传参类型    obj = views.TestForm({'name':'jason','age':18})    obj = views.TestForm({'name':'jason','email':"123@qq.com",'age':18})    obj = views.TestForm({'name':'jason','email':"123@qq.com",'age':18,'abc':123})    3.form组件完成    class Book(models.Model):        title = models.CharField(max_length=32)        price = models.DecimalField(max_digits=8,decimal_places=2)        date = models.DateField()        publish = models.ForeignKey("Publish")        authors = models.ManyToManyField("Author")    class Publish(models.Model):        name = models.CharField(max_length=32)    class Author(models.Model):        name = models.CharField(max_length=32)对上述三张表用form完成增  >>>  编辑功能form组件书写难度1.新建django项目 自定义模型表这里详细演戏图书管理系统的增删改查:    1.先不借助任何组件,自己手动渲染标签        这里需要注意的问题有前端input标签一定要写name属性        后端在更新数据的时候,记得用关键字传参的形式去做        新增用add(*author) 编辑用set(author)            2.借助form组件        前端三种渲染方式            3.最后推到出modelform组件        class BookModelForm(forms.ModelForm):            class Meta:                model = models.Book                fields = '__all__'4.modelform介绍"""
"""1.modelform完成CRM项目中模型表的增删改查    这里为什么定义这个方法,主要是用户如果想针对自己的模型表进行其他的特定操作    def get_model_form(self):        if self.model_form_class:            return self.model_form_class        from django.forms import ModelForm        class ModelFormClass(ModelForm):            class Meta:                model = self.model                fields = '__all__'        return ModelFormClass                def add_view(self,request):            model_form = self.get_model_form()            if request.method == 'POST':                model_form_obj = model_form(request.POST)                if model_form_obj.is_valid():                    model_form_obj.save()                    return redirect(self.get_reverse_url('list'))            model_form_obj = model_form()            return render(request,'stark/add_view.html',locals())                    def edit_view(self,request,id):            model_form = self.get_model_form()            edit_obj = self.model.objects.filter(pk=id).first()            if request.method == 'POST':                model_form_obj = model_form(request.POST,instance=edit_obj)                if model_form_obj.is_valid():                    model_form_obj.save()                    return redirect(self.get_reverse_url('list'))            model_form_obj = model_form(instance=edit_obj)            return render(request,'stark/edit_view.html',locals())                    def delete_view(self,request,id):            delete_obj = self.model.objects.filter(pk=id).delete()            return redirect(self.get_reverse_url('list'))"""

分页

"""1.批量插入数据方法    传统:效率极低        def index(request):            for i in range(100):                Book.objects.create(title='book_%s'%i,price=i*i)            return render(request,'book_list.html')    现在:        book_list = []  # 里面方法Book对象        for i in range(100):            book = Book(title="book_%s"%i,price=i*i)            book_list.append(book)        Book.objects.bulk_create(book_list)2.展示批量产生的数据 3.分页介绍    博客园分页代码拷贝,解释    保存搜索条件介绍(拉勾网展示)    request.GET.urlencoded()构造get请求携带数据格式"""

数据展示类

"""1.数据展示全部封装到新的Showlist展示类中"""

search功能

"""1.bootstrap中找寻前端样式    css样式   >>>     表单2.后端模拟简单版本实现效果    # search功能  简单推导1    key_word = request.GET.get('q')    if key_word:        for field in self.search_fields:            queryset = self.model.objects.filter(title__icontains=key_word)3.如何解决查询条件关键字 title__icontains拼接?    Q对象简介        # python console中演示推导过程1        from app01 import models        from django.db.models import Q        models.Book.objects.filter(title='西游记')        
]> models.Book.objects.filter(Q(title='西游记')|Q(price=399))
,
]> # 推导过程2 q = Q() q.children.append(('title','西游记')) models.Book.objects.filter(q)
]> # 推导过程3多个条件 q = Q() q.children.append(('title','西游记')) models.Book.objects.filter(q)
]> q.children.append(('price','399')) models.Book.objects.filter(q)
# 最终推导 from django.db.models import Q q = Q() q.children.append(("字段名","可能存在的字段值")) # 特点在于 直接写的是字符串 q.connector = "or" # q添加数据默认是和的关系,可通过该参数改变 Models.objects.filter(q) # 以q里面添加的条件筛选相应数据4.要想实现模糊查询需要 q.children.append(("字段名"+"__icontains","可能存在的字段值")) 5.search功能实现6.search功能封装配置类方法7.search功能前端搜索保留搜索条件 配置类对象添加key_word属性8.search功能前端界面显隐 根据key_word属性控制"""

action功能

"""1.django admin后台action功能演示2.前端样式        3.点击提交按钮需要将checkbox选中数据与select选择框中的数据提交到后端,所以需要保证二者在一个form表单中    
{% csrf_token %}

filter功能

"""1.admin list_filter功能演示,展示的其实是一个个的数据对象2.前端页面搭建    
FILTER
3.后端 分析: 1.list_filter中只能放外键字段 2.先循环字段,取出该字段对应的模型表,再取每个字段对应的多组数据 model._meta.get_field('字段').rel.to >>> 模型表 3.深拷贝request.GET 获取get请求参数 保存搜索条件 4.all标签渲染 由于传输数据格式为[{'外键字段':[a,b,c,d...],'外键字段':[e,f,g,h...]}] 每个外键字段对应的列表中都需要一个all标签,而all标签的作用就是去除其所在字段在url中的键值,也就是说只需要pop掉当前循环的字段即可 def get_list_filter(self): tmp_dict = {} for field in self.config_obj.list_filter: tmp = [] relation_model = self.config_obj.model._meta.get_field(field).rel.to queryset = relation_model.objects.all() import copy params = copy.deepcopy(self.request.GET) click_id = self.request.GET.get(field) # all标签 params2 = copy.deepcopy(self.request.GET) if field in params2: params2.pop(field) all_link = "All" % params2.urlencode() else: all_link = "All" tmp.append(mark_safe(all_link)) for data in queryset: params[field] = data.pk _url = params.urlencode() if click_id == str(data.pk): s = "%s" % (_url, data) else: s = '%s' % (_url, data) tmp.append(mark_safe(s)) tmp_dict[field] = tmp return tmp_dic4.前端
FILTER
{% for k,v in show_obj.get_list_filter.items %}
By {
{ k|upper }}
{% for data in v %}

{

{ data }}

{% endfor %}
{% endfor %}
5.数据过滤 外键字段查询时 model.objects.filter(publish__id=1) model.objects.filter(publish=obj) 同样也支持 model.objects.filter(publish=1) >>> 自动转换成第一种 所以我们再利用q对象往children里面添加数据时可以直接('publishs',1) """

open样式演示

"""新建django项目演示open方法    1.window.open 方法        window.open('https://www.baidu.com','','height=400,width=800')    2.填写自己的路由,打开添加页面    3.填写数据,window.opener调用父类方法    4.如何将创建出来的数据渲染到父页面>>>后端将数据对象传递到子页面,子页面传到父页面    5.window.open路由中添加前端标签id,后端接收再传递到子页面,子页面再传到父页面        后端充当中间商,只做数据传输"""

pop功能

"""1.admin查看效果2.加号渲染(必须是一对多或多对多字段,如何判断?)    我们后台循环的字段是model字段还是form字段?是form字段,意味着没法通过ForeignKey,ManyToManyField判断,因为是form字段    后端先打印每个字段的类型发现均是BoundField类型,无法判断    需要拿字段对象再点field属性才能取到真经    isinstance可以判断多继承关系    前端如何根据条件渲染这个加号呢?后端给field字段对象添加is_pop=True属性3.前端加号样式通过相对移动调节样式open样式演示完之后再回来1.加号事件绑定    路由问题解决,不同加号对应不同的添加页面>>>字段对象能加is_pop属性,能不能再加一个url属性,到时候直接点拿出来就行了(注意一定要放到form字段属性中)        后端form字段对象如何获取对应的model字段的字段名        不能用self.model 因为它是当前访问的表的添加页面,而加号对应的另外两个表的添加页面,所以这里需要我们手动反向解析url        需要获取到加号字段对应的模型表            form字段.name >>> form字段对应的model字段字段名            self.model._meta.get_filed(form字段.name).rel.to >>> 表            _url = reverse("%s_%s_add",xx,yy) 解决添加url                select标签id查找        谷歌浏览器查看 id_publish,id_authors        form字段.name 拿到对应model字段的字段名            _url = _url+"?pop_back_id=id_"+form字段.name            这是我们手动拼接,还可以自动拼接            _url = _url +"?pop_back_id="+form字段.auto_id          后端添加页面不能直接返回pop页面,不然的话我们连正常打开的pop页面也会打不开,所以需要根据url中是否有pop_back_id来判断是正常访问还是加号跳转        pop页面调用父页面传pop_back_id,pk,text        父页面DOM操作添加标签        新添加的数据需要添加selected属性    """

Stark组件Bug调整

"""数据展示的时候,点分页会报错,因为会把page=x传到了filter中,还有就是search查询中的q=x也会报错,所以在filter功能中加if判断去掉    if field in ['page','q']        continue还有就是这样写了之后如果在url中手动条件额外不存在的键值还是会报错                try:                    queryset = queryset.filter(q)                except BaseException:                    pass"""

Stark组件总结

"""从头到尾捋一遍"""

权限介绍

"""1.什么是权限?    生活中到处都是权限,比如我们办公室密码门,视频vip,等等...    再回来我们写的web应用,一个公司里面老板和员工用的同一个web服务,两者能干的事也是各不相同    再来看Django admin应用,访问模型表的增删改查这是不是也是一种权限    总的来说就是    who             what            how    哪些人对哪些资源拥有哪些操作的权限,看admin的url    http://127.0.0.1:8000/admin/auth/user/对auth下面的user表数据查看权限    http://127.0.0.1:8000/admin/auth/user/1/change/对auth下面的user表数据的修改权限    http://127.0.0.1:8000/admin/auth/user/1/delete/对auth下面的user表数据的删除权限    http://127.0.0.1:8000/admin/auth/user/add/对auth下面的user表数据的增加权限    权限其实就是一个个的url,用户可以访问的url放在一个大列表里,访问对应url的时候,去列表里查找,如果有就代表可以访问,拥有该权限,没有就是禁止访问,没有权限。2.定义几张表模拟一下    class User:        pass    class Permission:        pass    class user2permission:        pass    1.创建俩用户一个拥有查,一个拥有查改    2.一下子来了十个员工,都拥有增删改查四个权限,那我需要在第三张表里面反复录入"""

RBAC(Roel Based Access Control)

"""1.介绍日常生活中的应用软件怎么区分权限的?普通用户,超级管理员,经理,职员...是不是都是基于角色的权限管理,每一个角色对应有一定的权限,用户只需按角色划分,就能有对应的权限2.表关系class User:    passclass Role:    passclass Permission:    passclass user2role:    passclass role2permission:    pass一次性有100个员工,你会发现方案1和方案2差距很大!!!   """

项目搭建

"""1.新建django项目,stark组件移植过来    知识点:        templates文件查找会先从项目根目录找,其次会去应用下面找,再找不到报错        static文件亦是如此,注意在拖拽的时候,防止pycharm自动加stark前缀,需要手动去除掉,任然以staic开头        2.创建模型表并注册到stark组件中    class User(models.Model):        name = ...        pwd = ...        roles = ...    class Role(model.Model):        title = ...        permissions = ...    class Permission(model.Model):        title = ...        url = ...3.启动项目 添加数据    权限表         角色和用户的增删改查    角色表        销售      查看 添加用户        讲师      查看        CEO      用户的增删改查        管理员     所有权限    用户表        kevin   销售+讲师        egon    CEO        jason   管理员权限思路:    1.创建表,录入数据    2.登陆验证,获取登陆人的权限    3.权限校验5.登陆校验获取登陆人的权限    简单的前端登陆页面    后端获取查询校验        需要慢一点的地方在于如何基于用户对象查询权限信息            user_obj.roles.all()  >>> 角色对象            user_obj.roles.all().values('permission__url')    权限列表构造    session保存def login(request):    if request.method == 'POST':        username = request.POST.get('username')        password = request.POST.get('password')        user_obj = models.User.objects.filter(name=username,pwd=password).first()        if user_obj:            # 记录登陆状态            request.session['user'] = username            # 记录权限列表            permission_list = []            res = user_obj.roles.values('permissions__url').distinct()            for permission in res:                permission_list.append(permission.get('permissions__url'))            request.session['permission_list'] = permission_list    return render(request,'login.html')"""

中间件校验权限

"""整体流程:    1.用户访问白名单        利用正则    2.判断用户是否登陆    3.获取用户权限并进行校验        利用正则(并需要手动加限制"^$")        注册到settings文件中讲课推理:    1.判断用户是否登陆    2.获取权限校验        for循环直接判断在不在        正则校验判断        # 判断是否有权访问        import re        for permission_rex in permission_list:            permission_rex = '^%s$'%permission_rex            res = re.search(permission_rex,current_path)            if res:                return None        return HttpResponse('没有访问权限')            3.用户访问白名单        放开以admin打头的所有访问权限(正则)                """

前端样式调整

"""1.模板中加导航条和侧边栏以及整体样式微调"""

权限展示

"""1.前端页面需要展示菜单权限,但是并不是所有权限都要展示,也并不是都展示在一个主菜单下(通常只展示查看权限),所以我们应该想个办法区分权限的种类>>>权限表添加code字段标识权限种类(首页导航条右侧登陆用户展示,注销按钮)2.后端login视图函数中除了之前构建的权限列表外,需要再构建当前登录用户的权限名称,url,权限类型的列表套字典格式方便左侧菜单渲染            # 菜单权限展示            permission_menu_list = []            for permission in permissions:                permissions_list.append(permission.get('permissions__url'))                if permission.get('permissions__code') == 'list':                    permission_menu_list.append({                        'title':permission.get("permissions__title"),                        'url':permission.get("permissions__url")                    })            # 存储菜单权限            request.session['permission_menu_list'] = permission_menu_list"""

CRM关系表

from django.db import models# Create your models here.class User(models.Model):    name = models.CharField(max_length=64)    password = models.CharField(max_length=128)    roles = models.ManyToManyField(to='Role')    def __str__(self):        return self.nameclass Role(models.Model):    title = models.CharField(max_length=64)    permissions = models.ManyToManyField(to='Permission')    def __str__(self):        return self.titleclass Permission(models.Model):    title = models.CharField(max_length=64)    url = models.CharField(max_length=128)    code = models.CharField(max_length=64,default='list')    def __str__(self):        return self.title# CRM关系表class Department(models.Model):    """    部门表    市场部     1000    销售       1001    """    title = models.CharField(verbose_name='部门名称', max_length=16)    code = models.IntegerField(verbose_name='部门编号', unique=True, null=False)    def __str__(self):        return self.titleclass UserInfo(models.Model):    """    员工表    """    name = models.CharField(verbose_name='员工姓名', max_length=16)    email = models.EmailField(verbose_name='邮箱', max_length=64)    depart = models.ForeignKey(verbose_name='部门', to="Department",to_field="code")    user=models.OneToOneField("User",default=1)    def __str__(self):        return self.nameclass Course(models.Model):    """    课程表    如:        Linux基础        Linux架构师        Python自动化开发精英班        Python自动化开发架构师班        Python基础班        go基础班    """    name = models.CharField(verbose_name='课程名称', max_length=32)    def __str__(self):        return self.nameclass School(models.Model):    """    校区表    如:        北京沙河校区        上海校区    """    title = models.CharField(verbose_name='校区名称', max_length=32)    def __str__(self):        return self.titleclass 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)    memo = models.CharField(verbose_name='说明', max_length=256, blank=True, null=True, )    teachers = models.ManyToManyField(verbose_name='任课老师', to='UserInfo')    tutor = models.ForeignKey(verbose_name='班主任', to='UserInfo',related_name="class_list")    def __str__(self):        return "{0}({1}期)".format(self.course.name, self.semester)class Customer(models.Model):    """    客户表    """    qq = models.CharField(verbose_name='qq', max_length=64, unique=True, help_text='QQ号必须唯一')    name = models.CharField(verbose_name='学生姓名', max_length=16)    gender_choices = ((1, '男'), (2, '女'))    gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)    education_choices = (        (1, '重点大学'),        (2, '普通本科'),        (3, '独立院校'),        (4, '民办本科'),        (5, '大专'),        (6, '民办专科'),        (7, '高中'),        (8, '其他')    )    education = models.IntegerField(verbose_name='学历', choices=education_choices, blank=True, null=True, )    graduation_school = models.CharField(verbose_name='毕业学校', max_length=64, blank=True, null=True)    major = models.CharField(verbose_name='所学专业', max_length=64, blank=True, null=True)    experience_choices = [        (1, '在校生'),        (2, '应届毕业'),        (3, '半年以内'),        (4, '半年至一年'),        (5, '一年至三年'),        (6, '三年至五年'),        (7, '五年以上'),    ]    experience = models.IntegerField(verbose_name='工作经验', blank=True, null=True, choices=experience_choices)    work_status_choices = [        (1, '在职'),        (2, '无业')    ]    work_status = models.IntegerField(verbose_name="职业状态", choices=work_status_choices, default=1, blank=True,                                      null=True)    company = models.CharField(verbose_name="目前就职公司", max_length=64, blank=True, null=True)    salary = models.CharField(verbose_name="当前薪资", max_length=64, blank=True, null=True)    source_choices = [        (1, "qq群"),        (2, "内部转介绍"),        (3, "官方网站"),        (4, "百度推广"),        (5, "360推广"),        (6, "搜狗推广"),        (7, "腾讯课堂"),        (8, "广点通"),        (9, "高校宣讲"),        (10, "渠道代理"),        (11, "51cto"),        (12, "智汇推"),        (13, "网盟"),        (14, "DSP"),        (15, "SEO"),        (16, "其它"),    ]    source = models.SmallIntegerField('客户来源', choices=source_choices, default=1)    referral_from = models.ForeignKey(        'self',        blank=True,        null=True,        verbose_name="转介绍自学员",        help_text="若此客户是转介绍自内部学员,请在此处选择内部学员姓名",        related_name="internal_referral"    )    course = models.ManyToManyField(verbose_name="咨询课程", to="Course")    status_choices = [        (1, "已报名"),        (2, "未报名")    ]    status = models.IntegerField(        verbose_name="状态",        choices=status_choices,        default=2,        help_text=u"选择客户此时的状态"    )    consultant = models.ForeignKey(verbose_name="课程顾问", to='UserInfo', related_name='consultanter' )    date = models.DateField(verbose_name="咨询日期", auto_now_add=True)    recv_date = models.DateField(verbose_name="当前课程顾问的接单日期", null=True)    last_consult_date = models.DateField(verbose_name="最后跟进日期", )    def __str__(self):        return self.nameclass ConsultRecord(models.Model):    """    客户跟进记录    """    customer = models.ForeignKey(verbose_name="所咨询客户", to='Customer')    consultant = models.ForeignKey(verbose_name="跟踪人", to='UserInfo')    date = models.DateField(verbose_name="跟进日期", auto_now_add=True)    note = models.TextField(verbose_name="跟进内容...")    def __str__(self):        return self.customer.name + ":" + self.consultant.nameclass Student(models.Model):    """    学生表(已报名)    """    customer = models.OneToOneField(verbose_name='客户信息', to='Customer')    class_list = models.ManyToManyField(verbose_name="已报班级", to='ClassList', blank=True)    emergency_contract = models.CharField(max_length=32, blank=True, null=True, verbose_name='紧急联系人')    company = models.CharField(verbose_name='公司', max_length=128, blank=True, null=True)    location = models.CharField(max_length=64, verbose_name='所在区域', blank=True, null=True)    position = models.CharField(verbose_name='岗位', max_length=64, blank=True, null=True)    salary = models.IntegerField(verbose_name='薪资', blank=True, null=True)    welfare = models.CharField(verbose_name='福利', max_length=256, blank=True, null=True)    date = models.DateField(verbose_name='入职时间', help_text='格式yyyy-mm-dd', blank=True, null=True)    memo = models.CharField(verbose_name='备注', max_length=256, blank=True, null=True)    def __str__(self):        return self.customer.nameclass ClassStudyRecord(models.Model):    """    上课记录表 (班级记录)    """    class_obj = models.ForeignKey(verbose_name="班级", to="ClassList")    day_num = models.IntegerField(verbose_name="节次", help_text=u"此处填写第几节课或第几天课程...,必须为数字")    teacher = models.ForeignKey(verbose_name="讲师", to='UserInfo')    date = models.DateField(verbose_name="上课日期", auto_now_add=True)    course_title = models.CharField(verbose_name='本节课程标题', max_length=64, blank=True, null=True)    course_memo = models.TextField(verbose_name='本节课程内容概要', blank=True, null=True)    has_homework = models.BooleanField(default=True, verbose_name="本节有作业")    homework_title = models.CharField(verbose_name='本节作业标题', max_length=64, blank=True, null=True)    homework_memo = models.TextField(verbose_name='作业描述', max_length=500, blank=True, null=True)    exam = models.TextField(verbose_name='踩分点', max_length=300, blank=True, null=True)    def __str__(self):        return "{0} day{1}".format(self.class_obj, self.day_num)class StudentStudyRecord(models.Model):    '''    学生学习记录    '''    classstudyrecord = models.ForeignKey(verbose_name="第几天课程", to="ClassStudyRecord")    student = models.ForeignKey(verbose_name="学员", to='Student')    record_choices = (('checked', "已签到"),                      ('vacate', "请假"),                      ('late', "迟到"),                      ('noshow', "缺勤"),                      ('leave_early', "早退"),                      )    record = models.CharField("上课纪录", choices=record_choices, default="checked", max_length=64)    score_choices = ((100, 'A+'),                     (90, 'A'),                     (85, 'B+'),                     (80, 'B'),                     (70, 'B-'),                     (60, 'C+'),                     (50, 'C'),                     (40, 'C-'),                     (0, ' D'),                     (-1, 'N/A'),                     (-100, 'COPY'),                     (-1000, 'FAIL'),                     )    score = models.IntegerField("本节成绩", choices=score_choices, default=-1)    homework_note = models.CharField(verbose_name='作业评语', max_length=255, blank=True, null=True)    note = models.CharField(verbose_name="备注", max_length=255, blank=True, null=True)    homework = models.FileField(verbose_name='作业文件', blank=True, null=True, default=None)    stu_memo = models.TextField(verbose_name='学员备注', blank=True, null=True)    date = models.DateTimeField(verbose_name='提交作业日期', auto_now_add=True)    def __str__(self):        return "{0}-{1}".format(self.classstudyrecord, self.student)

数据录入

"""学校课程部门用户信息班级按照models.py中模型表的顺序依次添加,添加过程中需要引入的知识点有1.添加班级表记录时,授课老师和班主任信息展示需要用到limit_choices_to    limit_choices_to={'depart_id':170}  >>>     单个部门    limit_choices_to={'depart_id__in':[120,150]}    >>>     多个部门2.客户表    录入数据后,展示客户性别引出get_field_display()展示choice字段对应的注解        def display_gender(self,is_header=False,obj=None):            if is_header:                return '性别'            return obj.get_gender_display()        按照上述方式,只要是有choice字段的都可按照此法展示3.展示咨询课程    3.1将咨询课程全部做成a标签的样式,然后提出a标签的需求:        点哪个a标签就将该a标签对应的客户咨询课程删除    3.2删除的是某一客户的咨询课程,而我们stark组件只会为每一个模型表创建增删改查四条基本的url,这个问题如何解决?        先去stark组件源码二级路由分发处演示思路,直接在get_urls()演示            def get_urls(self):                tmp = [                    url(r'^$',self.list_view,name='%s_%s_list'%(self.app_label,self.model_name)),                    url(r'^add/',self.add_view,name='%s_%s_add'%(self.app_label,self.model_name)),                    url(r'^edit/(\d+)/',self.edit_view,name='%s_%s_edit'%(self.app_label,self.model_name)),                    url(r'^delete/(\d+)/',self.delete_view,name='%s_%s_delete'%(self.app_label,self.model_name))                ]                tmp.append(                    url(r'^.../',删除客户咨询某一课程记录)                )                return tmp       这样做的缺陷就是会生成很多条相同的url,如何做到只为某一个模型表配置额外的url?       (你们想想list_display,actions这些功能是怎么玩的???)       a标签渲染        def display_course(self,is_header=False,obj=None):            if is_header:                return '咨询课程'            course_list =  []            for course in obj.course.all():                course_list.append("%s"%(obj.pk,course.pk,course.name))            return mark_safe(' '.join(course_list))                   自定义扩张url方法        def extra_url(self):            tmp = []            tmp.append(            url(r'^cancel_course/(\d+)/(\d+)/',self.cancel_course)            )            return tmp                    自定义视图函数        def cancel_course(self,request,customer_id,course_id):            customer_obj = models.Customer.objects.filter(pk=customer_id).first()            customer_obj.course.remove(course_id)            return redirect(self.get_reverse_url('list'))                    stark组件新增一个空的extra_url方法,用户不配置就无任何多余的url        def extra_url(self):            return []   """

剩余四张表

"""1.咨询记录表信息录入2.学生信息录入3.课程记录    stark组件源码增加自动识别get_field_display()4.学习记录    根据课程记录批量生成对应的学习记录        利用actions自定义批量生成函数    def patch_studyrecord(self,request,queryset):        tmp = []        for course_record in queryset:                                              student_list=Student.objects.filter(class_list__id=course_record.class_obj.pk)        for student in student_list:            obj = StudyRecord(student=student,course_record=course_record)            tmp.append(obj)        StudyRecord.objects.bulk_create(tmp)5.学习记录筛选    筛选当天学习记录    利用list_filter功能        def get_filter(self,request,queryset):        q = Q()        for field,field_id in request.GET.items():            if field in ['page','q']:                continue            field_id = request.GET.get(field)            q.children.append((field, field_id))        queryset = queryset.filter(q)        return queryset    学习记录中自定义记录列点击记录跳转到对应的学生学习记录    def record(self,is_header=False,obj=None):        if is_header:            return '记录'        _url = '/stark/app01/studentstudyrecord/?classstudyrecord=%s'%obj.pk        return mark_safe("记录"%_url)    list_display = ['class_obj','day_num',record]    考勤功能    def work(self,is_header=False,obj=None):        if is_header:            return '考勤'        html = ''        for k in obj.record_choices:            if obj.record == k[0]:                s = ""%k            else:                s = ""%k            html += s        return mark_safe(""%(obj.pk,html))    def check(self,request):        status = request.POST.get('status')        pk = request.POST.get('pk')        print(status,pk)        models.StudentStudyRecord.objects.filter(pk=pk).update(record=status)        return HttpResponse('ok')    def extra_url(self):        tmp = []        tmp.append(            url(r'^check_work/',self.check)        )        return tmp                        window.onload = function () { $('.xxx').change(function () {     var status = $(this).val();     var pk = $(this).attr('pk');     $.ajax({         url:'/stark/app01/studentstudyrecord/check_work/',         type:'post',         data:{             status:status,             pk:pk         },         success:function (data) {             console.log(data)         }     }) })};"""
 
 
 
 

Django知识点回顾

"""1.django请求生命周期    http协议:        四大特性:            1.基于scoket应用于应用层的协议            2.基于请求响应的协议            3.无连接            4.无状态    WSGI协议:wsgiref,uwsgi,werkzeug实现模块    中间件:默认七个中间件,五个可自定义方法,全局访问频率限制,权限限制等        process_request  请求刚进来时        process_view    经过url执行视图函数之前        process_template_response   视图函数中return render时触发        process_exception       视图函数中报错执行        process_response    返回相应响应时            urls.py:路由控制器    MTV:        views.py:            视图层:FBV,CBV                CBV可张开讲:from django.views import View                看一下源码                            返回结果必须是HttpResponse对象                    templates.py:            模板语法:变量相关{
{}},逻辑相关{%%} models.py: ORM操作 2.django session机制 request.session仅仅只是产生缓存,真正起作用还是中间件 3.form组件 auth认证 简单提一嘴4.django settings文件配置5.前后端传输数据编码格式 简单前后端传输页面代码搭建 http传输数据格式书写 三种常见编码格式总结 urlencoded form-data json 请求体数据格式推导(先瞎猜,再用事实验证) 请求首行作用ContentType参数作用 浏览器查看form表单默认提交方式以及组织数据格式 ajax提交数据(默认提交,json提交>>>前后端分离) request.POST无法解析>>>request.body存储原始数据 """

admin使用

"""打开博客园django-admin组件,介绍admin是啥    django自带的一个后台管理组件,快速的帮我们完成对数据的增删改查操作,我们这会是要学习admin的使用,并模仿它(及参考admin的源码)开发一套我们自己的后台管理工具    新建项目,直接访问,需要超级用户博客园拷贝图书馆管理系统表格,数据库迁移并注册到admin中后台模型表展示添加一条数据后先总结url的规律模型表路由规律总结    路由中都有admin是因为它是一个组件        推导另外一个模型表的url规律    总结:    admin为每一个注册了的模型表创建增删改查四条url你们用admin应该只到这一步吧,接下来我们继续往深里看所有表的展示页面是不是都是一样的,现在我想对某个表设置不一样的展示,咋弄?再来五大重点参数介绍    模型表继承admin.ModelAdmin        list_display >>> 演示这个效果之后 看一点源码 配置类概念>>>阐释配置类概念        为何要继承ModelAdmin        list_display_links    search_field    list_filter    actions        讲action时,复习一个前端知识,单选多选getlist()    1.启动源码    django启动,执行每一个app下的admin.py文件    原因:autodiscover_module('admin')单例模式复习    对照博客    重点在基于模块的单例模式上        诠释模块导入重复导入只加载一次的特性pyc地方        再写一个py文件,写一个函数里面调,然后去另外一个文件调函数    再来个坑:导类过来,实例化两次,求打印结果?2.admin注册源码摘取精髓部分class AdminSite(object):    def __init__(self, name='admin'):        self._registry = {}    def register(self, model_or_iterable, admin_class=None, **options):        if not admin_class:            admin_class = ModelAdmin        self._registry[model] = admin_class(model, self)site=AdminSite()# **************************源码**************************admin.site.register(Book)admin.site.register(Book,BookConfig)引出配置类作用,self._registry中数据存放格式打印_registry里面数据带他们看看  这里慢点讲!!!"""

3.url设计

"""1.url分发本质url(r'^index/', ([],None,None))  # 固定写法元祖里面三个参数2.一级,二级分发演示url(r'^stark/',([],None,None))第一次推导    url(r'^index/',([            url(r'^test01/',test01),            url(r'^test02/',test02)    ],None,None))第二次推导    url(r'^index/',([        url(r'^test01/',([            url(r'^test01_1',test01_1),             url(r'^test01_2',test01_2),            url(r'^test01_3',test01_3),        ],None,None)),        url(r'^test02/',test02)    ],None,None))自己生成注册了的模型表的urldef list_view(request):    return HttpResponse('list_view')def add_view(request):    return HttpResponse('add_view')def edit_view(request,id):    return HttpResponse('edit_view')def delete_view(request,id):    return HttpResponse('delete_view')def get_urls1():    tmp = [        url(r'^$',list_view),        url(r'^add/',add_view),        url(r'^edit/(\d+)/',edit_view),        url(r'^delete/(\d)/',delete_view)    ]    return tmpdef get_urls():    tmp = []    for class_model,config_obj in admin.site._registry.items():        app_label = class_model._meta.app_label        model_name = class_model._meta.model_name        tmp.append(            url(r'%s/%s/'%(app_label,model_name),(get_urls1(),None,None))        )    return tmpurlpatterns = [    url(r'^admin/', admin.site.urls),    url(r'^stark/',(get_urls(),None,None))]"""

CRM项目开始

"""组件也是应用,一个项目有多个应用,一个应用可以用在多个项目里1.admin启动源码(django配置文件整体梳理>>>注册的app中admin)2.autodiscover_modules应用3.新建django项目>>>stark应用>>>service文件夹4.admin源码摘取 + 配置类5.url设计    研究url(r'^admin/', admin.site.urls)源码    一级分发    二级分发(配置类介绍)6.总结回顾    解释一下二级分发那个self到底是谁    7.视图函数中self.model诠释8.展示各个模型表数据对象9.依据list_display详细展示数据对象    表单展示    表头展示        verbose_name介绍 model._meta.get_field('字段名').verbose_name    小bug调试,表头后端代码筛选__str__特殊情况        对象反射拿__str__不报错的原因>>>联想到迭代器__next__,嫌麻烦,可以写成next()        10.单张表的自定义数据列 选择 编辑 删除>>>拓展至全局配置    详细讲        先用户自定义 再转成全局配置        获取表头表单内部代码优化11.选择 编辑 删除标识性参数设置12.反向解析13.list_display_links        自定义编辑列根据list_display_links显隐展示"""

form与modelform

"""2.form组件介绍    演示form本质应用    class TestForm(forms.Form):        name = forms.CharField(max_length=32)        email = forms.EmailField()        age = forms.IntegerField()            python console中直接测试    from app01 import views    obj = views.TestForm({'name':'jason','email':'123','age':18})    obj.is_valid()  # 校验数据    False    obj.cleaned_data  # 合格的放入这个里面    {'name': 'jason', 'age': 18}    obj.errors  # 不合格的放入errors中    {'email': ['Enter a valid email address.']}        继续演示几种传参类型    obj = views.TestForm({'name':'jason','age':18})    obj = views.TestForm({'name':'jason','email':"123@qq.com",'age':18})    obj = views.TestForm({'name':'jason','email':"123@qq.com",'age':18,'abc':123})    3.form组件完成    class Book(models.Model):        title = models.CharField(max_length=32)        price = models.DecimalField(max_digits=8,decimal_places=2)        date = models.DateField()        publish = models.ForeignKey("Publish")        authors = models.ManyToManyField("Author")    class Publish(models.Model):        name = models.CharField(max_length=32)    class Author(models.Model):        name = models.CharField(max_length=32)对上述三张表用form完成增  >>>  编辑功能form组件书写难度1.新建django项目 自定义模型表这里详细演戏图书管理系统的增删改查:    1.先不借助任何组件,自己手动渲染标签        这里需要注意的问题有前端input标签一定要写name属性        后端在更新数据的时候,记得用关键字传参的形式去做        新增用add(*author) 编辑用set(author)            2.借助form组件        前端三种渲染方式            3.最后推到出modelform组件        class BookModelForm(forms.ModelForm):            class Meta:                model = models.Book                fields = '__all__'4.modelform介绍"""
"""1.modelform完成CRM项目中模型表的增删改查    这里为什么定义这个方法,主要是用户如果想针对自己的模型表进行其他的特定操作    def get_model_form(self):        if self.model_form_class:            return self.model_form_class        from django.forms import ModelForm        class ModelFormClass(ModelForm):            class Meta:                model = self.model                fields = '__all__'        return ModelFormClass                def add_view(self,request):            model_form = self.get_model_form()            if request.method == 'POST':                model_form_obj = model_form(request.POST)                if model_form_obj.is_valid():                    model_form_obj.save()                    return redirect(self.get_reverse_url('list'))            model_form_obj = model_form()            return render(request,'stark/add_view.html',locals())                    def edit_view(self,request,id):            model_form = self.get_model_form()            edit_obj = self.model.objects.filter(pk=id).first()            if request.method == 'POST':                model_form_obj = model_form(request.POST,instance=edit_obj)                if model_form_obj.is_valid():                    model_form_obj.save()                    return redirect(self.get_reverse_url('list'))            model_form_obj = model_form(instance=edit_obj)            return render(request,'stark/edit_view.html',locals())                    def delete_view(self,request,id):            delete_obj = self.model.objects.filter(pk=id).delete()            return redirect(self.get_reverse_url('list'))"""

分页

"""1.批量插入数据方法    传统:效率极低        def index(request):            for i in range(100):                Book.objects.create(title='book_%s'%i,price=i*i)            return render(request,'book_list.html')    现在:        book_list = []  # 里面方法Book对象        for i in range(100):            book = Book(title="book_%s"%i,price=i*i)            book_list.append(book)        Book.objects.bulk_create(book_list)2.展示批量产生的数据 3.分页介绍    博客园分页代码拷贝,解释    保存搜索条件介绍(拉勾网展示)    request.GET.urlencoded()构造get请求携带数据格式"""

数据展示类

"""1.数据展示全部封装到新的Showlist展示类中"""

search功能

"""1.bootstrap中找寻前端样式    css样式   >>>     表单2.后端模拟简单版本实现效果    # search功能  简单推导1    key_word = request.GET.get('q')    if key_word:        for field in self.search_fields:            queryset = self.model.objects.filter(title__icontains=key_word)3.如何解决查询条件关键字 title__icontains拼接?    Q对象简介        # python console中演示推导过程1        from app01 import models        from django.db.models import Q        models.Book.objects.filter(title='西游记')        
]> models.Book.objects.filter(Q(title='西游记')|Q(price=399))
,
]> # 推导过程2 q = Q() q.children.append(('title','西游记')) models.Book.objects.filter(q)
]> # 推导过程3多个条件 q = Q() q.children.append(('title','西游记')) models.Book.objects.filter(q)
]> q.children.append(('price','399')) models.Book.objects.filter(q)
# 最终推导 from django.db.models import Q q = Q() q.children.append(("字段名","可能存在的字段值")) # 特点在于 直接写的是字符串 q.connector = "or" # q添加数据默认是和的关系,可通过该参数改变 Models.objects.filter(q) # 以q里面添加的条件筛选相应数据4.要想实现模糊查询需要 q.children.append(("字段名"+"__icontains","可能存在的字段值")) 5.search功能实现6.search功能封装配置类方法7.search功能前端搜索保留搜索条件 配置类对象添加key_word属性8.search功能前端界面显隐 根据key_word属性控制"""

action功能

"""1.django admin后台action功能演示2.前端样式        3.点击提交按钮需要将checkbox选中数据与select选择框中的数据提交到后端,所以需要保证二者在一个form表单中    
{% csrf_token %}

filter功能

"""1.admin list_filter功能演示,展示的其实是一个个的数据对象2.前端页面搭建    
FILTER
3.后端 分析: 1.list_filter中只能放外键字段 2.先循环字段,取出该字段对应的模型表,再取每个字段对应的多组数据 model._meta.get_field('字段').rel.to >>> 模型表 3.深拷贝request.GET 获取get请求参数 保存搜索条件 4.all标签渲染 由于传输数据格式为[{'外键字段':[a,b,c,d...],'外键字段':[e,f,g,h...]}] 每个外键字段对应的列表中都需要一个all标签,而all标签的作用就是去除其所在字段在url中的键值,也就是说只需要pop掉当前循环的字段即可 def get_list_filter(self): tmp_dict = {} for field in self.config_obj.list_filter: tmp = [] relation_model = self.config_obj.model._meta.get_field(field).rel.to queryset = relation_model.objects.all() import copy params = copy.deepcopy(self.request.GET) click_id = self.request.GET.get(field) # all标签 params2 = copy.deepcopy(self.request.GET) if field in params2: params2.pop(field) all_link = "All" % params2.urlencode() else: all_link = "All" tmp.append(mark_safe(all_link)) for data in queryset: params[field] = data.pk _url = params.urlencode() if click_id == str(data.pk): s = "%s" % (_url, data) else: s = '%s' % (_url, data) tmp.append(mark_safe(s)) tmp_dict[field] = tmp return tmp_dic4.前端
FILTER
{% for k,v in show_obj.get_list_filter.items %}
By {
{ k|upper }}
{% for data in v %}

{

{ data }}

{% endfor %}
{% endfor %}
5.数据过滤 外键字段查询时 model.objects.filter(publish__id=1) model.objects.filter(publish=obj) 同样也支持 model.objects.filter(publish=1) >>> 自动转换成第一种 所以我们再利用q对象往children里面添加数据时可以直接('publishs',1) """

open样式演示

"""新建django项目演示open方法    1.window.open 方法        window.open('https://www.baidu.com','','height=400,width=800')    2.填写自己的路由,打开添加页面    3.填写数据,window.opener调用父类方法    4.如何将创建出来的数据渲染到父页面>>>后端将数据对象传递到子页面,子页面传到父页面    5.window.open路由中添加前端标签id,后端接收再传递到子页面,子页面再传到父页面        后端充当中间商,只做数据传输"""

pop功能

"""1.admin查看效果2.加号渲染(必须是一对多或多对多字段,如何判断?)    我们后台循环的字段是model字段还是form字段?是form字段,意味着没法通过ForeignKey,ManyToManyField判断,因为是form字段    后端先打印每个字段的类型发现均是BoundField类型,无法判断    需要拿字段对象再点field属性才能取到真经    isinstance可以判断多继承关系    前端如何根据条件渲染这个加号呢?后端给field字段对象添加is_pop=True属性3.前端加号样式通过相对移动调节样式open样式演示完之后再回来1.加号事件绑定    路由问题解决,不同加号对应不同的添加页面>>>字段对象能加is_pop属性,能不能再加一个url属性,到时候直接点拿出来就行了(注意一定要放到form字段属性中)        后端form字段对象如何获取对应的model字段的字段名        不能用self.model 因为它是当前访问的表的添加页面,而加号对应的另外两个表的添加页面,所以这里需要我们手动反向解析url        需要获取到加号字段对应的模型表            form字段.name >>> form字段对应的model字段字段名            self.model._meta.get_filed(form字段.name).rel.to >>> 表            _url = reverse("%s_%s_add",xx,yy) 解决添加url                select标签id查找        谷歌浏览器查看 id_publish,id_authors        form字段.name 拿到对应model字段的字段名            _url = _url+"?pop_back_id=id_"+form字段.name            这是我们手动拼接,还可以自动拼接            _url = _url +"?pop_back_id="+form字段.auto_id          后端添加页面不能直接返回pop页面,不然的话我们连正常打开的pop页面也会打不开,所以需要根据url中是否有pop_back_id来判断是正常访问还是加号跳转        pop页面调用父页面传pop_back_id,pk,text        父页面DOM操作添加标签        新添加的数据需要添加selected属性    """

Stark组件Bug调整

"""数据展示的时候,点分页会报错,因为会把page=x传到了filter中,还有就是search查询中的q=x也会报错,所以在filter功能中加if判断去掉    if field in ['page','q']        continue还有就是这样写了之后如果在url中手动条件额外不存在的键值还是会报错                try:                    queryset = queryset.filter(q)                except BaseException:                    pass"""

Stark组件总结

"""从头到尾捋一遍"""

权限介绍

"""1.什么是权限?    生活中到处都是权限,比如我们办公室密码门,视频vip,等等...    再回来我们写的web应用,一个公司里面老板和员工用的同一个web服务,两者能干的事也是各不相同    再来看Django admin应用,访问模型表的增删改查这是不是也是一种权限    总的来说就是    who             what            how    哪些人对哪些资源拥有哪些操作的权限,看admin的url    http://127.0.0.1:8000/admin/auth/user/对auth下面的user表数据查看权限    http://127.0.0.1:8000/admin/auth/user/1/change/对auth下面的user表数据的修改权限    http://127.0.0.1:8000/admin/auth/user/1/delete/对auth下面的user表数据的删除权限    http://127.0.0.1:8000/admin/auth/user/add/对auth下面的user表数据的增加权限    权限其实就是一个个的url,用户可以访问的url放在一个大列表里,访问对应url的时候,去列表里查找,如果有就代表可以访问,拥有该权限,没有就是禁止访问,没有权限。2.定义几张表模拟一下    class User:        pass    class Permission:        pass    class user2permission:        pass    1.创建俩用户一个拥有查,一个拥有查改    2.一下子来了十个员工,都拥有增删改查四个权限,那我需要在第三张表里面反复录入"""

RBAC(Roel Based Access Control)

"""1.介绍日常生活中的应用软件怎么区分权限的?普通用户,超级管理员,经理,职员...是不是都是基于角色的权限管理,每一个角色对应有一定的权限,用户只需按角色划分,就能有对应的权限2.表关系class User:    passclass Role:    passclass Permission:    passclass user2role:    passclass role2permission:    pass一次性有100个员工,你会发现方案1和方案2差距很大!!!   """

项目搭建

"""1.新建django项目,stark组件移植过来    知识点:        templates文件查找会先从项目根目录找,其次会去应用下面找,再找不到报错        static文件亦是如此,注意在拖拽的时候,防止pycharm自动加stark前缀,需要手动去除掉,任然以staic开头        2.创建模型表并注册到stark组件中    class User(models.Model):        name = ...        pwd = ...        roles = ...    class Role(model.Model):        title = ...        permissions = ...    class Permission(model.Model):        title = ...        url = ...3.启动项目 添加数据    权限表         角色和用户的增删改查    角色表        销售      查看 添加用户        讲师      查看        CEO      用户的增删改查        管理员     所有权限    用户表        kevin   销售+讲师        egon    CEO        jason   管理员权限思路:    1.创建表,录入数据    2.登陆验证,获取登陆人的权限    3.权限校验5.登陆校验获取登陆人的权限    简单的前端登陆页面    后端获取查询校验        需要慢一点的地方在于如何基于用户对象查询权限信息            user_obj.roles.all()  >>> 角色对象            user_obj.roles.all().values('permission__url')    权限列表构造    session保存def login(request):    if request.method == 'POST':        username = request.POST.get('username')        password = request.POST.get('password')        user_obj = models.User.objects.filter(name=username,pwd=password).first()        if user_obj:            # 记录登陆状态            request.session['user'] = username            # 记录权限列表            permission_list = []            res = user_obj.roles.values('permissions__url').distinct()            for permission in res:                permission_list.append(permission.get('permissions__url'))            request.session['permission_list'] = permission_list    return render(request,'login.html')"""

中间件校验权限

"""整体流程:    1.用户访问白名单        利用正则    2.判断用户是否登陆    3.获取用户权限并进行校验        利用正则(并需要手动加限制"^$")        注册到settings文件中讲课推理:    1.判断用户是否登陆    2.获取权限校验        for循环直接判断在不在        正则校验判断        # 判断是否有权访问        import re        for permission_rex in permission_list:            permission_rex = '^%s$'%permission_rex            res = re.search(permission_rex,current_path)            if res:                return None        return HttpResponse('没有访问权限')            3.用户访问白名单        放开以admin打头的所有访问权限(正则)                """

前端样式调整

"""1.模板中加导航条和侧边栏以及整体样式微调"""

权限展示

"""1.前端页面需要展示菜单权限,但是并不是所有权限都要展示,也并不是都展示在一个主菜单下(通常只展示查看权限),所以我们应该想个办法区分权限的种类>>>权限表添加code字段标识权限种类(首页导航条右侧登陆用户展示,注销按钮)2.后端login视图函数中除了之前构建的权限列表外,需要再构建当前登录用户的权限名称,url,权限类型的列表套字典格式方便左侧菜单渲染            # 菜单权限展示            permission_menu_list = []            for permission in permissions:                permissions_list.append(permission.get('permissions__url'))                if permission.get('permissions__code') == 'list':                    permission_menu_list.append({                        'title':permission.get("permissions__title"),                        'url':permission.get("permissions__url")                    })            # 存储菜单权限            request.session['permission_menu_list'] = permission_menu_list"""

CRM关系表

from django.db import models# Create your models here.class User(models.Model):    name = models.CharField(max_length=64)    password = models.CharField(max_length=128)    roles = models.ManyToManyField(to='Role')    def __str__(self):        return self.nameclass Role(models.Model):    title = models.CharField(max_length=64)    permissions = models.ManyToManyField(to='Permission')    def __str__(self):        return self.titleclass Permission(models.Model):    title = models.CharField(max_length=64)    url = models.CharField(max_length=128)    code = models.CharField(max_length=64,default='list')    def __str__(self):        return self.title# CRM关系表class Department(models.Model):    """    部门表    市场部     1000    销售       1001    """    title = models.CharField(verbose_name='部门名称', max_length=16)    code = models.IntegerField(verbose_name='部门编号', unique=True, null=False)    def __str__(self):        return self.titleclass UserInfo(models.Model):    """    员工表    """    name = models.CharField(verbose_name='员工姓名', max_length=16)    email = models.EmailField(verbose_name='邮箱', max_length=64)    depart = models.ForeignKey(verbose_name='部门', to="Department",to_field="code")    user=models.OneToOneField("User",default=1)    def __str__(self):        return self.nameclass Course(models.Model):    """    课程表    如:        Linux基础        Linux架构师        Python自动化开发精英班        Python自动化开发架构师班        Python基础班        go基础班    """    name = models.CharField(verbose_name='课程名称', max_length=32)    def __str__(self):        return self.nameclass School(models.Model):    """    校区表    如:        北京沙河校区        上海校区    """    title = models.CharField(verbose_name='校区名称', max_length=32)    def __str__(self):        return self.titleclass 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)    memo = models.CharField(verbose_name='说明', max_length=256, blank=True, null=True, )    teachers = models.ManyToManyField(verbose_name='任课老师', to='UserInfo')    tutor = models.ForeignKey(verbose_name='班主任', to='UserInfo',related_name="class_list")    def __str__(self):        return "{0}({1}期)".format(self.course.name, self.semester)class Customer(models.Model):    """    客户表    """    qq = models.CharField(verbose_name='qq', max_length=64, unique=True, help_text='QQ号必须唯一')    name = models.CharField(verbose_name='学生姓名', max_length=16)    gender_choices = ((1, '男'), (2, '女'))    gender = models.SmallIntegerField(verbose_name='性别', choices=gender_choices)    education_choices = (        (1, '重点大学'),        (2, '普通本科'),        (3, '独立院校'),        (4, '民办本科'),        (5, '大专'),        (6, '民办专科'),        (7, '高中'),        (8, '其他')    )    education = models.IntegerField(verbose_name='学历', choices=education_choices, blank=True, null=True, )    graduation_school = models.CharField(verbose_name='毕业学校', max_length=64, blank=True, null=True)    major = models.CharField(verbose_name='所学专业', max_length=64, blank=True, null=True)    experience_choices = [        (1, '在校生'),        (2, '应届毕业'),        (3, '半年以内'),        (4, '半年至一年'),        (5, '一年至三年'),        (6, '三年至五年'),        (7, '五年以上'),    ]    experience = models.IntegerField(verbose_name='工作经验', blank=True, null=True, choices=experience_choices)    work_status_choices = [        (1, '在职'),        (2, '无业')    ]    work_status = models.IntegerField(verbose_name="职业状态", choices=work_status_choices, default=1, blank=True,                                      null=True)    company = models.CharField(verbose_name="目前就职公司", max_length=64, blank=True, null=True)    salary = models.CharField(verbose_name="当前薪资", max_length=64, blank=True, null=True)    source_choices = [        (1, "qq群"),        (2, "内部转介绍"),        (3, "官方网站"),        (4, "百度推广"),        (5, "360推广"),        (6, "搜狗推广"),        (7, "腾讯课堂"),        (8, "广点通"),        (9, "高校宣讲"),        (10, "渠道代理"),        (11, "51cto"),        (12, "智汇推"),        (13, "网盟"),        (14, "DSP"),        (15, "SEO"),        (16, "其它"),    ]    source = models.SmallIntegerField('客户来源', choices=source_choices, default=1)    referral_from = models.ForeignKey(        'self',        blank=True,        null=True,        verbose_name="转介绍自学员",        help_text="若此客户是转介绍自内部学员,请在此处选择内部学员姓名",        related_name="internal_referral"    )    course = models.ManyToManyField(verbose_name="咨询课程", to="Course")    status_choices = [        (1, "已报名"),        (2, "未报名")    ]    status = models.IntegerField(        verbose_name="状态",        choices=status_choices,        default=2,        help_text=u"选择客户此时的状态"    )    consultant = models.ForeignKey(verbose_name="课程顾问", to='UserInfo', related_name='consultanter' )    date = models.DateField(verbose_name="咨询日期", auto_now_add=True)    recv_date = models.DateField(verbose_name="当前课程顾问的接单日期", null=True)    last_consult_date = models.DateField(verbose_name="最后跟进日期", )    def __str__(self):        return self.nameclass ConsultRecord(models.Model):    """    客户跟进记录    """    customer = models.ForeignKey(verbose_name="所咨询客户", to='Customer')    consultant = models.ForeignKey(verbose_name="跟踪人", to='UserInfo')    date = models.DateField(verbose_name="跟进日期", auto_now_add=True)    note = models.TextField(verbose_name="跟进内容...")    def __str__(self):        return self.customer.name + ":" + self.consultant.nameclass Student(models.Model):    """    学生表(已报名)    """    customer = models.OneToOneField(verbose_name='客户信息', to='Customer')    class_list = models.ManyToManyField(verbose_name="已报班级", to='ClassList', blank=True)    emergency_contract = models.CharField(max_length=32, blank=True, null=True, verbose_name='紧急联系人')    company = models.CharField(verbose_name='公司', max_length=128, blank=True, null=True)    location = models.CharField(max_length=64, verbose_name='所在区域', blank=True, null=True)    position = models.CharField(verbose_name='岗位', max_length=64, blank=True, null=True)    salary = models.IntegerField(verbose_name='薪资', blank=True, null=True)    welfare = models.CharField(verbose_name='福利', max_length=256, blank=True, null=True)    date = models.DateField(verbose_name='入职时间', help_text='格式yyyy-mm-dd', blank=True, null=True)    memo = models.CharField(verbose_name='备注', max_length=256, blank=True, null=True)    def __str__(self):        return self.customer.nameclass ClassStudyRecord(models.Model):    """    上课记录表 (班级记录)    """    class_obj = models.ForeignKey(verbose_name="班级", to="ClassList")    day_num = models.IntegerField(verbose_name="节次", help_text=u"此处填写第几节课或第几天课程...,必须为数字")    teacher = models.ForeignKey(verbose_name="讲师", to='UserInfo')    date = models.DateField(verbose_name="上课日期", auto_now_add=True)    course_title = models.CharField(verbose_name='本节课程标题', max_length=64, blank=True, null=True)    course_memo = models.TextField(verbose_name='本节课程内容概要', blank=True, null=True)    has_homework = models.BooleanField(default=True, verbose_name="本节有作业")    homework_title = models.CharField(verbose_name='本节作业标题', max_length=64, blank=True, null=True)    homework_memo = models.TextField(verbose_name='作业描述', max_length=500, blank=True, null=True)    exam = models.TextField(verbose_name='踩分点', max_length=300, blank=True, null=True)    def __str__(self):        return "{0} day{1}".format(self.class_obj, self.day_num)class StudentStudyRecord(models.Model):    '''    学生学习记录    '''    classstudyrecord = models.ForeignKey(verbose_name="第几天课程", to="ClassStudyRecord")    student = models.ForeignKey(verbose_name="学员", to='Student')    record_choices = (('checked', "已签到"),                      ('vacate', "请假"),                      ('late', "迟到"),                      ('noshow', "缺勤"),                      ('leave_early', "早退"),                      )    record = models.CharField("上课纪录", choices=record_choices, default="checked", max_length=64)    score_choices = ((100, 'A+'),                     (90, 'A'),                     (85, 'B+'),                     (80, 'B'),                     (70, 'B-'),                     (60, 'C+'),                     (50, 'C'),                     (40, 'C-'),                     (0, ' D'),                     (-1, 'N/A'),                     (-100, 'COPY'),                     (-1000, 'FAIL'),                     )    score = models.IntegerField("本节成绩", choices=score_choices, default=-1)    homework_note = models.CharField(verbose_name='作业评语', max_length=255, blank=True, null=True)    note = models.CharField(verbose_name="备注", max_length=255, blank=True, null=True)    homework = models.FileField(verbose_name='作业文件', blank=True, null=True, default=None)    stu_memo = models.TextField(verbose_name='学员备注', blank=True, null=True)    date = models.DateTimeField(verbose_name='提交作业日期', auto_now_add=True)    def __str__(self):        return "{0}-{1}".format(self.classstudyrecord, self.student)

数据录入

"""学校课程部门用户信息班级按照models.py中模型表的顺序依次添加,添加过程中需要引入的知识点有1.添加班级表记录时,授课老师和班主任信息展示需要用到limit_choices_to    limit_choices_to={'depart_id':170}  >>>     单个部门    limit_choices_to={'depart_id__in':[120,150]}    >>>     多个部门2.客户表    录入数据后,展示客户性别引出get_field_display()展示choice字段对应的注解        def display_gender(self,is_header=False,obj=None):            if is_header:                return '性别'            return obj.get_gender_display()        按照上述方式,只要是有choice字段的都可按照此法展示3.展示咨询课程    3.1将咨询课程全部做成a标签的样式,然后提出a标签的需求:        点哪个a标签就将该a标签对应的客户咨询课程删除    3.2删除的是某一客户的咨询课程,而我们stark组件只会为每一个模型表创建增删改查四条基本的url,这个问题如何解决?        先去stark组件源码二级路由分发处演示思路,直接在get_urls()演示            def get_urls(self):                tmp = [                    url(r'^$',self.list_view,name='%s_%s_list'%(self.app_label,self.model_name)),                    url(r'^add/',self.add_view,name='%s_%s_add'%(self.app_label,self.model_name)),                    url(r'^edit/(\d+)/',self.edit_view,name='%s_%s_edit'%(self.app_label,self.model_name)),                    url(r'^delete/(\d+)/',self.delete_view,name='%s_%s_delete'%(self.app_label,self.model_name))                ]                tmp.append(                    url(r'^.../',删除客户咨询某一课程记录)                )                return tmp       这样做的缺陷就是会生成很多条相同的url,如何做到只为某一个模型表配置额外的url?       (你们想想list_display,actions这些功能是怎么玩的???)       a标签渲染        def display_course(self,is_header=False,obj=None):            if is_header:                return '咨询课程'            course_list =  []            for course in obj.course.all():                course_list.append("%s"%(obj.pk,course.pk,course.name))            return mark_safe(' '.join(course_list))                   自定义扩张url方法        def extra_url(self):            tmp = []            tmp.append(            url(r'^cancel_course/(\d+)/(\d+)/',self.cancel_course)            )            return tmp                    自定义视图函数        def cancel_course(self,request,customer_id,course_id):            customer_obj = models.Customer.objects.filter(pk=customer_id).first()            customer_obj.course.remove(course_id)            return redirect(self.get_reverse_url('list'))                    stark组件新增一个空的extra_url方法,用户不配置就无任何多余的url        def extra_url(self):            return []   """

剩余四张表

"""1.咨询记录表信息录入2.学生信息录入3.课程记录    stark组件源码增加自动识别get_field_display()4.学习记录    根据课程记录批量生成对应的学习记录        利用actions自定义批量生成函数    def patch_studyrecord(self,request,queryset):        tmp = []        for course_record in queryset:                                              student_list=Student.objects.filter(class_list__id=course_record.class_obj.pk)        for student in student_list:            obj = StudyRecord(student=student,course_record=course_record)            tmp.append(obj)        StudyRecord.objects.bulk_create(tmp)5.学习记录筛选    筛选当天学习记录    利用list_filter功能        def get_filter(self,request,queryset):        q = Q()        for field,field_id in request.GET.items():            if field in ['page','q']:                continue            field_id = request.GET.get(field)            q.children.append((field, field_id))        queryset = queryset.filter(q)        return queryset    学习记录中自定义记录列点击记录跳转到对应的学生学习记录    def record(self,is_header=False,obj=None):        if is_header:            return '记录'        _url = '/stark/app01/studentstudyrecord/?classstudyrecord=%s'%obj.pk        return mark_safe("记录"%_url)    list_display = ['class_obj','day_num',record]    考勤功能    def work(self,is_header=False,obj=None):        if is_header:            return '考勤'        html = ''        for k in obj.record_choices:            if obj.record == k[0]:                s = ""%k            else:                s = ""%k            html += s        return mark_safe(""%(obj.pk,html))    def check(self,request):        status = request.POST.get('status')        pk = request.POST.get('pk')        print(status,pk)        models.StudentStudyRecord.objects.filter(pk=pk).update(record=status)        return HttpResponse('ok')    def extra_url(self):        tmp = []        tmp.append(            url(r'^check_work/',self.check)        )        return tmp                        window.onload = function () { $('.xxx').change(function () {     var status = $(this).val();     var pk = $(this).attr('pk');     $.ajax({         url:'/stark/app01/studentstudyrecord/check_work/',         type:'post',         data:{             status:status,             pk:pk         },         success:function (data) {             console.log(data)         }     }) })};"""

转载于:https://www.cnblogs.com/pdun/p/10839408.html

你可能感兴趣的文章
产品经理有话说——产品汪成长记(入职)
查看>>
2016/01
查看>>
从魔兽世界到激战2看MMO网游角色成长
查看>>
转两好文防丢:Debian 版本升级/降级 & Linux 应用程序失去输入焦点问题的解决...
查看>>
HDU - Pseudoforest
查看>>
Nexus杂
查看>>
Android --- GreenDao的实现(ORM框架)
查看>>
用Java发起HTTP请求与获取状态码(含状态码列表)
查看>>
js_coding
查看>>
Linux平台Java调用so库-JNI使用例子
查看>>
PCM数据格式,多少字节算一帧
查看>>
Spring Data JPA
查看>>
KACK的处理方法
查看>>
POJ3438 ZOJ2886 UVALive3822 Look and Say【数列】
查看>>
IE6的height小BUG
查看>>
说说IUnitOfWork~DbContext对象的创建应该向BLL层公开
查看>>
强制卸载kernel
查看>>
js 杂项(一)函数篇
查看>>
pythonGUI-wxpython
查看>>
最小生成树模板 加 例题分析 (最小生成树类型汇总)
查看>>