分页

Django的分页器(paginator)

view



from django.shortcuts import render,HttpResponse

# Create your views here.
from app01.models import *
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

def index(request):

    '''
    批量导入数据:

    Booklist=[]
    for i in range(100):
        Booklist.append(Book(title="book"+str(i),price=30+i*i))
    Book.objects.bulk_create(Booklist)
    '''

    '''
分页器的使用:

    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)

    print("count:",paginator.count)           #数据总数
    print("num_pages",paginator.num_pages)    #总页数
    print("page_range",paginator.page_range)  #页码的列表



    page1=paginator.page(1) #第1页的page对象
    for i in page1:         #遍历第1页的所有数据对象
        print(i)

    print(page1.object_list) #第1页的所有数据


    page2=paginator.page(2)

    print(page2.has_next())            #是否有下一页
    print(page2.next_page_number())    #下一页的页码
    print(page2.has_previous())        #是否有上一页
    print(page2.previous_page_number()) #上一页的页码



    # 抛错
    #page=paginator.page(12)   # error:EmptyPage

    #page=paginator.page("z")   # error:PageNotAnInteger

    '''


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 10)
    page = request.GET.get('page',1)
    currentPage=int(page)


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",{"book_list":book_list,"paginator":paginator,"currentPage":currentPage})



index.html:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" 
    integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>

<div class="container">

    <h4>分页器</h4>
    <ul>

        {% for book in book_list %}
             <li>{{ book.title }} -----{{ book.price }}</li>
        {% endfor %}

     </ul>


    <ul class="pagination" id="pager">

                 {% if book_list.has_previous %}
                    <li class="previous"><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li>
                 {% else %}
                    <li class="previous disabled"><a href="#">上一页</a></li>
                 {% endif %}


                 {% for num in paginator.page_range %}

                     {% if num == currentPage %}
                       <li class="item active"><a href="/index/?page={{ num }}">{{ num }}</a></li>
                     {% else %}
                       <li class="item"><a href="/index/?page={{ num }}">{{ num }}</a></li>

                     {% endif %}
                 {% endfor %}



                 {% if book_list.has_next %}
                    <li class="next"><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li>
                 {% else %}
                    <li class="next disabled"><a href="#">下一页</a></li>
                 {% endif %}

            </ul>
</div>



</body>
</html>

扩展


def index(request):


    book_list=Book.objects.all()

    paginator = Paginator(book_list, 15)
    page = request.GET.get('page',1)
    currentPage=int(page)

    #  如果页数十分多时,换另外一种显示方式
    if paginator.num_pages>30:

        if currentPage-5<1:
            pageRange=range(1,11)
        elif currentPage+5>paginator.num_pages:
            pageRange=range(currentPage-5,paginator.num_pages+1)

        else:
            pageRange=range(currentPage-5,currentPage+5)

    else:
        pageRange=paginator.page_range


    try:
        print(page)
        book_list = paginator.page(page)
    except PageNotAnInteger:
        book_list = paginator.page(1)
    except EmptyPage:
        book_list = paginator.page(paginator.num_pages)


    return render(request,"index.html",locals())

自定义分页器



"""
分页组件使用示例:

    obj = Pagination(request.GET.get('page',1),len(USER_LIST),request.path_info)
    page_user_list = USER_LIST[obj.start:obj.end]
    page_html = obj.page_html()

    return render(request,'index.html',{'users':page_user_list,'page_html':page_html})


"""


