分页器(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表单类继承问题: