• Python Django


    本章内容:

    参考文档

      环境搭建及基础配置

      URL设置

      Django快速Web开发——模型(基础)

      Django快速Web开发——模型(高级)

      Django快速Web开发——管理后台

      Django中文文档

      Django 1.11.6 文档

      

    Django 安装

    参考文档

    Django的安装会涉及一下多个软件,部署的参考文档会有很多,遇到的报错也会很多,百度、goole 可解决

    系统字符集:

    #echo $LANG
    en_us.UTF-8

    yum源设置

    mirrors.aliyun.com/help/centos
    or   wget -O /etc/yum.repos.d/CentOs-Base.repo http://mirrors.aliyun.com/repo/Centos-6.repo

    时区设置:  

    ntpdate time.windows.com

    python 相关包安装:  

    依赖的包:
    
      yum -y install openssl-devel readline-devel gcc  gcc-c++ 
    
      pypi setuptools 包,注意回退一个版本比较稳定
        Wget -S https://pypi.python.org/packages/dc/8c/7c9869454bdc53e72fb87ace63eac39336879eef6f2bf96e946edbf03e90/setuptools-33.1.1.zip#md5=7963d41d97b94e450e3f8a217be06ffe     
    unzip setuptools-33.1.1.zip     cd setuptools-33.1.1     /usr/local/python27/bin/python setup.py install   python-2.7.13 版本
        wget -S https://www.python.org/ftp/python/2.7.13/Python-2.7.13.tgz     .
    /configure --prefix=/usr/locl/python27     make && make intall   pip 安装     /usr/local/python27/bin/easy_install pip     vim /etc/pip.conf       [global]       trusted-host = pypi.douban.com       index-url = http://pypi.douban.com/simple       [list]       format=colums

    virtualenv 环境安装

    /usr/local/python27/bin/pip install virtualenv
    cd data/
    /usr/local/python27/bin/virtualenv ./python27env
    source /data/python27/env/bin/activate
    pip install ipython
    pip install mysql-python
    #deactiveate ,退出虚拟环境

    django 安装

    pip install "django>=1.8,<1.9"    #安装1.8版本
    ipython 中
        django.get_version()          #查看版本

    mysql 安装

    5.6版本比较稳定
    
    rpm -ivh https://dev.mysql.com/get/mysql-community-release-el6-5.noarch.rpm
    
    sudo yum -y install mysql mysql-server mysql-devel zlib-devel

    django 实例

    django-admin startproject opsweb        #生成opswed项目

      项目目录结构

        

      

      运行第一个小实例:

      需要提前在settings.py里修改这一行: ALLOWED_HOSTS = ["*"]  

    python manage.py runserver 0.0.0.0:33333

      

      这里运行的时候遇到一个报错:

      ImportError: No module named security

      这个是由于我在virtualenv环境下创建的这个项目,执行的时候却退出了,需要进入后再执行。

    django app 实例 

    python manage.py startapp dashboard

    生成的目录结构:  

         

    目录文件说明

      

    配置app

      把app的名字写入

        opsweb/settings.py

        

      再对url进行配置

        添加到opsweb/urls.py中

        

        可以理解为处理dashboard目录,交给后面的函数来处理

      配置视图

        

      配置dashboard中的url:

        

    梳理下流程

      如:发起url请求:http://59.110.12.72:33333/dashboard/hello/

      首先匹配到dashboard 这个app,然后又在python27env/reboot/opsweb/opsweb/urls.py中匹配到了 url(r'^dashboard/', include("dashboard.urls")),然后就会去dashboard中查找urls.py. 在其中发现url(r'hello/$',views.hello), 然后就会执行views视图中的hello函数。

    django HttpRequest 对象

      视图函数中的request是由Django创建的

    def index(request):
          pass

      request属性

    HttpRequest.scheme
    HttpRequest.body
    HttpRequest.path
    HttpRequest.path_info
    HttpRequest.method
    HttpRequest.encoding
    HttpRequest.GET
    HttpRequest.POST
    HttpRequest.META
    HttpRequest.user
    

      request方法

    HttpRequest.get_host()
    HttpRequest.get_full_path()
    HttpRequest.build_absoulute_uri(location)
    HttpRequest.get_signed_cookie()
    HttpRequest.is_secure()
    HttpRequest.is_ajax()

    django HttpResponse对象

      传递一个字符串作为页面的内容到HttpResponse构造函数

    from django.http import HttpResponse
    
    return HttpResponse('Here is the text of hte web page')
    return HttpResponse('Test',content_type="text/plain")

      reponse属性

    HttpResponse.content 
    HttpResponse.charset 
    HttpResponse.status_code 
    HttpResponse.reason_phrase

      reponse方法

    HttpResponse.__init__(content=”, content_type=None, status=200, reason=None, charset=None)

      如何用呢?待了解

      django 中 return HttpResponse('内容'),这个内容只能是string格式的,所以需要 json.dumps(res) 下这个res结果

      加入这个res是字典,后端已经序列化了,传递给前端后,需要把这个字符串转化为对象,  var obj = JSON.parse(data)

      前端对象转换为字符串 :

         

      那为题来了,ajax 请求中只能 return HttpResponse 吗?最好是这样,但可以用 render,不过这个返回的是一个渲染好的html页面,处理是个问题,redirect这个是不能用的!

    django JsonResponse对象

      支持传递list,dict

      return JsonResponse([1,2,3], safe = False)

    django QueryDict对象

    In [1]: from django.http import QueryDict
    In [2]: Get = QueryDict('a=1&b=2&c=3')

      QueryDict的方法: 

    QueryDict.get(key, default=None) 
    QueryDict.setdefault(key, default=None)[source]
    QueryDict.update(other_dict) QueryDict.items() QueryDict.values() QueryDict.copy() QueryDict.getlist(key, default
    =None)
    QueryDict.setlist(key, list_)[source]
    QueryDict.appendlist(key, item)
    QueryDict.setlistdefault(key, default_list=None)
    QueryDict.lists() QueryDict.pop(key) QueryDict.popitem() QueryDict.dict() QueryDict.urlencode(safe
    =None)

    Render 的前世

      这种方法相比render较不适用,建议使用render,学习一下

      与flask相似,需要建立一个templates文件夹,把html文件放到这里,然后再渲染

      视图中添加

        

      urls中添加

        

      html文件

        

     后端验证登录

      request.GET

      request.POST

      request.FILES    #上传文件

      request.getlist()         #checkbox 等多选的内容

     1 def login(request):
     2     print request
     3     if request.method == "GET":
     4         print 'username from get -->',request.GET.get('username')
     5         print 'password  from get-->',request.GET.get('password')
     6         template = loader.get_template('login.html')
     7         context = Context({"title":"reboot 运维平台"})
     8         return HttpResponse(template.render(context))
     9 
    10     elif request.method == 'POST':
    11         print 'username from get -->',request.POST.get('username')
    12         print 'password  from get-->',request.POST.get('password')
    13         username = request.POST.get('username')
    14         password = request.POST.get('password')
    15         return HttpResponse('login ok!')
    views 函数
     <html>
         <head>
             <title>
                 {{title}}
             </title>
             <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
         </head>
         <body>
             <h1>用户登录</h1>
             <ul>
                 <form action="/dashboard/login/" method="post">
                     <li><input type="text" name="username" id="username" /></li>
                     <li><input type="text" name="password" id="password" /></li>
                     <li><input type="submit" value="login" id="form_submit" /></li>
                 </form>
             </ul>
     
             <script>
                 $(function(){
                    $('#form_submit').click(function(){
                         var username = $('#username').val();
                         var password = $('#password').val();
                         $.post("/dashboard/login/",{username:username,password:password},function(res){
                             alert(res)   
                         })
                         return false;  #如果不return false的话,就会按照默认的请求走了
                    }) 
                 })
             </script>
         </body>
     </html>
    Ajax 异步登录

    project 添加一个目录并且可识别

      又名静态文件配置

      

      添加static目录,需要添加setting里面的

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

      这样,就可以在templates目录下的html文件中引用这个url了

      

    django 路由系统URL

      项目下的urls.py的配置

        1、/index/

        2、/index/(d+)

        3、/index/(?P<nid>d+)

          正则(?P<year>[0-9]{4})用法

          

          相当于定义了一个year变量,在后边匹配到条件,就把取到值复制给year

        4、/index/(?P<nid>d+) name='root'

          reverse()

          {%  url  'root' 1 %}

        5、include

          当有N个app时,url的编写都在项目的usls.py下就会有点乱,可以把这个文件转移到各个app下的urls.py下,需要在项目urls.py下做如下操作

          from  django.conf.urls  import  url,  include

          urlpatterns  =  [

            url(r'^cmdb/',  include('app01.urls'))

            url(r'^monitor/',  include('app02.urls'))

          ]

        6、默认值(传递参数)

          /index/  {'web':'root'}

          def func(request, web):

            return ......

          例子:

            url(r'^index/', views.index, {'name':'root'})

            def  index(request, name):

              print(name)

              return HttpResponse('ok')

          这时候回多传递后面的字典给后端,而浏览器的格式不变。这个字典的变量可以是动态的,如,动态获取了客户的信息,然后传递给后端。这是后再view中定义的函数,也需要传递这个字典的key,不然会报确实参数的错。

        7、name

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

    url(r'abcdefg', views.index,  name='i1')
    url(r'bbbbbb/(d+)/(d+)', views.index,  name='i2')
    url(r'dddddd/(?P<pid>d+)/(?P<nid>d+)/', views.index,  name='i3')
    url.py
    def func(request, *args,  **kwargs):
        from  django.urls  import reverse
      url1  =  reverse('i1')                         #生成的url       abcdefg
        url2  =  reverse('i2', args = (1,2,))      #bbbbbb/1/2/
        url3   =  reverse('i3' , kwargs = {'pid':1, "nid":9})      #dddddd/1/9
    view.py
    action = {% url "i1" %}
    {% url "i3"  1 2 %}
    {% url  'i3' pid=1  nid = 9%}
    html

     django Views

      视图获取用户相关请求信息,以及请求头。

      print(tpye(request))         #查看类类型

      from django.core.handlers.wsgi  import WAGIRequest          #可以查看到所有的请求头都是包含在environ 方法中的

      print(request.environ)

      for k,v in request.environ.items():              #去查看请求头过来的所有信息   

    def login_view(request):
        if request.method == "GET":
            return render(request, "public/login.html")
        else:
            username = request.POST.get("username", "")
            userpass = request.POST.get("password", "")
            user = authenticate(username=username, password=userpass)
            ret = {"status":0, "errmsg":""}
            if user:
                login(request, user)
                ret['next_url'] = request.GET.get("next") if request.GET.get("next", None) else "/"
            else:
                ret['status'] = 1
                ret['errmsg'] = "用户名或密码错误,请联系管理员"
            return JsonResponse(ret)
    View中三元运算写法

    django Template

      模板继承:有时候许多页面有许多相似之处,为了书写简单就可以用到末班继承,

      被继承文件  layer.html  ,写好公共的内容, {% block content %}   {% endblock %}   这个里面是继承的页面中需要自己书写的东西

      继承的文件  a.html     {% extends 'layer.hmlt' %}    #说明下这个内容是从哪里继承的

                {%  block  content  %}   书写自己的代码   {%   endblock  %}  ,当然可以写多块内容

      模板导入:别人写好的代码块,咱这个页面上面需要导入,比如淘宝上面的每个产品的块

             a.html b.html  这些都是一个个小的产品,这时候需要在主页面导入

              {%   include  “a.html” %}

            {% include "b.html" %}

    django Simple_tag/filter

          Simple_tag写法

      1、首先要在app的目录下创建一个templatetags(名字不能变)目录,app需要添加到setting里面就不必多说了

      2、穿件一个任意名称的python文件,如xxoo.py

      3、xxoo.py 代码

    from django import template
    
    register = template.Library()       #register名字不能变
    
    @register.simplt_tag
    def  zidingyi(a,b):
        #可以添加参数
        return a + b

      4、配置html文件

    {% load xxoo %}        //首先需要在html文件的顶部load这个python文件
    
    
    {% zidingyi  2  5  %}     //然后下面可以引用这个函数了

      优点:可以传递多个参数

      缺点:不能作为if条件

      Filter

      用法基本相同

    from django import template
    
    register = template.Library()       #register名字不能变
    
    @register.filter
    def  zidingyi(a,b):
        #可以添加参数,最多只允许两个参数
        return a + b

      html文件

    {% load xxoo %}        //首先需要在html文件的顶部load这个python文件
    
    
    {% ‘第一个参数’|zidingyi:“第二个参数”  %}     //注意中间不能有空格

    django cookie

      cookie:以键对的方式存储在客户端

      django设置cookie: rep.set_cookie(key,value,参数)

    def login(request):
        user_info = {
            'dachengzi':{'pwd':'123'},
            'kangbazi':{'pwd':'123'}
        }
    
        if request.method == 'GET':
            print('I am here')
            return render(request, 'login.html')
    
        elif request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            print(username,password)
            res = user_info.get(username)
            if not res:
                return render(request, 'login.html')
    
            if res['pwd'] == password:
                print('I am coming to denglu')
                res = redirect('/denglu/')                          #可以这种写法
                res.set_cookie('username111',username)
    
                return res
            else:
                return  render(request,'login.html')
    
    
    
    def denglu(request):
        v = request.COOKIES.get('username111')    #提取登录的username
        if not v:
            return redirect('/login/')
        return render(request, 'denglu.html', {'current_user':v})    #在前端显示登录的user
    举例说明

       

        参数:
            key,              键
            value='',         值
            max_age=None,     超时时间
            expires=None,     超时时间(IE requires expires, so set it if hasn't been already.)
            path='/',         Cookie生效的路径,/ 表示根路径,特殊的:跟路径的cookie可以被任何url的页面访问
            domain=None,      Cookie生效的域名
            secure=False,     https传输
            httponly=False    只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

      例:

        current_date = datetime.datetime.utcnow()

                current_date = current_date + datetime.timedelta(seconds=5)

                response.set_cookie('username111', u, expires=current_data)

        httponly=False  这只后只有http能获取到cookie,js获取不到

    <select onchange="changePageSize()">
        <option value="10">10</option>
        <option value="30">30</option>
        <option value="50">50</option>
        <option value="100">100</option>
    </select>
    
    
    <script src="jquery.js"></script>
    <script src="jquery.cookie.js"></script>       //cookie是基于juery的,对cookie进行操作
    
    <script>
        function changePageSize(ths){
            var v = $(ths).val()
            $.cookie('per_page_count', v)
        }
    </script>
    cookie,分页

      cookie 加salt

      obj = HttpResponse('s')

      obj.set_signed_cookie('username', "kangbazi", salt='abcdefg')             #加盐加密

      request.get_signed_cookie('username', salt='abcdefg')            #用盐解密      

    django session

      django实现session功能十分简单,在视图函数中添加如下,

        request.session['username'] = username

      看似简单,其实django帮我们做了许多事情

                1、生成随机字符串

        2、写到浏览器的cookie中,(sessionid的形式)

        3、保存在服务器端的session中,(保存在了数据库中django_session表中)

        4、当然这个服务器端存session的字典中也可以保存一些其他的客户的信息,来更好的识别客户

      待session设置完毕后需要

        python manage.py makemigrations

        python manage.py migrate

      来使之生效

      django的session的缓存时间默认是2周,可以人为设置

        request.session.set_expiry(10s)        设置10s过期

      还可以在setting里添加一些默认的设置

        SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
         
        SESSION_COOKIE_NAME = "sessionid"                       # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
        SESSION_COOKIE_PATH = "/"                               # Session的cookie保存的路径(默认)
        SESSION_COOKIE_DOMAIN = None                             # Session的cookie保存的域名(默认)
        SESSION_COOKIE_SECURE = False                            # 是否Https传输cookie(默认)
        SESSION_COOKIE_HTTPONLY = True                           # 是否Session的cookie只支持http传输(默认)
        SESSION_COOKIE_AGE = 1209600                             # Session的cookie失效日期(2周)(默认)
        SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  # 是否关闭浏览器使得Session过期(默认)
        SESSION_SAVE_EVERY_REQUEST = False                       # 是否每次请求都保存Session,默认修改之后才保存(默认)

    django 链接数据库

      setting的配置中

    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'wang.....',
            'USER':'#####',
            'PASSWORD':'123456',
            'HOST':'59.110.12.72',
            'PORT':3306
        }
    }

      测试链接数据是否成功:

        python manage.py syncdb

      需要注意的是,Django默认使用的是MySQLdb模块链接MYSQL,python3中需要修改为pymysql,在project 同名文件夹下的__init__文件中添加如下代码即可:

      import pymysql

      pymysql.install_as_MYSQLdb()

      链接数据库创建普通用户:

        python manage.py shell

        from django.contrib.auth.models import User

        user = User.objects.create_user('rock','rock@51reboot.com','123456')

      创建管理员用户,命令行模式下:

        python manage.py createsuperuser --username=reboot --email=reboot@51reboot.com

      修改密码:

        python manage.py shell

        from django.contrib.auth.models import User

        user = User.objects.get(username='rock')

        user.set_password('rock')

        user.save()

      用户登录和退出验证: 

    from django.contrib.auth import authenticate,login,logout
    
    def login_view(request):
        print request
        if request.method == "GET":
            template = loader.get_template('login.html')
            context = Context({"title":"reboot 运维平台"})
            return HttpResponse(template.render(context))
    
        elif request.method == 'POST':
            print 'username from get -->',request.POST.get('username')
            print 'password  from get-->',request.POST.get('password')
            username = request.POST.get('username')
            password = request.POST.get('password')
            user = authenticate(username=username,password=password)
            if user:
                login(request,user)
                return HttpResponse('login ok!')
            else:
                return HttpResponse('login fail')
        
    
    def logout_view(request):
        logout(request)
        return HttpResponse('logout success!!')

    类方法的写法 

    from django.views import view

    class
    Home(view): #继承view方法 ''' 执行get、post方法之前都会先执行dispatch方法 ''' def dispatch(self, request, *args, **kwargs): #代用父类中的dispatch print('before') result = super(Home, self).dispatch(request, *args, **kwargs) print('after') def get(self, request): print(request.method) return render(request, 'home.html') def post(self, request): print(request.method, 'POST') return render(request, 'home.html')

    session 与 cookie的区别

      1,session 在服务器端,cookie 在客户端(浏览器)
      2,session 默认被存在在服务器的一个文件里(不是内存)
      3,session 的运行依赖 session id,而 session id 是存在 cookie 中的,也就是说,如果浏览器禁用了 cookie ,同时 session 也会失效(但是可以通过其它方式 实现,比如在 url 中传递 session_id)
      4,session 可以放在 文件、数据库、或内存中都可以。
      5,用户验证这种场合一般会用 session

    django流程介绍

       

      两种架构:

      MVC

        即将程序分为三个组成部分, model(模型)、view(视图)、controller(控制器)

        M  管理应用程序的状态,

        C  接受外部用户的操作,根据操作访问模型获取数据

        V  负责把数据格式化后呈献给用户

      django 也是MVC的框架,但是在Django中,控制器接受用户输入的部分由框架自行处理,所以Django里更关注的是模型(Model),模块(Template)和视图(Views),成为MTV模式:

        M  代表模型(Model) ,即数据存取层,该层处理与数据相关的所有事物:如何存取、如何验证有效性、包含哪些行为以及数据之间的关系等。

        T  代表模板(Template), 即表现层,该层处理与表现相关的决定:如何在页面或者其他类型文档中进行显示

        V  代表视图(View), 即业务逻辑层,盖层包含存取模型及调取恰当模块的相关逻辑,你可以把它看做模型与模块之间的桥梁。 

    Djiango 数据库 ORM

      小例,通过django orm 添加表,然后admin展示:

      首先在dashboard这个app下的models.py添加表

      

    from django.db import models
    
    # Create your models here.
    
    class Publisher(models.Model):
        name = models.CharField(max_length=30)
        address = models.CharField(max_length=50)
        city = models.CharField(max_length=60)
        state_province = models.CharField(max_length=30)
        country = models.CharField(max_length=50)
        website = models.URLField()
        def __unicode__(self):             #这两行是为了在后台中以名字展现,不然不会显示创建的名称
            return "<%s>"%(self.name)
    
    class Author(models.Model):
        first_name = models.CharField(max_length=30)
        last_name = models.CharField(max_length=40)
        email = models.EmailField()
        def __unicode__(self):
            return "<%s,%s>"%(self.first_name,self.last_name)
     
    class Book(models.Model):
        title = models.CharField(max_length=100)
        authors = models.ManyToManyField(Author)
        publisher = models.ForeignKey(Publisher)
        publication_date = models.DateField()
        def __unicode__(self):
            return "<%s>"%(self.title)

      表格创建完毕后需要在数据苦衷生成了

        python manage.py makemigrations

        python manage.py migrate

      这样数据库中就会生成对应的表:

        

      表创建完毕了,就需要在app下的admin.py中导入表的信息   

    from django.contrib import admin
    
    # Register your models here.
    import models
    
    admin.site.register(models.Author)
    admin.site.register(models.Book)
    admin.site.register(models.Publisher)

      python manay.py createsuperuser ,创建可登录admin后台的超级管理员用户 

        这样在访问http://59.110.12.72:33333/admin/ ,就可以在里面做一些对标的增、删、改、查 了

      Django 数据库支持的字段类型:

        详见:https://docs.djangoproject.com/en/1.9/ref/models/fields/ 

        

      Django 中如果想要表格可以输入为空

        

        null = True 控制的是数据库可以为空

        blank = True 告诉Django表格可以为空

        然后再发布配置:

        

       使标题显示中文

        

      ORM对数据库进行操作

        表中插入数据

        python manage.py shell

        >>> from dashboard.models import Publisher

        >>> p1 = Publisher(name='Apress',address='USA',city='MHD',state_province='..',country='USA',website='www.baidu.com')

        >>> p1.save()             #这种方法,需要save()后才会添加到数据库

                       #下面这种方法,可以直接在添加到数据库

        >>> p1 = Publisher.objects.create(name='laoboy',address='USA',city='MHD',state_province='..',country='USA',website='www.baidu.com')

        这套命令对应这数据库操作的 insert

      如果要改变其中某个字段的值,需要怎么操作呢?

        p1.name = 'balabala'

        p1.save()

      这里保存的时候,是又重新把整个表保存了一遍。

      查找对象   

        >>> Publisher.objects.all()

        [<Publisher: <快网出版社>>, <Publisher: <Apress>>, <Publisher: <oldboy>>]

        注意到Django在选择所有数据时并没有使用 SELECT* ,而是显式列出了所有字段。 设计的时候就是这样:SELECT* 会更慢

      

        >>> Publisher.objects.filter(name='oldboy')

        [<Publisher: <oldboy>>]

        同样,也支持,多条件过滤

        >>> Publisher.objects.filter(name='oldboy',country='USA') 

        [<Publisher: <oldboy>>]

        模糊查询

        >>> Publisher.objects.filter(name__contains="boy")           #中间是双横杠 

        [<Publisher: <oldboy>>]

        获取单个对象并对齐修改

        >>> Publisher.objects.get(name='oldboy')

        <Publisher: <oldboy>>
        >>> a = Publisher.objects.get(name='oldboy')
        >>> a.name = 'oldboy2'
        >>> a.save()
        获取对象后进行排序

        >>> Publisher.objects.order_by("name")     #按照name来排序

        >>> Publisher.objects.order_by("state_province""address")   #第一项一样的,按照第二项来排序

        >>> Publisher.objects.order_by("-name")    #倒叙

        排来排去有点麻烦,可以用meta来进行全局的排序

        

        连锁查询

        >>> Publisher.objects.filter(country="U.S.A.").order_by("-name")

        [<Publisher: O'Reilly>, <Publisher: Apress>]
          过滤完数据在查询。
        限制查询
        >>> Publisher.objects.order_by('name')[0]  #指向要帅选出来的第一条数据
        <Publisher: Apress>
        相当于mysql的
        

        筛选到数据并修改:

        

        删除对象

        

     

    django shell  操作/自带方法

    shell 中修改密码:

    from
    django.contrib.auth.models import User u = User.objects.get(username='admin') #得到admin用户的对象 u.set_password('123') #设置密码 u.password #查看的密码就是加密后的 #添加新用户 u2 = User() u2.username = 'u2' u2.set_password('123') u2.save() #设置is_staff后便可以登录后台系统了 u2.is_staff = True #django user登录鉴权 from django.contrib.auth import authenticate test = authenticate(username='u2', password='123') #如果有值则存在,None则不存在

      用户验证登录的时候如果没有验证成功,django会有一个自己的rewritelogin的地址如果想要更改这个login的得知的话,则需要在settings配置文件中添加如下一行

    LOGIN_URL = ‘/login’

      django自带方法

      1、login

    from django.contrib.auth import login, authenticate
    
    user = authenticate(username='u2', password='123')
    login(request, user)     #登录

      2、login_required

    from django.contrib.auth.decorators import login_required
    
    
    @login_required
    def index(request):          #装饰到函数前面
        pass

    django分页功能

      xss: django为了安全机制,默认传递的都是字符串,比如来自浏览客户的评论,如果给写了个js脚本,抱歉那是不会执行的,只是按照字符串来对待

      确定安全的情况下,那如何让其对这字符串做解释呢?

      方法:

        1、前端   {{  page_str |safe}}       //对后端传递过来的字符串作解释

        2、后端   from django.utils.safestring import mark_safe

                              page_str = mark_safe(page)             #对html的字符串做mark_safe后,再传递

      手写一个分页:

    def user_list(request):
        current_page = request.GET.get('p',1)     #获取参数p,没有就默认为1
        start = (current_page-1) * 10
        end = current_page * 10
        data = LIST[start:end]        #LIST  想象为数据库获取的数据
    
    
        all_count = len(LIST)
        count, yushu = divmod(all_count, 10)
        if y:
            count += 1
    
        page_list = []
        for i in range(1, count+1):
            temp = '<a href="/user_list/?p=%s>%s</a>"' %(i,i)
            page_list.append(temp)
    
        page_str = "".join(page_list)
    
        page_str = mark_safe(page_str)
    
        return render(request, 'user_list.html' , {'li': data, 'page_str': page_str})
    分页

     django csrf

      CSRF, Cross Site Request Forgery, 跨站点伪造请求。举例来讲,某个恶意的网站上有一个指向你的网站的链接,如果某个用户已经登录到你的网站上了,那么当这个用户点击这个恶意网站上的那个链接时,就会向你的网站发来一个请求,你的网站会以为这个请求是用户自己发来的,其实呢,这个请求是那个恶意网站伪造的。具体的细节及其危害见 wikipedia

      机制:django 第一次响应来自某个客户端的请求时,会在服务器端随机生成一个 token,把这个 token 放在 cookie 里。然后每次 POST 请求都会带上这个 token,这样就能避免被 CSRF 攻击。

      setting中开启csrf功能后,在没有做特殊处理的情况下会遇到下面的报错:

      

      那如何解决这个问题呢?

      1、form 表单提交的的时候需要添加上{% csrf_token %}

    <form action="/cref/" method="post">
        {%  csrf_token %}
        <div>
            用户名:<input type="text" name="username">
        </div>
        <div>
            密码:<input type="text" name="password">
        </div>
        <div>
            <input type="submit" value="提交">
        </div>
    </form>
    csrf_token

      2、如果是ajax请求呢?那就需要在请求的时候,在header中添加这么一行,headers:{'X-CSRFtoken':csrf_token},

        <script>
            $(function () {
                $('#btn').click(function () {
                    var csrf_token = $.cookie('csrftoken')
                    $.ajax({
                        url:'/cref/',
                        type:"POST",
                        headers:{'X-CSRFtoken':csrf_token},
                        data : {'username':'admin','password':'123'},
                        success:function(){
    
                        }
                    })
    
                })
            })
    
        </script>
    ajax

      如果你的ajax很多,老是添加这么一行,那岂不是很麻烦呢?那只需要在开头添加一个ajaxSetup即可 

            $(function () {
                $.ajaxSetup({
                    beforeSend:function (xhr,settings) {
                        xhr.setRequestHeader('X-CSRFtoken',$.cookie('csrftoken'))
                    }
                });
    
                $('#btn').click(function () {
                    var csrf_token = $.cookie('csrftoken')
                    $.ajax({
                        url:'/cref/',
                        type:"POST",
                        //headers:{'X-CSRFtoken':csrf_token},
                        data : {'username':'admin','password':'123'},
                        success:function(){
    
                        }
                    })
    
                })
            })
    many_ajax

       另外想一个问题,如果有100个views,只有其中 两个需要加这个需求,另外的都不加,再如果有两个加,其他的都不加呢?这里就涉及到全局和局部使之生效的问题

      全局:

        中间件 django.middleware.csrfViewMiddleware

      局部:

    • @csrf_protect, 为当前的幻术强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件
    • @csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件    

       

    django + uwsgi + nginx 启动 

      使用runserver可以使我们的django项目很便捷的在本地运行起来,但这只能在局域网内访问,如果在生产环境部署django,就要多考虑一些问题了。比如静态文件处理,安全,效率等等,本篇文章总结归纳了一下基于uwsgi+Nginx下django项目生产环境的部署

      准备知识:

        Django:一个基于python的开源web框架

        uwsgi:一个基于自由uwagi协议、wsgi协议和http服务协议的web网关

        nginx:常用的高性能代理服务器

        wsgi.py : django项目携带的一个wsgi接口文件

      项目流程

        1、首先客户端请求服务资源,

        2、nginx作为直接对外的服务接口,接收到客户端发送过来的http请求,会解包、分析,

        3、如果是静态文件请求就根据nginx配置的静态文件目录,返回请求的资源,

        4、如果是动态的请求,nginx就通过配置文件,将请求传递给uWSGI;uWSGI 将接收到的包进行处理,并转发给wsgi,

        5、wsgi根据请求调用django工程的某个文件或函数,处理完后django将返回值交给wsgi,

        6、wsgi将返回值进行打包,转发给uWSGI, uWSGI接收后转发给nginx,nginx最终将返回值返回给客户端(如浏览器)。 *

        注:不同的组件之间传递信息涉及到数据格式和协议的转换

      软件安装:

        1.yum -y install gcc openssl openssl-devel

        2.install python3
                         ./configure --prefix=/usr/local --with-ssl
                          make && make install
        3. istall pip3
            url:https://github.com/pypa/pip/archive/1.5.5.tar.gz
            python3 setup.py install
           /usr/local/python3/bin       pip 安装的命令都放到这个目录下

        4.pip3 install uwsgi

                5. install nginx

         tar 包安装的ngin,需要自己添加快速启动脚本到 /etc/init.d/下

     #!/bin/sh
     #
     # nginx - this script starts and stops the nginx daemon
     #
     # chkconfig: - 85 15
     # description: Nginx is an HTTP(S) server, HTTP(S) reverse 
     #   proxy and IMAP/POP3 proxy server
     # processname: nginx
     # config: /etc/nginx/nginx.conf
     # config: /etc/sysconfig/nginx
     # pidfile: /var/run/nginx.pid
     # Source function library.
     . /etc/rc.d/init.d/functions
     # Source networking configuration.
     . /etc/sysconfig/network
     # Check that networking is up.
     [ "$NETWORKING" = "no" ] && exit 0
         nginx="/usr/local/nginx/sbin/nginx"
         prog=$(basename $nginx)
         NGINX_CONF_FILE="/usr/local/nginx/conf/nginx.conf"
     [ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx
         lockfile=/var/lock/subsys/nginx
    
     start() {
         [ -x $nginx ] || exit 5
         [ -f $NGINX_CONF_FILE ] || exit 6
         echo -n $"Starting $prog: "
         daemon $nginx -c $NGINX_CONF_FILE
         retval=$?
         echo
     [ $retval -eq 0 ] && touch $lockfile
         return $retval
     }
    
     stop() {
         echo -n $"Stopping $prog: "
         killproc $prog -QUIT
         retval=$?
         echo
     [ $retval -eq 0 ] && rm -f $lockfile
         return $retval
         killall -9 nginx
     }
    
     restart() {
         configtest || return $?
         stop
         sleep 1
         start
     }
    
     reload() {
         configtest || return $?
         echo -n $"Reloading $prog: "
         killproc $nginx -HUP
         RETVAL=$?
         echo
     }
    
     force_reload() {
         restart
     }
    
     configtest() {
         $nginx -t -c $NGINX_CONF_FILE
     }
    
     rh_status() {
         status $prog
     }
    
     rh_status_q() {
         rh_status >/dev/null 2>&1
     }
    
     case "$1" in
         start)
             rh_status_q && exit 0
             $1
         ;;
         stop)
             rh_status_q || exit 0
             $1
         ;;
         restart|configtest)
             $1
         ;;
         reload)
             rh_status_q || exit 7
             $1
         ;;
         force-reload)
             force_reload
         ;;
         status)
             rh_status
         ;;
         condrestart|try-restart)
             rh_status_q || exit 0
         ;;
         *)
             echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|configtest}"
             exit 2
     esac
    nginx_restat.sh

      下面配置uwsgi.ini 文件

    # hello_uwsgi.ini file
    [uwsgi]
    
    # Django-related settings
    
    socket = :9999                   #这里需要配置的socket,如果是http的话,会有错误
    #http = :9999
    
    # the base directory (full path)
    chdir           = /home/right/cache_check
    
    # Django s wsgi file
    module          = cache_check.wsgi
    
    # process-related settings
    # master
    master          = true
    
    # maximum number of worker processes
    processes       = 4
    
    
    #logto = /var/log/uwsgi/%n.log
    daemonize   = /var/log/uwsgi/dango_uwsgi.log
    
    # ... with appropriate permissions - may be needed
    # chmod-socket    = 664
    # clear environment on exit
    vacuum          = true
    
    plugin         = python
    #harakiri    = 12

      添加uwsgi快速启动脚本

    #!/bin/sh
    NAME="dango"
    if [ ! -n "$NAME" ];then
        echo "no arguments"
        exit;
    fi
    
    echo $NAME
    ID=`ps -ef | grep "$NAME" | grep -v "$0" | grep -v "grep" | awk '{print $2}'`
    echo $ID
    echo "################################################"
    for id in $ID
    do
    kill -9 $id
    echo "kill $id"
    done
    echo  "################################################"
    uwsgi --ini /home/right/cache_check/dango_uwsgi.ini

      添加nginx的配置

            location / {
                include uwsgi_params;
                uwsgi_pass 127.0.0.1:9999;
                   uwsgi_send_timeout 1600;        # 指定连接到后端uWSGI的超时时间。
                uwsgi_connect_timeout 1600;   # 指定向uWSGI传送请求的超时时间,完成握手后向uWSGI传送请求的超时时间。
                uwsgi_read_timeout 1600;        # 指定接收uWSGI应答的超时时间,完成握手后接收uWSGI应答的超时时间。
    
                #root   html;
                #index  index.html index.htm;
                #uwsgi_param SCRIPT_NAME;
            }

      到这里配置完毕,可以运行了

      

    针对以上的内容做一个小练习:

      

      可以添加新书,并显示

      

     1 from django.db import models
     2 
     3 # Create your models here.
     4 
     5 class Publisher(models.Model):
     6     name = models.CharField(max_length=30)
     7     address = models.CharField(max_length=50)
     8     city = models.CharField(max_length=60)
     9     state_province = models.CharField(max_length=30)
    10     country = models.CharField(max_length=50,null=True)
    11     website = models.URLField()
    12     def __unicode__(self):
    13         return "<%s>"%(self.name)
    14 
    15 class Author(models.Model):
    16     first_name = models.CharField(max_length=30)
    17     last_name = models.CharField(max_length=40)
    18     email = models.EmailField()
    19     def __unicode__(self):
    20         return "<%s,%s>"%(self.first_name,self.last_name)
    21  
    22 class Book(models.Model):
    23     title = models.CharField(max_length=100)
    24     authors = models.ManyToManyField(Author)
    25     publisher = models.ForeignKey(Publisher)
    26     publication_date = models.DateField()
    27     def __unicode__(self):
    28         return "<%s>"%(self.title)
    models.py
    #!/usr/bin/python
    #coding:utf-8
    
    from django.shortcuts import render
    from django.http import HttpResponse
    from django.template import Context,loader
    from django.contrib.auth import authenticate,login,logout
    
    import models
    # Create your views here.
    
    def booklist(request):
        if request.method == 'POST':
            book_name = request.POST.get('name')
            publisher_id = request.POST.get('publisher_id')
            author_ids = request.POST.get('author_ids')
            print 'books`s name from post -->',request.POST.get('name')
            print 'publisher_id  from post-->',request.POST.get('publisher_id')
            print 'author_ids from post-->',request.POST.get('author_ids')
    
            new_book = models.Book(
                title = book_name,
                publisher_id = publisher_id,
                publication_date = '2016-05-22'
            )
            new_book.save()
            new_book.authors.add(*author_ids)   #表中多对多,需要另外插入
            
        books = models.Book.objects.all()
        publisherlist = models.Publisher.objects.all()
        authorlist = models.Author.objects.all()
    
        return render(request, 'books.html',{'books':books,'publisher':publisherlist,'authorlist':authorlist} ) 
    views.py
     1 <!DOCTYPE html>
     2 <html lang="en" xmlns="http://www.w3.org/1999/html">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>booklist</title>
     6     <style books_name></style>
     7     <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" >
     8     <style>
     9         .book_form{margin-top:10px;}
    10     </style>
    11 </head>
    12 <body>
    13     <div class="container">
    14         </br>
    15         <ul>
    16             {% for book in books %}
    17                 <li>{{book.title}}</li>
    18 
    19             {% endfor%}
    20         </ul>
    21 
    22         </br>
    23         <form method='post' action='/dashboard/books/'>
    24             <div class="col-xs-4">
    25                 输入书名<input type="text" class=" input-sm form-control" name='name' >
    26             </div>
    27             </br>
    28             <div class="col-xs-2">
    29                 <select class="input-sm form-control" name="publisher_id">
    30                     <option >请选择出版社</option>
    31                     {% for banshe in publisher%}
    32                         <option value='{{banshe.id}}'>{{banshe.name}}</option>
    33                     {% endfor%}
    34 
    35                 </select>
    36 
    37             </div>
    38             <div class="col-xs-4">
    39                <select multiple class="form-control" name='author_ids'>
    40                   {% for auth in authorlist%}
    41                   <option value='{{auth.id}}'>{{auth.first_name}}</option>
    42                   {% endfor %}
    43                 </select> 
    44             </div>
    45 
    46             <input type="submit" value="创建新书">
    47         </form>
    48     </div>
    49 </body>
    50 </html>
    前端html

    应用练习

    总结一

      用户登录,前端用户ajax请求登录,后端验证,翻过json给前端,前端通过状态码来判断做什么操作

      涉及的内容:django login, authenticate, login_required  , ajax请求, from表单

    from django.http import HttpResponse, JsonResponse
    from django.http.response import JsonResponse
    from django.shortcuts import render, redirect
    from django.contrib.auth import authenticate, login
    from django.contrib.auth.decorators import login_required
    
    
    @login_required
    def index(request):
        return render(request, 'index.html')
    
    def mylogin(request):
        user_info = {
            'dachengzi':{'pwd':'123'},
            'kangbazi':{'pwd':'123'}
        }
    
        if request.method == 'GET':
            print('I am here')
            return render(request, 'pages/examples/login.html')
    
        elif request.method == 'POST':
            print('I am post request!')
            username = request.POST.get('username')
            password = request.POST.get('password')
            print(username,password)
            res = authenticate(username=username, password=password)
            res_json = {}
            if res is not None:
                login(request,res)
                res_json['status'] = 0
            else:
                res_json['status'] = 1
    
        return JsonResponse(res_json)
    views.py
    <form action="#" >         //防止from自动get请求,这里填入#
          <div class="form-group has-feedback">
            <input id="username" class="form-control" placeholder="Email">
            <span class="glyphicon glyphicon-envelope form-control-feedback"></span>
          </div>
          <div class="form-group has-feedback">
            <input id="password" type="password" class="form-control" placeholder="Password">
            <span class="glyphicon glyphicon-lock form-control-feedback"></span>
          </div>
          <div class="row">
            <div class="col-xs-8">
              <div class="checkbox icheck">
                <label>
                  <input type="checkbox"> Remember Me
                </label>
              </div>
            </div>
            <!-- /.col -->
            <div class="col-xs-4">
              <button id="submit" type="submit" class="btn btn-primary btn-block btn-flat">Sign In</button>
            </div>
            <!-- /.col -->
          </div>
        </form>
    
    
    
    <script>
    
        $('#submit').click(function () {
            username = $('#username').val()
            password = $('#password').val()
    
            $.ajax({
                type:"POST",
                url:"/login/",
                data:{username:username, password:password},
                dataTpye:"json",
                success:function (data1) {
                    status = data1.status
                    if(status ==0){
                        location.href='/'
                    }else{
                        console.log('error')
                    }
                }
            })
    
        })
    
    </script>
    html

              

  • 相关阅读:
    构建maven的web项目时注意的问题(出现Error configuring application listener of class org.springframework.web.context.ContextLoaderListener 或者前端控制器无法加载)
    c3p0私有属性checkoutTimeout设置成1000引发的调试错误:
    sql面试题(学生表_课程表_成绩表_教师表)
    传值与传址
    new String()理解
    hashcode的理解
    CentOs安装ssh服务
    openstack swift memcached
    openstack swift middleware开发
    java实现二叉树
  • 原文地址:https://www.cnblogs.com/nopnog/p/7356905.html
Copyright © 2020-2023  润新知