Django--分页器(paginator)Django的用户认证Django的FORM表单
Posted 始怡
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django--分页器(paginator)Django的用户认证Django的FORM表单相关的知识,希望对你有一定的参考价值。
分页器(paginator)
>>> from django.core.paginator import Paginator >>> objects = [\'john\', \'paul\', \'george\', \'ringo\'] >>> p = Paginator(objects, 2) >>> p.count #数据总数 4 >>> p.num_pages #总页数 2 >>> type(p.page_range) # `<type \'rangeiterator\'>` in Python 2. <class \'range_iterator\'> >>> p.page_range #页码的列表 range(1, 3) # =========[1,2] >>> page1 = p.page(1) #第1页的page对象 >>> page1 <Page 1 of 2> >>> page1.object_list #第1页的数据 [\'john\', \'paul\'] >>> page2 = p.page(2) >>> page2.object_list #第2页的数据 [\'george\', \'ringo\'] >>> page2.has_next() #是否有下一页 False >>> page2.has_previous() #是否有上一页 True >>> page2.has_other_pages() #是否有其他页 True >>> page2.next_page_number() #下一页的页码 Traceback (most recent call last): ... EmptyPage: That page contains no results >>> page2.previous_page_number() #上一页的页码 1 >>> page2.start_index() # 本页第一条记录的序数(从1开始) 3 >>> page2.end_index() # 本页最后录一条记录的序数(从1开始) 4 >>> p.page(0) #错误的页,抛出异常 Traceback (most recent call last): ... EmptyPage: That page number is less than 1 >>> p.page(3) #错误的页,抛出异常 Traceback (most recent call last): ... EmptyPage: That page contains no results
另一种错误:
PageNotAnInteger at /index/
That page number is not an integer
实现一个分页效果:
模板:
<ul>
{% for book in book_list %}
<li>{{ book.title }} {{ book.price }}</li>
{% endfor %} </ul>
{# 分页器#} <ul class="pagination"> {% if book_list.has_previous %} <li><a href="/index/?page={{ book_list.previous_page_number }}">上一页</a></li> {% else %} <li class="disabled"><a href="#">上一页</a></li> {% endif %} {% for num in p.page_range %} <li><a href="/index/?page={{ num }}">{{ num }}</a></li> {% endfor %} {% if book_list.has_next %} <li><a href="/index/?page={{ book_list.next_page_number }}">下一页</a></li> {% else %} <li class="disabled"><a href="#">下一页</a></li> {% endif %} </ul>
视图: 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) 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",locals())
Django的用户认证
认证登录
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:login_required函数
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``,可以不用删除用户来禁止 用户登录
User 对象方法
1 is_authenticated()
如果是真正的 User 对象,返回值恒为 True 。 用于检查用户是否已经通过了认证。
通过认证并不意味着用户拥有任何权限,甚至也不检查该用户是否处于激活状态,这只是表明用户成功的通过了认证。
这个方法很重要, 在后台用request.user.is_authenticated()判断用户是否已经登录,如果true则可以向前台展示request.user.name
2 创建用户
使用 create_user 辅助函数创建用户:
from django.contrib.auth.models import User user = User.objects.create_user(username=\'\',password=\'\',email=\'\')
3 修改密码set_password(passwd)
这个方法是用来更改密码的,使用步骤:
user=User.objects.get(username=\'\') user.set_password(passeord=\'\') user.save
4 check_password(passwd)
用户需要修改密码的时候 首先要让他输入原来的密码 ,如果给定的字符串通过了密码检查,返回 True
示例:注册
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\', \'\') if password == \'\' or repeat_password == \'\': state = \'empty\' elif password != repeat_password: state = \'repeat_error\' else: 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() new_my_user = MyUser(user=new_user, telephone=request.POST.get(\'telephone\', \'\')) new_my_user.save() return redirect(\'/book/\') content = { \'state\': state, \'user\': None, } return render(request, \'book/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, \'book/set_password.html\', content)
FORM
Django表单系统中,所有的表单类都作为django.forms.Form的子类创建,包括ModelForm
关于django的表单系统,主要分两种
基于django.forms.Form:所有表单类的父类
基于django.forms.ModelForm:可以和模型类绑定的Form
需求:向数据库的Info表中添加一些新的个人信息
使用Form的情况
#-----------------------------------------urls.py #----------------------------------------- from django.conf.urls import url from django.contrib import admin from app01 import views urlpatterns = [ url(r\'^admin/\', admin.site.urls), url(r\'^add_info/\', views.add_info,name=\'add_info\'), ] #-----------------------------------------models.py #----------------------------------------- from django.db import models # Create your models here. class Info(models.Model): name = models.CharField(max_length=64) sex = models.CharField(max_length=64) birthday = models.CharField(max_length=64) age=models.CharField(max_length=64) qualification=models.CharField(max_length=64) job=models.CharField(max_length=64) email=models.CharField(max_length=64,default=\'\') class Hobby(models.Model): item=models.CharField(max_length=64) #-----------------------------------------form.py #----------------------------------------- from django import forms from app01 import models from django.core.exceptions import ValidationError class Info_form(forms.Form): def validate_name(value): try: models.Info.objects.get(name=value) raise ValidationError(\'%s 的信息已经存在!\'%value) except models.Info.DoesNotExist: pass sex_choice=((0,\'男\'), (1,\'女\'))#select的数据可以像这样写,也可以在另外一张表中动态去拿 name = forms.CharField(validators=[validate_name],label=\'姓名\',error_messages={\'required\':\'必填\'}) age = forms.CharField(label=\'年龄\',error_messages={\'required\':\'必填\'}) # sex = forms.CharField(label=\'性别\',error_messages={\'required\':\'必填\',},) sex=forms.IntegerField(widget=forms.widgets.Select(choices=sex_choice, attrs={\'class\':\'setform2\'} )) birthday = forms.CharField(label=\'生日\',error_messages={\'required\':\'必填\'}) qualification = forms.CharField(label=\'学历\',error_messages={\'required\':\'必填\'}, widget=forms.TextInput(attrs={\'class\':\'formset\', \'placeholder\':\'本科\' } )) email=forms.EmailField(max_length=100,min_length=10,,error_messages={\'invalid\': u\'请填写有效邮箱地址。\'}) job = forms.CharField(label=\'工作\',error_messages={\'required\':\'必填\'}) def __init__(self,*args,**kwargs): super(Info_form,self).__init__(*args,**kwargs) self.fields[\'hobby\']=forms.CharField(widget=forms.widgets.Select(choices=models.Hobby.objects.values_list(\'id\',\'item\'))) #-------------------------------------------------------views.py #------------------------------------------------------- from django.shortcuts import render,HttpResponse # Create your views here. from app01.models import * from app01.forms import * def add_info(req): if req.method==\'POST\': Info_form_obj=Info_form(req.POST) if Info_form_obj.is_valid(): Info.objects.create(name=Info_form_obj.cleaned_data[\'name\'], age=Info_form_obj.cleaned_data[\'age\'], sex=Info_form_obj.cleaned_data[\'sex\'], birthday=Info_form_obj.cleaned_data[\'birthday\'], qualification=Info_form_obj.cleaned_data[\'qualification\'], job=Info_form_obj.cleaned_data[\'job\'] ) return HttpResponse(\'添加成功!\') else: error_obj=Info_form_obj.errors print(\'***************\') print(type(error_obj))#<class \'django.forms.utils.ErrorDict\'> print(error_obj[\'name\'][0])#必填 print(error_obj.get(\'age\'))#<ul class="errorlist"><li>必填</li></ul> return render(req,\'add_info.html\',{\'form_obj\':Info_form_obj,\'error_obj\':error_obj}) Info_form_obj=Info_form() return render(req,\'add_info.html\',{\'form_obj\':Info_form_obj}) #------------------------------------------------------add_info.html #------------------------------------------------------- <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>添加个人信息</title> <style> .formset{ color: rebeccapurple; border: dashed cadetblue; } </style> </head> <body> <form action="{% url \'add_info\' %}" method="post"> <p>姓名{{ form_obj.name }}{{ error_obj.name.0 }}</p> <p>年龄{{ form_obj.age }}{{ error_obj.age.0 }}</p> <p>生日{{ form_obj.birthday }}{{ error_obj.birthday.0 }}</p> <p>工作{{ form_obj.job }}<span>{{ error_obj.job }}</span></p> <p>学历{{ form_obj.qualification }}<span>{{ error_obj.qualification }}</span></p> <p>性别{{ form_obj.sex }}<span>{{ error_obj.sex }}</span></p> <p>邮箱{{ form_obj.email }}<span>{{ error_obj.email }}</span></p> <p>爱好{{ form_obj.hobby }}<span>{{ error_obj.hobby }}</span></p> {# {{ form_obj.as_p }}#} <input type="submit" value="提交"><br> {% csrf_token %} </form> </body> </html>
DjangoForm补充:
问题1: 注册页面输入为空,报错:keyError:找不到password
def clean(self): print("---",self.cleaned_data) # if self.cleaned_data["password"]==self.cleaned_data["repeat_password"]: # 报错原因:self.cleaned_data是干净数据,如果页面没有输入内容,则self.cleaned_data没有password。 改如下: if self.cleaned_data.get("password")==self.cleaned_data.get("repeat_password"): return self.cleaned_data else: raise ValidationError("两次密码不一致")
问题2: 为什么要用全局clean()
按子段顺序一一校验,即校验到username时,你无法使用self.cleaned_data.get("password")。
而局部钩子使用完,到全局时,已经可以使用所有的self.cleaned_data
总结Django的Form表单的钩子:
钩子解决的是自定制校验规则
局部钩子:校验单个字段,例如:用户名最短5个字符,最长12个字符;密码必须大于8位,验证码必须正确
全局钩子:校验信息涉及多个字段,例如:密码和重复密码必须一致
注意:
form表单类继承问题:
以上是关于Django--分页器(paginator)Django的用户认证Django的FORM表单的主要内容,如果未能解决你的问题,请参考以下文章