class Pagination(object):

    def __init__(self,current_page,all_count,base_url,per_page_num=2,pager_count=11):
        """
        封装分页相关数据
        :param current_page: 当前页
        :param all_count:    数据库中的数据总条数
        :param per_page_num: 每页显示的数据条数
        :param base_url: 分页中显示的URL前缀
        :param pager_count:  最多显示的页码个数
        """

        try:
            current_page = int(current_page)
        except Exception as e:
            current_page = 1

        if current_page <1:
            current_page = 1

        self.current_page = current_page

        self.all_count = all_count
        self.per_page_num = per_page_num

        self.base_url = base_url

        # 总页码
        all_pager, tmp = divmod(all_count, per_page_num)
        if tmp:
            all_pager += 1
        self.all_pager = all_pager


        self.pager_count = pager_count
        self.pager_count_half = int((pager_count - 1) / 2)

    @property
    def start(self):
        return (self.current_page - 1) * self.per_page_num

    @property
    def end(self):
        return self.current_page * self.per_page_num

    def page_html(self):
        # 如果总页码 < 11个:
        if self.all_pager <= self.pager_count:
            pager_start = 1
            pager_end = self.all_pager + 1
        # 总页码  > 11
        else:
            # 当前页如果<=页面上最多显示11/2个页码
            if self.current_page <= self.pager_count_half:
                pager_start = 1
                pager_end = self.pager_count + 1

            # 当前页大于5
            else:
                # 页码翻到最后
                if (self.current_page + self.pager_count_half) > self.all_pager:
                    pager_end = self.all_pager + 1
                    pager_start = self.all_pager - self.pager_count + 1
                else:
                    pager_start = self.current_page - self.pager_count_half
                    pager_end = self.current_page + self.pager_count_half + 1

        page_html_list = []

        first_page = '<li><a href="%s?page=%s">首页</a></li>' % (self.base_url,1,)
        page_html_list.append(first_page)

        if self.current_page <= 1:
            prev_page = '<li class="disabled"><a href="#">上一页</a></li>'
        else:
            prev_page = '<li><a href="%s?page=%s">上一页</a></li>' % (self.base_url,self.current_page - 1,)

        page_html_list.append(prev_page)

        for i in range(pager_start, pager_end):
            if i == self.current_page:
                temp = '<li class="active"><a href="%s?page=%s">%s</a></li>' % (self.base_url,i, i,)
            else:
                temp = '<li><a href="%s?page=%s">%s</a></li>' % (self.base_url,i, i,)
            page_html_list.append(temp)

        if self.current_page >= self.all_pager:
            next_page = '<li class="disabled"><a href="#">下一页</a></li>'
        else:
            next_page = '<li><a href="%s?page=%s">下一页</a></li>' % (self.base_url,self.current_page + 1,)
        page_html_list.append(next_page)

        last_page = '<li><a href="%s?page=%s">尾页</a></li>' % (self.base_url,self.all_pager,)
        page_html_list.append(last_page)

        return ''.join(page_html_list)



中间件

render_template 传值_ViewUI

中间件的概念

中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。

Django的中间件的定义:



Middleware            is            a framework of hooks into Django’s request           /           response processing. <br>It’s a light, low           -           level “plugin” system            for            globally altering Django’s            input            or            output.



如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。

可能你还想在view执行之前做一些操作,这种情况就可以用 middleware来实现。

大家可能频繁在view使用request.user吧。 Django想在每个view执行之前把user设置为request的属性,于是就用了一个中间件来实现这个目标。所以Django提供了可以修改request 对象的中间件 AuthenticationMiddleware

Django默认的Middleware


MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]


每一个中间件都有具体的功能。

自定义中间件

中间件中一共有四个方法:


process_request

process_view

process_exception

process_response

process_request,process_response

当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者。

render_template 传值_render_template 传值_02

上述截图中的中间件都是django中的,我们也可以自己定义一个中间件,我们可以自己写一个类,但是必须继承MiddlewareMixin

需要导入



from            django.utils.deprecation            import            MiddlewareMixin


 

render_template 传值_render_template 传值_03

in views:



def index(request):

    print("view函数...")
    return HttpResponse("OK")


in Mymiddlewares.py:

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
 
    def process_response(self,request,response):
        print("Md1返回")
        return response

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2请求")
        #return HttpResponse("Md2中断")
    def process_response(self,request,response):
        print("Md2返回")
        return response

结果:



Md1请求 Md2请求 view函数... Md2返回 Md1返回



注意:如果当请求到达请求2的时候直接不符合条件返回,即return HttpResponse("Md2中断"),程序将把请求直接发给中间件2返回,然后依次返回到请求者,结果如下:

返回Md2中断的页面,后台打印如下:



Md1请求 Md2请求 Md2返回 Md1返回



流程图如下:

render_template 传值_render_template 传值_04

 

process_view



process_view(           self           , request, callback, callback_args, callback_kwargs)



 Mymiddlewares.py修改如下



from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
        #return HttpResponse("Md1中断")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md1view")

class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2请求")
        return HttpResponse("Md2中断")
    def process_response(self,request,response):
        print("Md2返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("Md2view")



结果如下:



Md1请求 Md2请求 Md1view Md2view view函数... Md2返回 Md1返回



下图进行分析上面的过程:

render_template 传值_ViewUI_05

当最后一个中间的process_request到达路由关系映射之后,返回到中间件1的process_view,然后依次往下,到达views函数,最后通过process_response依次返回到达用户。

process_view可以用来调用视图函数:


class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
        #return HttpResponse("Md1中断")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):

        # return HttpResponse("hello")

        response=callback(request,*callback_args,**callback_kwargs)
        return response


结果如下:



Md1请求 Md2请求 view函数... Md2返回 Md1返回



注意:process_view如果有返回值,会越过其他的process_view以及视图函数,但是所有的process_response都还会执行。

process_exception



process_exception(           self           , request, exception)



示例修改如下:



class Md1(MiddlewareMixin):

    def process_request(self,request):
        print("Md1请求")
        #return HttpResponse("Md1中断")
    def process_response(self,request,response):
        print("Md1返回")
        return response

    def process_view(self, request, callback, callback_args, callback_kwargs):

        # return HttpResponse("hello")

        # response=callback(request,*callback_args,**callback_kwargs)
        # return response
        print("md1 process_view...")

    def process_exception(self):
        print("md1 process_exception...")



class Md2(MiddlewareMixin):

    def process_request(self,request):
        print("Md2请求")
        # return HttpResponse("Md2中断")
    def process_response(self,request,response):
        print("Md2返回")
        return response
    def process_view(self, request, callback, callback_args, callback_kwargs):
        print("md2 process_view...")

    def process_exception(self):
        print("md1 process_exception...")



结果如下:



Md1请求
Md2请求
md1 process_view...
md2 process_view...
view函数...

Md2返回
Md1返回



流程图如下:

当views出现错误时:

render_template 传值_render_template 传值_06

 将md2的process_exception修改如下:



def process_exception(self,request,exception):

        print("md2 process_exception...")
        return HttpResponse("error")


结果如下:



Md1请求 Md2请求 md1 process_view... md2 process_view... view函数... md2 process_exception... Md2返回 Md1返回



 

Django实现的SESSION

 

1、 基本操作



1           、设置Sessions值          
                      request.session[           'session_name'           ]            =           "admin"          
           2           、获取Sessions值          
                      session_name            =           request.session[           "session_name"           ]          
           3           、删除Sessions值          
                      del            request.session[           "session_name"           ]          
           4           、检测是否操作session值          
                      if            "session_name"            is            request.session :



1、 基本操作



1           、设置Sessions值          
                      request.session[           'session_name'           ]            =           "admin"          
           2           、获取Sessions值          
                      session_name            =           request.session[           "session_name"           ]          
           3           、删除Sessions值          
                      del            request.session[           "session_name"           ]          
           4           、检测是否操作session值          
                      if            "session_name"            is            request.session :



5           、get(key, default           =           None           )          
                      
           fav_color            =            request.session.get(           'fav_color'           ,            'red'           )          
                      
           6           、pop(key)          
                      
           fav_color            =            request.session.pop(           'fav_color'           )          
                      
           7           、keys()          
                      
           8           、items()          
                      
           9           、setdefault()          
                      
           10           、flush() 删除当前的会话数据并删除会话的Cookie。          
                      这用于确保前面的会话数据不可以再次被用户的浏览器访问          
                      例如,django.contrib.auth.logout() 函数中就会调用它。          
                      
                      
           11            用户session的随机字符串          
                      request.session.session_key          
                      
                      # 将所有Session失效日期小于当前日期的数据删除          
                      request.session.clear_expired()          
                      
                      # 检查 用户session的随机字符串 在数据库中是否          
                      request.session.exists(           "session_key"           )          
                      
                      # 删除当前用户的所有Session数据          
                      request.session.delete(           "session_key"           )          
                      
                      request.session.set_expiry(value)          
                      *            如果value是个整数,session会在些秒数后失效。          
                      *            如果value是个datatime或timedelta,session就会在这个时间后失效。          
                      *            如果value是           0           ,用户关闭浏览器session就会失效。          
                      *            如果value是           None           ,session会依赖全局session失效策略。



2、 流程解析图

render_template 传值_render_template 传值_07

 3、 示例

views:



def log_in(request):

    if request.method=="POST": username=request.POST['user'] password=request.POST['pwd'] user=UserInfo.objects.filter(username=username,password=password) if user: #设置session内部的字典内容 request.session['is_login']='true' request.session['username']=username #登录成功就将url重定向到后台的url return redirect('/backend/') #登录不成功或第一访问就停留在登录页面 return render(request,'login.html') def backend(request): print(request.session,"------cookie") print(request.COOKIES,'-------session') """ 这里必须用读取字典的get()方法把is_login的value缺省设置为False, 当用户访问backend这个url先尝试获取这个浏览器对应的session中的 is_login的值。如果对方登录成功的话,在login里就已经把is_login 的值修改为了True,反之这个值就是False的 """ is_login=request.session.get('is_login',False) #如果为真,就说明用户是正常登陆的 if is_login: #获取字典的内容并传入页面文件 cookie_content=request.COOKIES session_content=request.session username=request.session['username'] return render(request,'backend.html',locals()) else: """ 如果访问的时候没有携带正确的session, 就直接被重定向url回login页面 """ return redirect('/login/') def log_out(request): """ 直接通过request.session['is_login']回去返回的时候, 如果is_login对应的value值不存在会导致程序异常。所以 需要做异常处理 """ try: #删除is_login对应的value值 del request.session['is_login'] # OR---->request.session.flush() # 删除django-session表中的对应一行记录 except KeyError: pass #点击注销之后,直接重定向回登录页面 return redirect('/login/')



template:



===================================login.html==================
<!DOCTYPE html>
<html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form action="/login/" method="post"> <p>用户名: <input type="text" name="user"></p> <p>密码: <input type="password" name="pwd"></p> <p><input type="submit"></p> </form> </body> </html> ===================================backend.html================== <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>hello {{ username }}</h3> <a href="/logout/">注销</a> </body> </html>



4、session存储的相关配置

(1)数据库配置(默认):

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
 
 
 
    
 
 
 
 
  a. 配置 settings.py 
 
 
 
 
    
 
 
 
 
   
  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,默认修改之后才保存(默认)



2)缓存配置 

a. 配置 settings.py
 
 
 
    
 
 
 
 
   
  SESSION_ENGINE  
  = 
  'django.contrib.sessions.backends.cache'   
  # 引擎 
 
 
 
 
   
  SESSION_CACHE_ALIAS  
  = 
  'default'                             
  # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置 
 
 
 
 
    
 
 
 
 
    
 
 
 
 
   
  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,默认修改之后才保存



(3)文件配置

a. 配置 settings.py
 
 
 
    
 
 
 
 
   
  SESSION_ENGINE  
  = 
  'django.contrib.sessions.backends.file'     
  # 引擎 
 
 
 
 
   
  SESSION_FILE_PATH  
  = 
  None                                     
  # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()         
 
 
 
 
   
  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,默认修改之后才保存



用户认证 

auth模块



from            django.contrib            import            auth



django.contrib.auth中提供了许多方法,这里主要介绍其中的三个:

1 、authenticate()   

提供了用户认证,即验证用户名以及密码是否正确,一般需要username  password两个关键字参数

如果认证信息有效,会返回一个  User  对象。authenticate()会在User 对象上设置一个属性标识那种认证后端认证了该用户,且该信息在后面的登录过程中是需要的。当我们试图登陆一个从数据库中直接取出来不经过authenticate()的User对象会报错的!!



user            =           authenticate(username           =           'someone'           ,password           =           'somepassword'           )



2 、login(HttpRequest, user)  

该函数接受一个HttpRequest对象,以及一个认证了的User对象

此函数使用django的session框架给某个已认证的用户附加上session id等信息。


from            django.contrib.auth            import            authenticate, login          


                      


           def            my_view(request):          


                      username            =            request.POST[           'username'           ]          


                      password            =            request.POST[           'password'           ]          


                      user            =            authenticate(username           =           username, password           =           password)          


                      if            user            is            not            None           :          


                      login(request, user)          


                      # Redirect to a success page.          


                      ...          


                      else           :          


                      # Return an 'invalid login' error message.          


                      ...



3 、logout(request) 注销用户  



from            django.contrib.auth            import            logout          


                      


           def            logout_view(request):          


                      logout(request)          


                      # Redirect to a success page.



该函数接受一个HttpRequest对象,无返回值。当调用该函数时,当前请求的session信息会全部清除。该用户即使没有登录,使用该函数也不会报错。

4 、user对象的 is_authenticated()

要求:

1  用户登陆后才能访问某些页面,

2  如果用户没有登录就访问该页面的话直接跳到登录页面

3  用户在跳转的登陆界面中完成登陆后,自动访问跳转到之前访问的地址

方法1:



def            my_view(request):          


                      if            not            request.user.is_authenticated():          


                      return            redirect(           '%s?next=%s'            %            (settings.LOGIN_URL, request.path))



方法2:

django已经为我们设计好了一个用于此种情况的装饰器:login_requierd()



from            django.contrib.auth.decorators            import           login_required          


                      


           @login_required          


           def            my_view(request):          


                      ...



若用户没有登录,则会跳转到django默认的 登录URL '/accounts/login/ ' (这个值可以在settings文件中通过LOGIN_URL进行修改)。并传递  当前访问url的绝对路径 (登陆成功后,会重定向到该路径)。

User对象

User 对象属性:username, password(必填项)password用哈希算法保存到数据库

is_staff : 用户是否拥有网站的管理权限.

is_active : 是否允许用户登录, 设置为``False``,可以不用删除用户来禁止 用户登录

 

2.1 、is_authenticated()

如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。 这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,如果true则可以向前台展示request.user.name

2.2 、创建用户

使用 create_user 辅助函数创建用户:



from            django.contrib.auth.models            import            User          


           user            =           User.objects.create_user(username           =           '           ',password='           ',email='           ')



