【Django】 初步学习

这个系列(或者成不了一个系列。。)预计会全程参考Vamei様的Django系列,膜一发。说句题外话,其实更加崇拜像Vamei那样的可以玩转生活、各个领域都能取得不小成就的人。html

【Django】前端

■  概述python

  Django久闻大名,是Python中最为有名的Web框架之一了。相比于其余框架,D的特色就是提供了各类各样的组件,重量级,能够解决不少不少问题。让Web编程一简再简。以前一直都学习使用Flask,不否定Flask有其有点,可是一个很大的不方便的地方在于,Flask的扩展没有统一的标准并且开放,全部人均可以写本身的Flask扩展。虽说是具备开源精神,可是一些比较常见的功能出现多种实现仍是会让人有些困扰。下面简单说说Django的使用mysql

  安装Django依然使用pip:pip install Django,总的包大小大概6.8M。web

  下载完成后能够在Python shell中运行如下命令:ajax

>>>import django
>>>print django.VERSION
(1, 11, 6, u'final', 0)

  说明安装成功。正则表达式

  ●  构建一个Django项目目录框架的快捷方法sql

  让我第一次感觉到Django的重型和周到是相比较于Flask构建项目时要本身一个个文件创建,Django能够一键帮助生成一个较为完整的项目框架等待你填充内容。在pip安装完成以后,若是是windows环境则在$PYTHON_HOME的scripts,若是是Linux环境则是在/usr/bin这些目录下,里面会有一个django-admin[.exe]可执行程序。运行这个程序,后接上参数startproject <项目名>能够在当前工做目录下生成Django项目的目录框架。获得的框架是这样的:shell

  这些也不全是空文件,像manage.py,settings.py等文件都是带有默认内容的。数据库

  考虑到通常开发确定是在windows上用IDE好比Pycharm,Pycharm也能够一键生成Django项目框架,并且比django-admin生成的多一个templates文件夹用来盛放模板文件。

  构建完成框架以后能够python manage.py runserver 8000来运行起这个server,内容由Django内置好。看到的界面是相似于这样的:

 

  ●  第一次为请求返回HTTP内容

  Django框架采用MVC架构,Flask框架中对于路由的响应经过装饰器来绑定响应函数完成。而Django的路由设置统一放在urls.py这个文件中。下面将修改一下urls.py(由于以前存在一些内容了)

from django.conf.urls import url
from django.contrib import admin

#####下面这行是新加的#####
from DjangoTest.views import first_page

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

    #####下面这行是新加的#####
    url(r'^$', first_page)
]

  先来解释一下urlpatterns这个列表,维护了整个项目的url和响应函数的对应关系。这里比较NB的一点在于支持的是正则表达式,也就是说能够为一批URL绑定相同的响应函数。这一个和Flask仍是比较不一样的。Flask若是须要正则路由匹配的支持,则须要本身到werkzeug.routing中本身实现一个支持正则的Convertor对象。

  默认的自带了Django服务器后面的URI若是是/admin/的话,那么路由到Django-Admin界面,而下面咱们添加的那条,则是说明了当请求URL为空(即访问的URI是/时),则路由到first_page这个函数中去。那么first_page在哪里定义呢,看上面的import语句,是DjangoTest目录下的views文件。这个文件是咱们本身建的而且要往里面写内容的。好比下面这样:

from django.http import HttpResponse

def first_page(request):
    return HttpResponse('<h1>Hello World</h1>')

 

  ●  进行模块化管理

  一个网站可能有不少功能,所以确定须要进行模块化的代码管理。这一点在Flask中能够用相似于blueprint的结构来实现。而在Django中这个被称为app(默默吐槽,比Flask恰好高了一级)

  运行一个项目中的manage.py好比python manage.py startapp new_app就能够在当前项目中增长一个名为new_app的目录,下面也有admin.py,__init__.py,models.py,tests.py和views.py等文件。

  光添加一个新的目录并无用,还须要将这个目录所表明的APP和当前项目关联起来。关联的方法就是修改DjangoTest下的settings.py文件。这个文件中有一个INSTALLED_APPS列表,在其中添加'new_app'便可。另外能够看到这个INSTALLED_APP里面已经有一些内容存在了,这些内容表明了Django内置的一些功能好比用户验证,会话管理,显示静态文件等等。Django识别APP是从项目的根目录开始的,因此不用像已有的那些写得比较复杂好比django.contrib.admin,而直接写new_app便可。

  为了访问到一个单独APP中的页面,咱们首先在项目总的urls.py中添加new_app的urls的相关信息(这样作有利于不一样模块的url映射的各自维护,模块间解耦)。把DjangoTest下的urls.py修改:

