什么是 django自带的admin系统
- Django 最强大的部分之一是自动生成的Admin 界面。它读取模型数据来提供一个强大的、生产环境就绪的界面,使内容提供者能立即用它向站点中添加内容。
- 它可以快速的开发出一个后台管理界面
如何开启admin系统
- 确保在
settings.py
中的INSTALLED_APPS
安装了'django.contrib.admin'
- 在
INSTALLED_APPS
中添加了四个依赖的app
,
django.contrib.auth
,
django.contrib.contenttypes
,
django.contrib.messages
,
django.contrib.sessions
。
- 在模板上下文中添加以下依赖
django.contrib.auth.context_processors.auth
,django.contrib.messages.context_processors.messages
- 在中间件中添加以下依赖
django.contrib.auth.middleware.AuthenticationMiddleware
,django.contrib.messages.middleware.MessageMiddleware
。
- 运行命令
python manage.py createsuperuser
创建一个超级用户,然后输入超级用户的用户名和密码。创建的用户是保存在auth_user表中 - 使用该命令创建的用户是一个超级管理员用户,它拥有所有的权限,需要妥善保管
- 如果没有通过migrate,需要先同步migrate
- 在浏览器中输入
127.0.0.1:8000/admin/
进入admin
登录界面。输入刚刚创建的用户名和密码,进入admin管理界面。 -
admin 界面默认是英文,如需要修改成中文,修改settings中的属性,
ps: 控制这个语言展示的模块叫i18n,i18n实际就是国际化,就代表支持多种语言的功能
界面效果图:
自定义admin:
- 把需要管理的模型添加到
admin
中:
首先要在INSTALLED_APPS
中添加对应的应用,然后在应用的admin.py
中注册,有2中方法注册,方法二常用
方法一:
class ArticleAdmin(admin.ModelAdmin):
pass
admin.site.register(Article, ArticleAdmin)
方法二:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib import admin
from .models import *
# Register your models here.
@admin.register(Classesnumber)
class ClassesnumberAuth(admin.ModelAdmin):
pass
- 修改app显示名称:
所有跟app相关的内容配置,可以实现一个Appconfig
类的子类来完成,django一般会默认在apps.py
中建立一个
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.apps import AppConfig
class TestappConfig(AppConfig):
name = 'TestApp'
- 然后在apps.py对应的子类中配置
verbose_name
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.apps import AppConfig
class TestappConfig(AppConfig):
name = 'TestApp'
verbose_name = u'练习项目'
- 我们只需要指定一下即可,需要管理的
__init__.py
中配置如下:
from .apps import *
default_app_config = 'TestApp.apps.TestappConfig'
- 修改模型显示的名称:
设置model中的元属性即可
class Meta:
verbose_name = u"班号"
verbose_name_plural = u"班号列表"
效果:
注意:要有数据 verbose_name才展示出来,否则显示的是复数形式。
- 修改模型列表的展示:
在models.py
中对应类添加一个__unicode__
方法(py3中使用的是__str__
),返回需要展示的字符串(注意需要返回字符串,否则Python将抛出一个TypeError 错误,并提示:”coercing to Unicode: need string or buffer, int found” ),如把return self.id
改为return str(self.s_id)
或者返回name
比如要展示班级名称:
#`models.py
def __unicode__(self):
return self.name
- 修改展示的列表项,即模型中其他字段内容,可以在admin.py中用
list_display
修改展示的列表项
#admin.py
@admin.register(Classesgrade)
class ClassesgradeAuth(admin.ModelAdmin):
list_display = ['name', 'create_time', 'update_time', 'number']
- Admin类管理
list_display
:可以修改展示的列表项
search_fields
:可以提供搜索的查找项
list_filter
:可以提供一个过滤的表
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib import admin
from .models import *
# Register your models here.
@admin.register(Classesnumber)
class ClassesnumberAuth(admin.ModelAdmin):
pass
@admin.register(Classesgrade)
class ClassesgradeAuth(admin.ModelAdmin):
list_display = ['id','name', 'create_time', 'update_time', 'number']
#提供搜索的查找项(模糊搜索),几个则是或or的关系
search_fields = ['id','name']
#提供一个过滤的表,如果多个,则且and的关系
list_filter = ['id','name']
注意:list_display不支持多对多的,需要处理下:/
#admin.py
@admin.register(Student)
class StudentAuth(admin.ModelAdmin):
#list_display不能显示多对多的
list_display = ('id', 'name', 'age', 'sex', 'classesno','teachers_list')
#然后自己定义个字段名来代替teacher在teachers_list中显示即可。因为待会我们要写一个同名方法来获取teacher的里的值。
def teachers_list(self,obj):
return [a.name for a in obj.teacher.all()] #获取老师所有对象,然后再迭代获取对应名称组成列表
teachers_list.short_description = u'老师'
# filter_horizontal = ['teacher']# filter_horizontal是用来编辑状态下的teacher页面的。
search_fields,在使用 Django admin 系统中的搜索时可能会出现“related Field has invalid lookup: icontains”错误,主要原因是外键查询是需要指定相应的字段的。外键不应该只是一个model,而该是另一个表的明确的一个字段。所以我们需要指定特定的字段 "本表外键字段__外键所在表需查询字段"。
更多操作:
参考文档:
https://docs.djangoproject.com/en/1.11/ref/contrib/admin/
https://yiyibooks.cn/xx/Django_1.11.6/ref/contrib/admin/index.html其它:
在admin操作后台的时候,如果选择多对多对象,需要ctrl+ 鼠标点击完全多选。
auth系统:
- auth系统是django内置一个的一个app,它是专门用于管理用户权限的一个组件;
- 创建一个用户:
from django.contrib.auth.models import User
,然后使用create_user
来创建一个用户。
from django.contrib.auth.models import User
User.objects.create_user(**kwargs)
- 验证用户
from django.contrib.auth import authenticate
#authenticate接受两个参数,用户名 username 和 密码 password ,并在密码对给出的用户名合法的情况下返回一个 User 对象,如果密码不合法。authenticate()返回None。
user = authenticate(username='john', password='secret')
if user is not None:
# 这个用户存在数据库中
else:
# 用户名或者密码错误
- 登录
from django.contrib.auth import authenticate, login
def post(self, request):
username = request.POST['username']
password = request.POST['password']
user = authenticate(username=username, password=password)
if user is not None:
#authenticate() 只是验证一个用户的证书而已。而要登录一个用户,使用 login() 。该函数接受一个 HttpRequest 对象和一个 User 对象作为参数并使用Django的会话( session )框架把用户的ID保存在该会话中。
login(request, user)
# 登录成功
else:
# 用户名或者密码错误
- 注销
from django.contrib.auth import logout
def get(self, request)
logout(request) # 当执行完logout,实际就是清除了session中的user信息
#它接受一个HttpRequest对象并且没有返回值,所以,因为没有返回值,需要返回一个页面。
- 登录验证
from django.contrib.auth.mixins import LoginRequiredMixin
class Show(LoginRequiredMixin, View):
login_url = "/account/login/" #如果没有登录成功,则跳转至内部定义的login_url,否则会跳转到`settings.LOGIN_URL`指定的URL中。即先找内部再找外部
#注意登录验证是用于一些只有登录了才能看的到的页面,但是可能存在一些直接输入url也可以看到这个页面,
#只不过没对应值而已,这样是不安全的,所以在进入这些页面前需要进行验证,以避免直接输入url的情况,
#如果验证已经登录成功的则进入对应页面,没有则通过使用LoginRequiredMixin来实现与login_required相同的行为,#如果没有登录成功,则跳转至内部定义的login_url,否则会跳转到`settings.LOGIN_URL`指定的URL中。即先找内部再找外部
- 修改密码,即找回密码
from django.contrib.auth.models import User
u = User.objects.get(username='john') #获取对象
u.set_password('new password') #保存可以用u.password = make_password(new password)
u.save() #保存
User模型常用属性和方法:
username
:用户名。
email
:邮箱。
groups
:多对多的组。
user_permissions
:多对多的用户权限。
is_staff
: 指明这个用户是否可以进入管理站点。
is_active
: 是否激活,判断该用户是否可用。
is_superuser
: 是否是超级用户。
last_login
: 上次登录时间。
date_joined
: 注册时间。
is_authenticated
: 是否验证通过了。
is_anonymous
:是否是匿名用户。
set_password(raw_password)
: 设置密码,传原生密码进去。
check_password(raw_password)
: 检查密码。
has_perm(perm)
: 判断用户是否有某个权限。
has_perms(perm_list)
: 判断用户是否有权限列表中的某个列表。
- Permission权限:
1.在模型中添加,需要控制权限的模型中添加权限,即通过这些权限,能做什么事情:
class Task(models.Model):
class Meta:
permissions = (
("view_task", "查看任务权限"),
("change_task_status", "修改任务权限"),
("close_task", "关闭任务权限"),
)
2.在代码中添加权限
from myapp.models import BlogPost
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.create(
codename='can_publish',
name='Can Publish Posts',
content_type=content_type, #必填。一个指向django_content_type数据库表,对于每一个Django模型,在这个表里面都有一个记录对应。
)
一般在模型中增加,毕竟只有那么一次
- 给用户赋相应权限
1.代码中:
permission = Permission.objects.get(name=u'查看商品信息')#对应auth_permission表中
myuser.user_permissions.set([permission_list]) # 设置一个权限列表
myuser.user_permissions.add(permission, permission, ...) # 添加一个权限
myuser.user_permissions.remove(permission, permission, ...) # 删除多个权限
myuser.user_permissions.clear() # 清理所有权限
# 以上操作都需要save,因为他们都是一个数据库操作
myuser.has_perm('foo.add_bar'
- 后台管理系统中
- 权限验证
from django.contrib.auth.mixins import PermissionRequiredMixin
class MyView(PermissionRequiredMixin, View):
# 单个权限
permission_required = 'polls.can_vote'
# 多个权限,且的关系
permission_required = ('polls.can_open', 'polls.can_edit')
- Group模型:
- 所属包
django.contrib.auth.models.Group
- 创建
Group
:必须传一个name
参数进去。 - Group`操作:
group.permissions.set([permission_list]) # 设置这个组包含的权限列表
group.permissions.add(permission, permission, ...) # 添加一个权限到这个组
group.permissions.remove(permission, permission, ...) # 从这个组中删除一个权限
group.permissions.clear() # 清理这个组的权限
myuser.groups.set([group_list]) # 设置一些组
myuser.groups.add(group, group, ...) # 添加某些组
myuser.groups.remove(group, group, ...) # 删除某些组
myuser.groups.clear() # 清理所有租
一般情况下,我们都不会手工添加对应的权限,都会通过models配置对应的权限
学以致用
- 使用django的auth组件,完成登录、注册、注销页面;
- 使用auth组件的权限,添加一个主页,主页展示商品列表,并设置一个权限才能访问;
- 使用admin组件,添加商品列表的数据;
- 需求分析
需要使用Django的auth组件,则不要单独建立user模型,使用自带的组件进行操作就可以了。 - 在
forms.py
建立注册表单类,其中名称,价格,商品详细信息:
# -*- coding: utf-8 -*-
from django import forms
from django.contrib.auth.models import User
class RegisterForm(forms.Form):
userName = forms.CharField(label=u'用户名',min_length = 3,max_length = 20)
userPassword = forms.CharField(label=u'登录密码',min_length= 6,max_length = 20,error_messages = {'min_length':u'密码至少6位','max_length':u'密码最长20位'})
userConfirmPassword = forms.CharField(label=u'确认密码',min_length = 6,max_length = 20,error_messages = {'min_length':u'密码至少6位','max_length':u'密码最长20位'})
userEmail = forms.EmailField(label=u'邮箱')
def clean_userName(self):
userName = self.cleaned_data['userName']
user = User.objects.filter(username = userName)
if user:
raise forms.ValidationError(u'用户名已存在')
return userName
def clean_userConfirmPassword(self):
userPassword = self.cleaned_data['userConfirmPassword']
userConfirmPassword = self.cleaned_data['userConfirmPassword']
if userPassword != userConfirmPassword:
raise forms.ValidationError(u'两次密码不一致')
return userPassword
class ResetPasswordForm(forms.Form):
userName = forms.CharField(label=u'用户名',min_length = 3,max_length = 20)
userPassword = forms.CharField(label=u'登录密码', min_length=6, max_length=20,error_messages={'min_length': u'密码至少6位', 'max_length': u'密码最长20位'})
userConfirmPassword = forms.CharField(label=u'确认密码',min_length = 6,max_length = 20,error_messages = {'min_length':u'密码至少6位','max_length':u'密码最长20位'})
def clean_userName(self):
userName = self.cleaned_data['userName']
user = User.objects.filter(username = userName)
print(user)
if not user:
raise forms.ValidationError(u'用户名不存在')
return userName
def clean_userConfirmPassword(self):
userPassword = self.cleaned_data['userPassword']
userConfirmPassword = self.cleaned_data['userConfirmPassword']
print(userPassword,userConfirmPassword)
if userPassword != userConfirmPassword:
raise forms.ValidationError(u'两次密码不一致')
return userPassword
注册页面sign_up.html
效果:
注册成功效果:
登录页面
sign_in.html
效果:
登录成功,跳转到首页
index.html
:
访问主页
home.html
:
具有添加权限的页面:
添加商品
addProduct.html
,成功之后返回商品展示页面:
注销退出,返回登录界面:
找回密码
resetpassword.html
,成功之后返回登录界面:
- urls.py:
# -*- coding:utf-8 -*-
from django.conf.urls import url,include
from auth_study import views
urlpatterns = [
url(r'^register/$', views.Register.as_view(),name='register'),
url(r'^login/$',views.Login.as_view(),name='login'),
url(r'^index/$',views.Index.as_view(),name='index'),
url(r'^logout/$',views.Logout.as_view(),name='logout'),
url(r'^resetpassword/$',views.ResetPassword.as_view(),name='resetpassword'),
url(r'^home/$', views.Home.as_view(), name='home'),
url(r'^addProduct/$', views.AddProduct.as_view(), name='addProduct')
]
- 视图views.py:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.shortcuts import render,redirect,reverse
from django.contrib.auth.models import User,Permission
from django.views import View
from .forms import *
from django.http import HttpResponse
from django.contrib.auth import authenticate,login,logout
from django.contrib.auth.mixins import LoginRequiredMixin,PermissionRequiredMixin
from .models import Product
import TestApp
from TestApp.models import *
# Create your views here.
#注册功能
class Register(View):
def get(self,request):
return render(request,'sign_up.html')
def post(self,request):
form = RegisterForm(request.POST)
print(form.is_bound)
if form.is_valid():
userName = form.cleaned_data['userName']
userPassword = form.cleaned_data['userPassword']
userConfirmPassword = form.cleaned_data['userConfirmPassword']
userEmail = form.cleaned_data['userEmail']
#create_user可以由Django自动将密码加密,而create还需要先将密码自己加密再给
user = User.objects.create_user(username=userName,email=userEmail,password=userPassword)
#给用户添加权限,多对多关系,用add添加
user.user_permissions.add(Permission.objects.get(codename='view_products'))
user.save() #需要save,因为他们都是一个数据库操作
return HttpResponse(u'注册成功,请返回登录')
else:
return render(request,'sign_up.html',locals())
#登录功能
class Login(View):
def get(self,request):
return render(request,'sign_in.html')
def post(self,request):
userName = request.POST.get('userName')
userPassword = request.POST.get('userPassword')
print(userName,userPassword)
#验证用户,它接受两个参数,用户名 username 和 密码 password,认证只有是否激活跟用户名密码。
user = authenticate(username = userName,password = userPassword)
#并在密码对给出的用户名合法的情况下返回一个 User 对象。 如果密码不合法,authenticate()返回None。
if user is not None:
if user.is_active:
#登录,向session中添加SESSION_KEY, 便于对用户进行跟踪:
login(request,user)
# 如果调用login方法以后,
# request对象就会激活user属性,这个属性不管登录或者未登录都是存在
return redirect(reverse('index'))
else:
message = u'该用户未激活'
else:
message = u'用户名或密码错误'
return render(request,'sign_in.html',locals())
class Index(LoginRequiredMixin,View): #登录验证,主要用于比如说直接输入地址情况。
# 如果需要指定单独的跳转,则该类中指定login_url属性
# 如果需要指定全局的,则在settings中指定LOGIN_URL属性
login_url = '/auth/login/'#没有登录则指定跳转
def get(self,request):
print(request.COOKIES)
return render(request, 'index.html', locals())
#注销功能
class Logout(View):
def get(self,request):
#注销用户,这个方法就会把我们的session跟cookie清理掉
logout(request)
message = u'注销成功'
return render(request,'sign_in.html',locals())
#重置密码
class ResetPassword(View):
def get(self,request):
return render(request,'resetpassword.html')
def post(self,request):
form = ResetPasswordForm(request.POST)
if form.is_valid():
username = form.cleaned_data['userName']
userPassword = form.cleaned_data['userPassword']
user = User.objects.get(username=username)
print(user)
if user:
user.set_password(userPassword)
user.save()
return render(request, 'sign_in.html', locals())
return render(request, 'resetpassword.html', locals())
#展示主页
class Home(PermissionRequiredMixin,View):
#单个权限
permission_required = 'auth_study.view_products'
#多个权限,要同时具有,且的关系,元祖或列表都可
# permission_required = ['auth_study.view_products','auth_study.update_products']
#上面个相当于全局的,只有满足了上面权限中的一个就可以进入下面的get了,否则就跳转到setting配置的LOGIN_URL去了
def get(self,request):
print('get...',request.user.user_permissions.all())
#has_perm(perm): 判断用户是否有某个权限。
#has_perms(perm_list): 判断用户是否有权限列表中的某个列表。
if request.user.has_perm('auth_study.view_products'):
products = Product.objects.all()
if request.user.has_perm('auth_study.add_products'):
canAdd = True #判断有没有添加权限,然后置为True,页面去判断是否显示相关
else:
message = '没有查看商品的权限'
return render(request,'home.html',locals())
#添加商品
class AddProduct(View):
def get(self,request):
return render(request,'addProduct.html')
def post(self,request):
print('post')
name = request.POST.get('username')
price = request.POST.get('price')
detail = request.POST.get('detail')
print(name,price,detail)
product = Product.objects.create(name = name,price = price,detail= detail)
if product:
return HttpResponse('添加商品成功')
return HttpResponse('添加商品失败')
- 页面html:
#注册页面sign_up.html
注册界面
注册
{{ form.errors }}
#登录页面sign_in.html
登录界面
{{ message }}
登录
找回密码