2.3 、check_password(passwd)



用户需要修改密码的时候 首先要让他输入原来的密码 ,如果给定的字符串通过了密码检查,返回            True



2.4 、修改密码

使用 set_password() 来修改密码



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


           user.set_password(password           =           '')          


           user.save 



2.5 、简单示例

注册:



def           sign_up(request):         


                    


                    state           =           None         


                    if           request.method           =          =           'POST'          :         


                    


                    password           =           request.POST.get(          'password'          , '')         


                    repeat_password           =          request.POST.get(          'repeat_password'          , '')         


                    email          =          request.POST.get(          'email'          , '')         


                    username           =           request.POST.get(          'username'          , '')         


                    if           User.objects.          filter          (username          =          username):         


                    state           =           'user_exist'         


                    else          :         


                    new_user           =          User.objects.create_user(username          =          username, password          =          password,email          =          email)         


                    new_user.save()         


                    


                    return           redirect(          '/book/'          )         


                    content           =           {         


                    'state'          : state,         


                    'user'          :           None          ,         


                    }         


                    return           render(request,           'sign_up.html'          , content)  



修改密码:

@login_required
 
 
 
  def  
  set_password(request): 
 
 
 
 
   
  user  
  =  
  request.user 
 
 
 
 
   
  state  
  =  
  None 
 
 
 
 
   
  if  
  request.method  
  = 
  =  
  'POST' 
  : 
 
 
 
 
   
  old_password  
  =  
  request.POST.get( 
  'old_password' 
  , '') 
 
 
 
 
   
  new_password  
  =  
  request.POST.get( 
  'new_password' 
  , '') 
 
 
 
 
   
  repeat_password  
  = 
  request.POST.get( 
  'repeat_password' 
  , '') 
 
 
 
 
   
  if  
  user.check_password(old_password): 
 
 
 
 
   
  if  
  not  
  new_password: 
 
 
 
 
   
  state  
  =  
  'empty' 
 
 
 
 
   
  elif  
  new_password ! 
  =  
  repeat_password: 
 
 
 
 
   
  state  
  =  
  'repeat_error' 
 
 
 
 
   
  else 
  : 
 
 
 
 
   
  user.set_password(new_password) 
 
 
 
 
   
  user.save() 
 
 
 
 
   
  return  
  redirect( 
  "/log_in/" 
  ) 
 
 
 
 
   
  else 
  : 
 
 
 
 
   
  state  
  =  
  'password_error' 
 
 
 
 
   
  content  
  =  
  { 
 
 
 
 
   
  'user' 
  : user, 
 
 
 
 
   
  'state' 
  : state, 
 
 
 
 
   
  } 
 
 
 
 
   
  return  
  render(request,  
  'set_password.html' 
  , content)



构建一个表单

假设你想在你的网站上创建一个简单的表单,以获得用户的名字。你需要类似这样的模板:
<form action="/your-name/" method="post">
 
 
 
   
  <label  
  for 
  = 
  "your_name" 
  >Your  
  name 
  : </label> 
 
 
 
 
   
  <input id= 
  "your_name"  
  type= 
  "text"  
  name 
  = 
  "your_name" 
  > 
 
 
 
 
   
  <input type= 
  "submit"  
  value= 
  "OK" 
  > 
 
 
 
 
  </form>



这是一个非常简单的表单。实际应用中,一个表单可能包含几十上百个字段,其中大部分需要预填充,而且我们预料到用户将来回编辑-提交几次才能完成操作。

我们可能需要在表单提交之前,在浏览器端作一些验证。我们可能想使用非常复杂的字段,以允许用户做类似从日历中挑选日期这样的事情,等等。

这个时候,让Django 来为我们完成大部分工作是很容易的。

so,两个突出优点:

    1 form表单提交时,数据出现错误,返回的页面中仍可以保留之前输入的数据。

    2 方便地限制字段条件



在Django 中构建一个表单

Form 类

我们已经计划好了我们的 HTML 表单应该呈现的样子。在Django 中,我们的起始点是这里:

#forms.py
 
 

     
 
 
 
 
  from  
  django import forms 
 
 
 

     
 
 
 
 
  class NameForm(forms.Form): 
 
 
 
 
   
  your_name = forms.CharField(label= 
  'Your name' 
  , max_length=100)


 它定义一个Form 类,只带有一个字段(your_name)。

字段允许的最大长度通过max_length 定义。它完成两件事情。首先,它在HTML 的<input> 上放置一个maxlength="100"(这样浏览器将在第一时间阻止用户输入多于这个数目的字符)。它还意味着当Django 收到浏览器发送过来的表单时,它将验证数据的长度。