from django.conf.urls import url,include
from django.contrib import admin
from DjangoTest.views import first_page

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^$', first_page)
    #####下面这行新增#####
    url(r'^new/', include('new_app.urls'))
]

 

  看到这里其实已经能够大概看出来Django中如何进行url的配置了。往urlpatterns里面能够增长url对象。url对象构建时第一个参数是正则匹配路径,第二个参数能够是一个callable的对象,此时须要在以前import进去;也能够是include方法的返回,include方法的参数是一个字符串,字符串中以endpoint的形式指向另外一个urls文件,此时那个urls文件中规定的正则匹配路径在整个项目中应该加上调用其include方法前面的路径整个拿来匹配。

  上面把new_app.urls文件中定义的url映射都include到了根目录下,然而在new_app下目前尚未urls.py文件,因此在这个目录下新建urls.py。文件中的内容参考下面这样子:

from django.conf.urls import url

from .views import new_first_page

urlpatterns = [
  url('^$', new_first_page),
]

 

  这么处理以后访问/new/就会映射到new_first_page这个函数下了。

 

■  数据库和ORM初步

  一个WEB应用的根基在于数据库中的数据,一个好的web框架必须有很好的和数据库交互的手段。以前在Flask的时候,采用了SQLAlchemy的第三方模块的方法,将flask和数据库的交互作得比较友好。到了Django的场合,Django有一套本身的ORM机制,看起来很像SQLAlchemy(事实上好像就是改造了SQLAlchemy),贴合度更好。

  要进行数据库交互,首先得有数据库。好比我先到虚拟机的mysql中建立一个Django项目用的数据库,而且指定(或者建立)一个用户来管理这个库:

$mysql -u root -p
password:
mysql>CREATE DATABASE Django_Test DEFAULT CHARSET utf8;

mysql>GRANT ALL PRIVILEGES ON Django_Test.* TO weiyz@'%';
/*将新建的数据库的操做权限赋给管理用户*/
mysql>FLUSH PRIVILEGES;

 

  而后在Django项目的settings.py中的数据库相关配置更改:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'Django_Test',
        'USER' : 'weiyz',
        'PASSWORD' : '123456',
        'HOST' : '192.168.191.112',
        'PORT' : '3306',
    }
}

 

   这样就关联了数据库和Django项目。

  web和数据库的交互形式是一个很重要的问题。若是咱们使用MySQLdb这类包装的比较低级的模块来作的话,每个数据库操做都要写一个SQL语句出来,略显笨拙。ORM的妙处就在于可以把数据库操做封装得像是一段原生的程序。Django采起的抽象数据库操做的方式和SQLAlchemy很像,就是把一张表抽象成一个python类。好比咱们在new_app这个APP中的models.py中加入如下内容:

from __future__ import unicode_literals

from django.db import models

class Character(models.Model):
    name = models.CharField(max_length=200)
    age = models.IntergerField()

    def __unicode__(self):
        return self.name

 

  此时项目中已经设计好了表,就差把表结构给注入数据库了。然而这个过程若是手动作就没有意义了。Django给出了自动的解决方案。依次运行以下命令:

python manage.py migrate

python manage.py makemigrations

python manage.py migrate

  第一个migrate能够看作是数据库的初始化,运行完第一条以后进入数据库看能够看到Django_Test库中有了下面这些表

