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

          

原文地址:https://www.cnblogs.com/nopnog/p/7356905.html