Form 的实例具有一个is_valid() 方法,它为所有的字段运行验证的程序。当调用这个方法时,如果所有的字段都包含合法的数据,它将:

  • 返回True
  • 将表单的数据放到cleaned_data属性中。

完整的表单,第一次渲染时,看上去将像:

<label for="your_name">Your name: </label>
 
 
 
  <input id= 
  "your_name"  
  type= 
  "text"  
  name 
  = 
  "your_name" 
  maxlength= 
  "100" 
  >

 注意它不包含 <form> 标签和提交按钮。我们必须自己在模板中提供它们。

视图

发送给Django 网站的表单数据通过一个视图处理,一般和发布这个表单的是同一个视图。这允许我们重用一些相同的逻辑。

当处理表单时,我们需要在视图中实例化它:



#views.py

from django.shortcuts import render
from django.http import HttpResponseRedirect

from .forms import NameForm

def get_name(request):
    # if this is a POST request we need to process the form data
    if request.method == 'POST':
        # create a form instance and populate it with data from the request:
        form = NameForm(request.POST)
        # check whether it's valid:
        if form.is_valid():
            # process the data in form.cleaned_data as required
            # ...
            # redirect to a new URL:
            return HttpResponseRedirect('/thanks/')

    # if a GET (or any other method) we'll create a blank form
    else:
        form = NameForm()

    return render(request, 'name.html', {'form': form})


如果访问视图的是一个GET 请求,它将创建一个空的表单实例并将它放置到要渲染的模板的上下文中。这是我们在第一个访问该URL 时预期发生的情况。

如果表单的提交使用POST 请求,那么视图将再次创建一个表单实例并使用请求中的数据填充它:form = NameForm(request.POST)。这叫做”绑定数据至表单“(它现在是一个绑定的表单)。

我们调用表单的is_valid()方法;如果它不为True,我们将带着这个表单返回到模板。这时表单不再为空(未绑定),所以HTML 表单将用之前提交的数据填充,然后可以根据要求编辑并改正它。

如果is_valid()True,我们将能够在cleaned_data 属性中找到所有合法的表单数据。在发送HTTP 重定向给浏览器告诉它下一步的去向之前,我们可以用这个数据来更新数据库或者做其它处理。

模板

我们不需要在name.html 模板中做很多工作。最简单的例子是:

<form action="/your-name/" method="post">
 
 
 
   
  {% csrf_token %} 
 
 
 
 
   
  {{ form }} 
 
 
 
 
   
  <input type= 
  "submit"  
  value= 
  "Submit"  
  /> 
 
 
 
 
  </form>


根据{{ form }},所有的表单字段和它们的属性将通过Django 的模板语言拆分成HTML 标记 。

注:Django 原生支持一个简单易用的跨站请求伪造的防护。当提交一个启用CSRF 防护的POST 表单时,你必须使用上面例子中的csrf_token 模板标签。

现在我们有了一个可以工作的网页表单,它通过Django Form 描述、通过视图处理并渲染成一个HTML <form>

 

Django Form 类详解

绑定的和未绑定的表单实例

绑定的和未绑定的表单 之间的区别非常重要:

  • 未绑定的表单没有关联的数据。当渲染给用户时,它将为空或包含默认的值。
  • 绑定的表单具有提交的数据,因此可以用来检验数据是否合法。如果渲染一个不合法的绑定的表单,它将包含内联的错误信息,告诉用户如何纠正数据。

字段详解

考虑一个比上面的迷你示例更有用的一个表单,我们完成一个更加有用的注册表单:



#forms.py

from django import forms

class RegisterForm(forms.Form):
    username = forms.CharField(max_length=100,
                               error_messages={"min_length":"最短为5个字符","required":"该字段不能为空"},
                               )
    password = forms.CharField(max_length=100,
                               widget=widgets.PasswordInput(attrs={"placeholder":"password"})
                                )

    telephone=forms.IntegerField(
        error_messages={
            "invalid":"格式错误"
        }

                                )


    gender=forms.CharField(
          initial=2,
          widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
             )

    email = forms.EmailField()
    is_married = forms.BooleanField(required=False)



Widgets

每个表单字段都有一个对应的Widget 类,它对应一个HTML 表单Widget,例如<input type="text">

在大部分情况下,字段都具有一个合理的默认Widget。例如,默认情况下,CharField 具有一个TextInput Widget,它在HTML 中生成一个<input type="text">

字段的数据

不管表单提交的是什么数据,一旦通过调用is_valid() 成功验证(is_valid() 返回True),验证后的表单数据将位于form.cleaned_data 字典中。这些数据已经为你转换好为Python 的类型。

注:此时,你依然可以从request.POST 中直接访问到未验证的数据,但是访问验证后的数据更好一些。