+----------------------------+
| Tables_in_Django_Test      |
+----------------------------+
| auth_group                 |
| auth_group_permissions     |
| auth_permission            |
| auth_user                  |
| auth_user_groups           |
| auth_user_user_permissions |
| django_admin_log           |
| django_content_type        |
| django_migrations          |
| django_session             |
+----------------------------+

  这些表也不是空表,都是有数据的并且比较重要。至于为何后面再说。

  第二条命令是将咱们新建的表(也就是models里面的类)给记录到APP的migrations目录中的一个文件。这个目录在python manage.py startapp的时候自动建立,且里面自带一个__init__.py。这些文件是做为后续数据库版本的升降级操做的依据,因此也不该该擅自删改。此时migrations目录下应该就有了一个0001_initial.py的文件了。

  第三条则是把本地的数据库信息同步到真的数据库中,在操做完这个命令以后,咱们能够看到数据库中会多出一张new_app_character的表,其表结构是和咱们的Character类定义的相同。

  ●  如何初始化migrations相关数据

  能够看到有django_migrations这个表,说明在数据库升降级的时候并非单单看migrations目录下面有哪些文件的,而是参考了数据库中的数据。因此说数据库中的那些初始化信息也很重要。这么一来,想要初始化全部数据库数据就不能简单的把migrations下面的文件删光了。比较完全的作法是把整个Django_Test数据库drop掉,而后把migrations中的除了__init__外全部文件删掉。再从新建库,migrate,makemigrations这样来作。

  固然在正式生产中确定不能这么作,这就代表,对于数据库初始化出来的数据以及migrations中的文件必定不能轻易修改删除。理想的作法是对表结构作出调整以后先makemigrations再migrate一下。

  这里顺便一提,进行数据库版本升级的时候django作得仍是很智能的。好比我一开始没有age字段,migrate的时候添加了age字段可是没指定default,django就提示说若是表里原来有记录的话就不知道新插入这个age字段该取什么值,让我选择时系统自动给一个default值呢仍是回models.py中手动指定一个default值。

  经过ORM进行增删查改之后慢慢说,这里只展现一下:

  首先经过后台插入数据:

INSERT INTO new_app_character (name,age) VALUES('Django',50);

  须要注意的是必定要给出(name,age),由于上面定义的时候咱们没有给出主键,orm自动为这个表添加一个名为id的字段做为主键,从1开始天然计数。

  而后在程序中好比在views中能够:

from .models import Character
from django.http import HttpResponse

def new_first_page(request):
    namelist = Character.objects.all()
    res = ''
    for name in namelist:
        res += '<p>%s</p>' % name
    return HttpResponse(res)

  这就实现了经过ORM从数据库中取出数据的目的了。

 

■  Django模板初步

  如上面目录中那样,在项目的根目录级下有一个templates目录,里面存放的天然就是项目的模板文件了。

  在settings.py中,能够看到一个配置项是TEMPLATES,下面有一个DIRS的配置项,这是一个list。其中默认的是那个templates目录,也能够本身手动再增长一些其余的目录,这样就实现了多个模板目录的设置了。至于模板的语法和渲染模板的方法如下面这个例子作个最简单的说明:

####模板文件test.html####
<h1>{{ label }}</h1>

####某个views.py文件中增长内容####
from django.shortcuts import render

