美文网首页
Django-Admin与auth认证

Django-Admin与auth认证

作者: Python野路子 | 来源:发表于2018-04-21 22:46 被阅读0次

    什么是 django自带的admin系统

    • Django 最强大的部分之一是自动生成的Admin 界面。它读取模型数据来提供一个强大的、生产环境就绪的界面,使内容提供者能立即用它向站点中添加内容。
    • 它可以快速的开发出一个后台管理界面

    如何开启admin系统

    1. 确保在settings.py中的INSTALLED_APPS安装了'django.contrib.admin'
    2. INSTALLED_APPS中添加了四个依赖的app
      django.contrib.auth
      django.contrib.contenttypes
      django.contrib.messages
      django.contrib.sessions
      image.png
    3. 在模板上下文中添加以下依赖
      django.contrib.auth.context_processors.authdjango.contrib.messages.context_processors.messages
      image.png
    4. 在中间件中添加以下依赖django.contrib.auth.middleware.AuthenticationMiddlewaredjango.contrib.messages.middleware.MessageMiddleware
      image.png
    5. 运行命令python manage.py createsuperuser创建一个超级用户,然后输入超级用户的用户名和密码。创建的用户是保存在auth_user表中
    6. 使用该命令创建的用户是一个超级管理员用户,它拥有所有的权限,需要妥善保管 image.png
    7. 如果没有通过migrate,需要先同步migrate
    8. 在浏览器中输入127.0.0.1:8000/admin/进入admin登录界面。输入刚刚创建的用户名和密码,进入admin管理界面。
    9. admin 界面默认是英文,如需要修改成中文,修改settings中的属性,

      ps: 控制这个语言展示的模块叫i18n,i18n实际就是国际化,就代表支持多种语言的功能 image.png
      界面效果图: image.png
      image.png

    自定义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显示名称:
      image.png
      所有跟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'
    
    image.png
    • 修改模型显示的名称:
      设置model中的元属性即可
     class Meta:
            verbose_name = u"班号"
            verbose_name_plural = u"班号列表"
    

    效果:

    image.png
    image.png
    注意:要有数据 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
    
    image.png
    • 修改展示的列表项,即模型中其他字段内容,可以在admin.py中用 list_display修改展示的列表项
    #admin.py
    @admin.register(Classesgrade)
    class ClassesgradeAuth(admin.ModelAdmin):
        list_display = ['name', 'create_time', 'update_time', 'number']
    
    image.png
    • 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']
    
    image.png
    注意: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页面的。
    
    image.png
    search_fields,在使用 Django admin 系统中的搜索时可能会出现“related Field has invalid lookup: icontains”错误,主要原因是外键查询是需要指定相应的字段的。外键不应该只是一个model,而该是另一个表的明确的一个字段。所以我们需要指定特定的字段 "本表外键字段__外键所在表需查询字段"。

    auth系统:

    1. auth系统是django内置一个的一个app,它是专门用于管理用户权限的一个组件;
    2. 创建一个用户: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'
    
    1. 后台管理系统中 image.png
    • 权限验证
    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模型:
    1. 所属包django.contrib.auth.models.Group
    2. 创建Group:必须传一个name参数进去。
    3. 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配置对应的权限

    学以致用
    1. 使用django的auth组件,完成登录、注册、注销页面;
    2. 使用auth组件的权限,添加一个主页,主页展示商品列表,并设置一个权限才能访问;
    3. 使用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效果:

    image.png
    注册成功效果: image.png
    登录页面sign_in.html效果:
    image.png
    登录成功,跳转到首页index.html
    image.png
    访问主页home.html
    image.png
    具有添加权限的页面:
    image.png
    添加商品addProduct.html,成功之后返回商品展示页面:
    image.png
    注销退出,返回登录界面:
    image.png
    找回密码resetpassword.html,成功之后返回登录界面:
    image.png
    • 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'注册成功,请返回<a href="/auth/login">登录</a>')
            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('添加商品成功<a href="/auth/home/"></a>')
    
            return HttpResponse('添加商品失败<a href="/auth/home/"></a>')
    
    • 页面html:
    #注册页面sign_up.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>注册界面</title>
    </head>
    <body>
    <div>
    <h1>注册</h1>
    <form action="/auth/register/" method="post">
        {% csrf_token %}
        用 户 名:<input type="text" name="userName" placeholder="用户名"/>
        登录密码:<input type="password" name="userPassword" placeholder="登录密码"/>
        确认密码:<input type="password" name="userConfirmPassword" placeholder="确认密码"/>
        邮    箱:<input type="email" name="userEmail" placeholder="邮箱"/>
        <input type="submit" value="注册"/>
    </form>
    </div>
       {{ form.errors }} <!--如果注册错误则显示对应的错误 -->
    </body>
    </html>
    
    #登录页面sign_in.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>登录界面</title>
    </head>
    <body>
       {{ message }}
    
    <h1>登录</h1>
    <form action="/auth/login/" method="post">
        {% csrf_token %}
        用 户 名:<input type="text" name="userName"/>
        登录密码:<input type="password" name="userPassword"/>
        <input type="submit" value="登录"/>
    </form>
    <a href="/auth/resetpassword/">找回密码</a>
    </div>
    </body>
    </html>
    
    #首页页面index.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
        <style>
            *{
                margin: 0;
                padding: 0;
            }
        </style>
    </head>
    <body>
    <div style="margin-top:20px;color: black;font-size: 20px;line-height: 20px;text-align: center;";>
        欢迎{{user.username}}&nbsp;&nbsp;{{user.email}}&nbsp;&nbsp;{{user.is_authenticated}}登录成功!
        <br/>
        <a href="/auth/home/">主页</a>
        <a href="/auth/logout/">退出</a>
    </div>
    </body>
    </html>
    
    #主页home.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>查看老师信息</title>
    </head>
    <body>
    <h2>{{user.username}}主页</h2>
    {% for product in products %}
    <p>
        名称:{{ product.name }}<br/>
        详细信息:{{product.detail}}<br/>
        价格:{{product.price}}<br/>
    </p>
    {% endfor %}
    {{ message }}
    {% if canAdd %} <!--判断有没有添加权限 -->
    <a href="/auth/addProduct/">添加商品</a>
    {% endif %}
    </body>
    </html>
    
    #添加商品addPruduct.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>添加商品</title>
    </head>
    <body>
    <form action="/auth/addProduct/" method="post">
        {% csrf_token %}
        名称:<input type="text" name="username"/>
        价格:<input type="text" name="price"/>
        详细信息: <textarea name="detail"></textarea>
        <input type="submit" value="添加">
    </form>
    </body>
    </html>
    
    #找回密码resetpassword.html
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>找回密码</title>
    </head>
    <body>
    <h1>找回密码</h1>
    <form action="/auth/resetpassword/" method="post">
        {% csrf_token %}
        用 户 名:<input type="text" name="userName"/>
        重置密码:<input type="password" name="userPassword"/>
        确认密码:<input type="password" name="userConfirmPassword"/>
        <input type="submit" value="确认"/>
    </form>
    </div>
    {{form.errors}}
    </body>
    </html>
    

    相关文章

      网友评论

          本文标题:Django-Admin与auth认证

          本文链接:https://www.haomeiwen.com/subject/tletkftx.html