在上面的联系表单示例中,is_married将是一个布尔值。类似地,IntegerField 和FloatField 字段分别将值转换为Python 的int 和float

 

使用表单模板

你需要做的就是将表单实例放进模板的上下文。如果你的表单在Context 中叫做form,那么{{ form }}将正确地渲染它的<label> 和 <input>元素。

表单渲染的选项

对于<label>/<input> 对,还有几个输出选项:

  • {{ form.as_table }} 以表格的形式将它们渲染在<tr> 标签中
  • {{ form.as_p }} 将它们渲染在<p> 标签中
  • {{ form.as_ul }} 将它们渲染在<li> 标签中

注意,你必须自己提供<table> 或<ul> 元素。

{{ form.as_p }}会渲染如下:

<form action="">
 
 
 
   
  < 
  p 
  > 
 
 
 
 
   
  < 
  label  
  for="id_username">Username:</ 
  label 
  > 
 
 
 
 
   
  < 
  input  
  id="id_username" maxlength="100" name="username" type="text" required=""> 
 
 
 
 
   
  </ 
  p 
  > 
 
 
 

     
 
 
 

     
 
 
 
 
   
  < 
  p 
  > 
 
 
 
 
   
  < 
  label  
  for="id_password">Password:</ 
  label 
  > 
 
 
 
 
   
  < 
  input  
  id="id_password" maxlength="100" name="password" placeholder="password" type="password" required=""> 
 
 
 
 
   
  </ 
  p 
  > 
 
 
 

     
 
 
 

     
 
 
 
 
   
  < 
  p 
  > 
 
 
 
 
   
  < 
  label  
  for="id_telephone">Telephone:</ 
  label 
  > < 
  input  
  id="id_telephone" name="telephone" type="number" required=""> 
 
 
 
 
   
  </ 
  p 
  > 
 
 
 

     
 
 
 

     
 
 
 
 
   
  < 
  p 
  > 
 
 
 
 
   
  < 
  label  
  for="id_email">Email:</ 
  label 
  > < 
  input 
  id="id_email" name="email" type="email" required=""> 
 
 
 
 
   
  </ 
  p 
  > 
 
 
 

     
 
 
 

     
 
 
 
 
   
  < 
  p 
  > 
 
 
 
 
   
  < 
  label  
  for="id_is_married">Is married:</ 
  label 
  > < 
  input  
  id="id_is_married" name="is_married" type="checkbox"> 
 
 
 
 
   
  </ 
  p 
  > 
 
 
 

     
 
 
 

     
 
 
 
 
   
  < 
  input  
  type="submit" value="注册"> 
 
 
 
 
  </ 
  form 
  >



手工渲染字段

我们没有必要非要让Django 来分拆表单的字段;如果我们喜欢,我们可以手工来做(例如,这样允许重新对字段排序)。每个字段都是表单的一个属性,可以使用{{ form.name_of_field }} 访问,并将在Django 模板中正确地渲染。例如:

<div class="fieldWrapper">
 
 
 
   
  {{ form.Username.errors }} 
 
 
 
 
   
  {{ form.Username.label_tag }} 
 
 
 
 
   
  {{ form.Username }} 
 
 
 
 
  </ 
  div 
  >



渲染表单的错误信息

1、

registerForm=RegisterForm(request.POST)
 
 
 
  print(type(registerForm.errors))                      #< 
  class  
  'django.forms.utils.ErrorDict'> 
 
 
 
 
  print(type(registerForm.errors["username"]))          #< 
  class  
  'django.forms.utils.ErrorList'>



2、

使用{{ form.name_of_field.errors }} 显示表单错误的一个清单,并渲染成一个ul。看上去可能像:

<ul class="errorlist">
 
 
 
   
  < 
  li 
  >Sender is required.</ 
  li 
  > 
 
 
 
 
  </ 
  ul 
  >



form组件的钩子


def foo(request):


    if request.method=="POST":

        regForm=RegForm(request.POST)

        if regForm.is_valid():
            pass
            # 可用数据: regForm.cleaned_data,
            # 将数据插入数据库表中


        else:
            pass
            # 可用数据: regForm.errors
            # 可以利用模板渲染讲errors嵌套到页面中返回
            # 也可以打包到一个字典中,用于ajax返回

    else:
        regForm=RegForm()
    return render(request,"register.html",{"regForm":regForm})

    

    '''
    实例化时:

        self.fields={
            "username":"字段规则对象",
            "password":"字段规则对象",

        }


    is_valid时:

        self._errors = {}
        self.cleaned_data = {}


        #局部钩子:

        for name, field in self.fields.items():
              try:

                    value = field.clean(value)
                    self.cleaned_data[name] = value
                    if hasattr(self, 'clean_%s' % name):
                        value = getattr(self, 'clean_%s' % name)()
                        self.cleaned_data[name] = value
              except ValidationError as e:
                    self.add_error(name, e)

        # 全局钩子:

        self.clean()     # def self.clean():return self.cleaned_data

        return  not self.errors    # True或者False


    '''