def template_show(request):
    context = {}
    context['label'] = 'Hello World'
    return render(request, 'test.html', context)

  以后在相应的APP的urls.py中添加对url的路由,访问相关页面就能够看到html为<h1>Hello World</h1>的页面了。这里能够注意一下render方法和flask中render_template的一些不一样,为了不大量变量渲染时引发的参数过长的问题,把全部参数都维护到一个context字典里面能够说是一个很是好的办法。

  Django在渲染模板的时候,首先将上下文数据context传递给模板文件,分析模板文件中须要渲染的部分,具体化以后又自动生成了HTTPResponse返回,因此咱们在这里能够直接return render方法的返回。结合上面说的ORM,能够从数据库中取出数据,进行必定程度的处理以后再传递给模板,这就完成了一个很是MVC的流程。

  以前在学习flask的时候就据说过Django的模板和Jinja2不太同样,可是粗粗看了下教程,发现是大同小异的,这里就再也不费口舌说一些基本的东西了。主要补充一些听说和jinja2不一样的地方(动态更新中...),好比在Django的模板中,无参函数的调用时不用机加括号的,可是jinja2是和原生的Python同样加括号。

  整体而言,Django的模板系统比Jinja2有更多的限制,也更不像是python或者其余的编程语言。好比Jinja2中可能会有{% if name == 'takanashi' %}这样的表达可是听说Django是不行的等等。

 

  ●  关于宏

  以前彷佛没有提到,django的模板系统中是不存在宏这种设定的。也就是说不能直接使用{% macro xxx %}这样的方式来定义宏从而减小编写重复代码的次数。

  不过好在有解决方案就是django-macros。pip install一下以后,在项目的settings中的INSTALLED_APPS中添加'macros',而后再在相关模板中{% load macros %}以后,这个模板文件里就能够自由使用macro了。

  ●  关于自动反转义

  若是后端传到模板的字符串中含有一些HTML敏感的字符好比<,>,&等,Django在渲染模板的时候会自动将这些内容进行一个反转义,从而使页面能够正确地显示这些文本。好比

  <div>{{ text }}</div>是模板,而后后端的ctx={'text': 'Hello,<b>World</b>'},渲染出获得的页面会是Hello,<b>World</b>,而不是Hello,World这样加粗字体的。

  有时若是须要反过来,不要他强行自动转义,则能够在模板中使用{% autoescape %}标签,包含在{% autoescape off %}{% endescape %}这个block中的全部待渲染的内容,是不会自动转义,而是保持HTML原有的样式的。

 

■  Django的表单处理

  任何一个Web框架都少不了对表单的支持。下面演示一个最简单的经过POST方法发送数据给WEB应用而后将数据存入数据库以后返回一个页面的Django的结构。models等一些数据复用了前面提到过的东西:

<!-- 模板页面 -->
<form method="post" action="/new/process/">
  {% csrf_token %}
  <input type="text" name="name" />
  <input type="number" name="age" />
  <input type="submit" value="Submit" />
</form>

<p>{{ rlt }}</p>
<p>{{ age }}</p>

  在后台的new_app/views.py中:

from django.shortcuts import render
from django.template.context_processors import csrf

def process(request):
  ctx = {}
  ctx.update(csrf(request))
  if request.POST:
    ctx['rlt'] = request.POST['name']
    ctx['age'] = request.POST['age']
  return render(request, 'formtest.html', ctx)

 

  这里须要注意的是在模板中咱们就作了csrf的处理,而后在后台也要进行一个csrf的处理,而后根据处理完以后的context再来渲染页面。能够看到,在Django里面默认不作出对某个url的访问方法的限制。因此在urls.py中定义了到这个处理函数的路由(/new/process)后访问这个路由,首先是GET方法获取页面,此时由于context中没有定义rlt和age这两个模板中的变量,因此页面下方是两个空行。而后填完数据表单提交,由于form标签的action指向仍是这个路由,因此POST数据到process函数下面。由于是POST,进入分支,context中有了关于rlt和age的值,因而就渲染出有值的页面了。

  若是须要将POST上来的数据根据刚才定义的model存进数据库那么能够:

def process(request):
  ctx = {}
  ctx.update(csrf(request))
  if request.POST:
    name,age = request.POST.get('name'),request.POST.get('age')
    new_record = Character(name=name,age=age)
    new_record.save()
  return render(request, 'formtest.html', ctx)

  这也是大概地展现一下如何用ORM进行“增”的数据库操做

  

  在flask中,咱们用到了wtforms来进行方便的表单渲染和管理,Django也有相似的功能。并且Django把表单管理的模块也一并整合到了Django这个大模块中,因此使得表单的描述和数据库表结构的描述能够统一块儿来。而这二者在实际中又经常是互相关联的。好比上面的那个表单,咱们能够作如下改造:

from django import forms

class CharacterForm(froms.Form):
    name = forms.Charfield(max_length=200,label="Your Name")
    age = forms.IntegerField(min_value=18)

def process(request):
    context = {}
    context.update(csrf(request))
    if request.POST:
        form = CharacterForm(request.POST)
        if form.is_valid():
            #do something with data
    form = CharacterForm()
    context['form'] = form
    return render(request, 'form_test.html', context)

####在模板中能够这么写####
{{ form.as_p }}
####这样就能够自动地生成一个表单了####

   虽然说是自动生成了表单,可是须要注意的是并非所有要素,只是要填的一些字段和相关的label等等,好比<form> 标签已经submit的input等仍是要本身手写的,至关于as_p方法只是放回了纯的变成了p标签形式的表单html代码。

  ●  对于ajax发起post请求的csrf处理

  以上对于表单发起post请求的举例都是经过了<form>这个DOM来实现的。可是在有ajax的时候咱们能够没必要拘泥于form而采用更加自由的ajax发起POST请求。这就引发了一个小问题,在form的时候咱们只要在前端模板里面写上{% csrf_token %}就能够自动给咱们的表单DOM增长防csrf验证功能。可是在ajax的时候如何将这部分信息和一个特定的ajax请求联系起来。办法有不少种,好比能够在页面中引入额外的一个csrf.js文件来适应csrf验证【参考https://code.ziqiangxuetang.com/django/django-csrf.html】。

  一个更加简单的方法是在全局ajax设置中增肌相关csrf验证的设置:

$.ajaxSetup({
  data: {
    csrfmiddlewaretoken: '{{ csrf_token }}'
  }
});

 

  这个办法须要注意的是1. 这段代码应该写在模板文件的<script>标签中由于{{ csrf_token }}这个只有在模板里面才能被识别,写在.js中是没法被识别的。2. csrf_token要用{{ }}括起来而不是{% %},具体缘由不知道。。总之只有这样才行。

  还有一个不是办法的办法,就是在相关的ajax的POST发向的那个view,from django.views.decorators.csrf import csrf_exempt,而后在这个view函数上面增长装饰器@csrf_exempt来迫使这个view接受到的请求不进行CSRF验证。

■  Django自带的WebApp

  之因此称Django是一个很大的框架,缘由在于它自带了不少功能,其中感受到最神奇的就是这个,自带的一个管理数据库的APP。这个APP一般在settings.py的INSTALLED_APPS中已经预安装好,而且在项目根目录的urls.py中还设置好了url,一般是[site]/admin来访问。

  这个App实际上是一个管理数据库模型的一个App,在经过它管理模型以前还须要在相关模型所在的应用中的admin.py下进行模型的注册。作法是:

###admin.py###
from models import Character

admin.site.register(Character)

 

  若是是第一次访问管理界面,那么须要用manage.py工具的createsuperuser命令来创建管理员用户,按照字符界面的提示输入管理员的用户名密码等信息来注册管理员用户。

  登陆以后咱们能够看到这样的界面:

  能够看到咱们注册的new_app下面的Character模型已展现在页面上了。至于上面的是Django预装的Auth模块,咱们之后还能够用它来进行用户的管理。由于用户说到底也只是数据库中的一张表,一个模型而已。另外这个web界面管理真的十分方便,这个Character的模型还略显简单了点,若是是个稍微复杂一点的模型好比:

class Role(models.Model):
    role_code = models.IntegerField(primary_key=True)
    role_name = models.CharField(max_length=100)
    def __unicode__(self):
        return self.role_name