form组件补充

1、Django内置字段如下:



Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='', 帮助信息(在标签旁边显示) error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'} show_hidden_initial=False, 是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直) validators=[], 自定义验证规则 localize=False, 是否支持本地化 disabled=False, 是否可以编辑 label_suffix=None Label内容后缀 CharField(Field) max_length=None, 最大长度 min_length=None, 最小长度 strip=True 是否移除用户输入空白 IntegerField(Field) max_value=None, 最大值 min_value=None, 最小值 FloatField(IntegerField) ... DecimalField(IntegerField) max_value=None, 最大值 min_value=None, 最小值 max_digits=None, 总长度 decimal_places=None, 小数位长度 BaseTemporalField(Field) input_formats=None 时间格式化 DateField(BaseTemporalField) 格式:2015-09-01 TimeField(BaseTemporalField) 格式:11:12 DateTimeField(BaseTemporalField)格式:2015-09-01 11:12 DurationField(Field) 时间间隔:%d %H:%M:%S.%f ... RegexField(CharField) regex, 自定制正则表达式 max_length=None, 最大长度 min_length=None, 最小长度 error_message=None, 忽略,错误信息使用 error_messages={'invalid': '...'} EmailField(CharField) ... FileField(Field) allow_empty_file=False 是否允许空文件 ImageField(FileField) ... 注:需要PIL模块,pip3 install Pillow 以上两个字典使用时,需要注意两点: - form表单中 enctype="multipart/form-data" - view函数中 obj = MyForm(request.POST, request.FILES) URLField(Field) ... BooleanField(Field) ... NullBooleanField(BooleanField) ... ChoiceField(Field) ... choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),) required=True, 是否必填 widget=None, 插件,默认select插件 label=None, Label内容 initial=None, 初始值 help_text='', 帮助提示 ModelChoiceField(ChoiceField) ... django.forms.models.ModelChoiceField queryset, # 查询数据库中的数据 empty_label="---------", # 默认空显示内容 to_field_name=None, # HTML中value的值对应的字段 limit_choices_to=None # ModelForm中对queryset二次筛选  ModelMultipleChoiceField(ModelChoiceField) ... django.forms.models.ModelMultipleChoiceField TypedChoiceField(ChoiceField) coerce = lambda val: val 对选中的值进行一次转换 empty_value= '' 空值的默认值 MultipleChoiceField(ChoiceField) ... TypedMultipleChoiceField(MultipleChoiceField) coerce = lambda val: val 对选中的每一个值进行一次转换 empty_value= '' 空值的默认值 ComboField(Field) fields=() 使用多个验证,如下:即验证最大长度20,又验证邮箱格式 fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),]) MultiValueField(Field) PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用 SplitDateTimeField(MultiValueField) input_date_formats=None, 格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y'] input_time_formats=None 格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M'] FilePathField(ChoiceField) 文件选项,目录下文件显示在页面中 path, 文件夹路径 match=None, 正则匹配 recursive=False, 递归下面的文件夹 allow_files=True, 允许文件 allow_folders=False, 允许文件夹 required=True, widget=None, label=None, initial=None, help_text='' GenericIPAddressField protocol='both', both,ipv4,ipv6支持的IP格式 unpack_ipv4=False 解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用 SlugField(CharField) 数字,字母,下划线,减号(连字符) ... UUIDField(CharField) uuid类型 ...



2、Django内置插件:



TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget



3、常用选择插件:



# 单radio,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单radio,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.RadioSelect
# )
 
# 单select,值为字符串
# user = fields.CharField(
#     initial=2,
#     widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
# )
 
# 单select,值为字符串
# user = fields.ChoiceField(
#     choices=((1, '上海'), (2, '北京'),),
#     initial=2,
#     widget=widgets.Select
# )
 
# 多选select,值为列表
# user = fields.MultipleChoiceField(
#     choices=((1,'上海'),(2,'北京'),),
#     initial=[1,],
#     widget=widgets.SelectMultiple
# )
 
 
# 单checkbox
# user = fields.CharField(
#     widget=widgets.CheckboxInput()
# )
 
 
# 多选checkbox,值为列表
# user = fields.MultipleChoiceField(
#     initial=[2, ],
#     choices=((1, '上海'), (2, '北京'),),
#     widget=widgets.CheckboxSelectMultiple
# )