class User(models.Model):
    name = models.CharField(max_length=100,primary_key=True)
    age = models.IntegerField()
    email = models.EmailField()
    role = models.ForeignKey(Role)
    def __unicode__(self):
        return '%s(%s)  Mail:%s' % (self.name,self.age,self.email)

  涉及到了外键的设置,此时若是先点击Role旁边的Add,能够手动为数据库中添加角色信息:

  当添加完一些信息以后,到添加User的界面中还能够看到刚才添加过的角色信息供选择:

  须要注意的是添加一条记录后会给出一个提示中有中文,再有就是好比这边角色的几个名字,这些都是根据__unicode__的返回决定的。因此在model类实现的时候须要实现__unicode__方法,而且想好一种表达清晰的返回。在开发阶段进行小批量的数据插入的时候,这个界面显然比到后台用SQL插入数据要友好不少。

  此外若是须要对某些字段进行隐藏处理的话能够修改一下new_app/admin.py中的内容,以前咱们直接admin.site.register了全部模型类。若是想要进行字段显示的调整能够在new_app/admin.py中进行:

from django.contrib import admin

from models import User,Role

class UserShow(admin.ModelAdmin):
    fields = ('name','age','role')    #没加email

admin.site.register(User,UserShow)
admin.site.register(Role)    #Role表不变,可是User表有所调整

 

  这样的话在界面上不管是读取User记录的信息仍是新增一个User的记录,Email字段就都不会显示出来了。其实这么作的原理显而易见,就是把一个ModelAdmin类的衍生类和咱们的模型类关联起来。上面这个ModelAdmin的子类UserShow用到了fields这个属性来设置显示不显示,其实还有更强大的属性好比fieldsets:

class UserShow(admin.ModelAdmin):
    fieldsets = (
        ['基本信息',{
            'classes' : ('collapse',),    # CSS设置
            'fields' : ('name','age')
        }],
        ['更多信息',{
            'classes' : ('collapse',),
            'fields' : ('email','role')
        }]
    )

 

   若是UserShow跟上面这样写的话,获得的界面就是:

  基本信息和更多信息两个Panel均可以经过点击旁边的hide和show来隐藏显示。

  相似的,设置这个类中的list_display属性能够改变展现界面的字段展现,下面贴出代码和修改先后界面的图:

class UserShow(admin.ModelAdmin):
    list_display = ('name','age','email','role')

   改变前:

  改变后:

 

■  用户验证与管理

  以前提到过Django预装了Auth这个用户管理模块,那么要怎么使用。首先在settings.py中的INSTALLED_APPS中通常是有admin.contrib.auth这个APP在了。在http://site/admin这个管理界面上能够在系统自带的那个Users中去添加删除用户,固然这个页面最好不要暴露给通常用户,正确的作法应该是本身设计一个表单收集用户提供的信息,而后根据信息进行后台的相关操做。由于用户的信息也在Django设计的用户系统的框架内因此后台那些操做天然也是Django自身提供的一些封装好的方法。

  在进行下面的说明以前,咱们先创建一个名为users的App来单独进行用户的一些操做:python manage.py startapp users

  ●  用户的登陆、验证和登出

  前端模板:

<!-- login.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{{ request.path }}</title>
</head>
<body>
<form method="post" action="/users/login">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Go!" />
</form>

</body>
</html>

  后端views.py:

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.shortcuts import render,redirect
from django.template.context_processors import csrf
from django import forms
from django.contrib.auth import authenticate,login
# Create your views here.

class LoginForm(forms.Form):
    username = forms.CharField(max_length=100,min_length=3)
    password = forms.CharField(min_length=8,widget=forms.PasswordInput)
    email = forms.EmailField()

def user_login(request):
    context = {}
    context.update(csrf(request))
    login_form = LoginForm()
    if request.POST:
        username = password = ''
        username = request.POST.get('username')
        password = request.POST.get('password')
        user = authenticate(username=username,password=password)
        if user is not None and user.is_active:
            login(request,user)
            return redirect('/')
        else:
            return redirect('/users/login')
    context['form'] = login_form
    return render(request,'login.html',context)

 

  这里比较新鲜的就是contrib.auth中的authentication和login两个方法。当用户在表单中输入信息而后POST上来以后,咱们能够直接调用authentication方法来快速验证用户密码的正确性,若是验证经过将返回这个用户的User对象。若是没有经过则是返回None。须要注意的是Django内建的User对象还具备active这个属性即用户是否在有效期内,若是不是的那么也不能将用户放行。另外,自带的这个验证机制彷佛不能判别是用户不存在仍是密码错误致使的验证没经过。

  login方法则更像是一个状态置活方法,经过验证以后调用这个方法来告诉系统当前用户XXX是登陆状态的。在调用过login方法以后就能够保持整个会话过程当中用户身份的保持了。

  在其余的视图中,能够经过request.user这个对象来调用当前登陆用户相关的一些信息。好比user.get_username()返回用户名,user.set_password('xxx')能够重设密码,user.password则能够看到密码的密文,date_joined和last_login分别能够看到帐号建立时间和上次登陆时间,不过这两个时间的时区有点诡异,反正都不是东八区。user.check_password('xxx')能够对一段明文是不是密码进行验证,能够用于用户登陆以后还须要验证密码的场合好比受权等等。下面是一个在其余视图(非登陆相关视图)中调用user信息的示例:

def auth_test(request):
    context = {}
    if request.user.is_authenticated():
        return HttpResponse('<p>%s</p>' % request.user.get_username())
    else:
        return redirect('/user/login')

 

  这里用的判断当前是否有用户的方式是用了if 语句判断user.is_authenticated方法返回的状态。其实还有更加方便的方法就是使用装饰器login_required:

from django.contrib.auth.decorators import login_required

@login_required
def auth_test(request):
    return HttpResponse('<p>%s</p>' % request.user.get_username())

  这里一个小问题是当用户处于登出状态的时候,若是访问@login_required修饰的路由函数会怎么样。默认状况下,会转送到uri为accounts/login?next=/xxxx(auth_test的路由),若是没有定义过accounts/login的话那么引发的就是404了。其实在使用@login_required的时候能够加上参数(login_url='/users/login')来把页面重定向到咱们设计好的/users/login下面去。只不过next这个参数仍是没有自带的实现的,因此还须要咱们在login的路由函数中再添加对GET参数next的一些处理。若是不但愿在后台作判断的话也能够在前台的模板中进行判断,好比添加一条{% if user.is_authenticated %}(Django模板函数不加括号哦),具体就不写出来了。

  说到登出,登出更加简单:

from django.contrib.auth import logout

def user_logout(request):
    logout(request)
    return redirect('/')

  相比于login,logout只须要request这一个参数。

 

■  用户注册

   用户注册和用户登陆相似,只不过接受表单的数据以后作的处理不太同样。固然咱们能够手动写一个表单的html来作,不过对于简单的用户注册,还有更加方便的操做:

from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import redirect,render
from django.template.context_processors import csrf

def user_register(request):
    if request.method == 'POST':
        form = UserCreationForm(request.POST)
        if form.is_valid():
            new_user = form.save()
        return redirect('/')

    else:
        form = UserCreationForm()
        context = {'form':form}
        context.update(csrf(request))
        return render(request, 'register.html', context)

  前端模板:

<form action="" method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <input type="submit" value="Submit" />
</form>

  尝试了一下,渲染出来的表单仍是很是难看的。。

 

 ■  自定义用户表

  若是以为django.contrib.models.User这个模型不能知足你的需求的话,也能够经过继承这个模型来自定义一个用户类。这个自定义的用户类能够适用于以前全部User类能够用的方法和函数。至关因而对django自带的User类进行了一个很好的扩展。

  继承是一种办法,另外一种办法就是自定义一个模型类以后,在类中增长一个OneToOneField映射到User这个表上。经过OneToOneField映射的好处就是在调用时能够直接request.user.xxx来调用咱们自定义的类,十分方便。

  若是对于定制要求比较高,那么也能够到更底层去,好比从AbstractBaseUser(User类的父类的父类)和AbstractUserManager开始继承。

===============

至此,Django的基本介绍结束,原博主还写了两篇关于用Web容器部署项目以及买服务器部署服务的,这里不太须要就很少说了。

这篇文章顶可能是对Django有一个大概的印象,接下来我会看书本,把上面提到的知识细化,分块记录下来。

以上。

相关文章
相关标签/搜索