Django-bugMangerSystem-登录注册

本文介绍了一个基于Django框架的前后端未分离项目的注册登录流程,涵盖了前端页面、路由配置、中间件验证、视图处理及表单验证等方面,详细展示了从前端请求到后端处理的全过程。

注册登录流程(前后端未分离)

最近在跟着视频学习django,写个博客记录一下。
视频地址
https://www.bilibili.com/video/BV1uA411b77M?t=178

项目目录结构

bugManagerSys/
├── bugManagerSys
│   ├── __init__.py
│   ├── local_settings.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── db.sqlite3
├── list.txt
├── manage.py
├── templates
├── utils
│   ├── Calibri.ttf
│   ├── encrypt.py
│   ├── errorfile
│   │   └── web_error.py
│   ├── image.py
│   ├── Moderat Medium.otf
│   └── tencent
│       └── sms.py
└── web
    ├── admin.py
    ├── apps.py
    ├── form
    │   ├── account.py
    │   ├── bootstrap.py
    ├── __init__.py
    ├── middleware
    │   ├── __init__.py
    │   ├── middleware.py
    │   └── __pycache__
    │       ├── __init__.cpython-36.pyc
    │       └── middleware.cpython-36.pyc
    ├── migrations
    │   ├── 0001_initial.py
    │   ├── __init__.py
    │   └── __pycache__
    │       ├── 0001_initial.cpython-36.pyc
    │       └── __init__.cpython-36.pyc
    ├── models.py
    ├── __pycache__
    │   ├── admin.cpython-36.pyc
    │   ├── apps.cpython-36.pyc
    │   ├── __init__.cpython-36.pyc
    │   ├── models.cpython-36.pyc
    │   └── urls.cpython-36.pyc
    ├── static
    │   ├── css
    │   ├── img
    │   ├── js
    │   │   └── jquery-3.4.1.min.js
    │   └── plugin
    │       ├── bootscrap
    │       └── font-awesome-4.7.0
    ├── templates
    │   └── web
    │       ├── home.html
    │       ├── layout
    │       │   └── basic.html
    │       ├── login.html
    │       ├── register.html
    │       └── sms_login.html
    ├── tests.py
    ├── urls.py
    └── views
        ├── account.py
        ├── __init__.py

  • 访问注册页面
前端(register.html) 路由urls.py 中间件 view form 发送get请求 erequest 你猜我登录了吗 未登录,导航栏展示登录注册入口 用户未登录,请继续你的表演 走get请求的处理逻辑 返回字段检查结果 返回字段信息 前端(register.html) 路由urls.py 中间件 view form

  • ajax提交注册页面数据
前端 路由 中间件 view form 发送POST请求 你猜我登录了吗 未登录,导航栏展示登录注册入口 用户未登录,请继续你的表演 走POST的请求处理 返回字段检查结果 返回字段信息 前端 路由 中间件 view form

``·

流程概述

一、web请求url

  1. 请求方式可以为浏览器输入url,用get的方式请求该接口。

  2. 请求方式可以为点击页面某个按钮,将该按钮绑定事件,由ajax的方式访问指定的url,提交form表单

    注意:绑定的按钮不能是submit属性,否则提交数据后浏览器会自动再发送一个GET请求

        <script>
            //页面加载完成会执行的函数
            $(function () {
                bindClickregisterBtn();
            })
            /*
            * 点击注册按钮 绑定事件
            * */
            function bindClickregisterBtn() {
                $('#registerSubmitBtn').click(function () {
                    // event.preventDefault(); //取出浏览器的默认行为(submit点击提交数据)
                    console.log("进入bindClickregisterBtn 绑定事件成功")
                    $.ajax({
                        	// "{% url "url别名" %}"  django 前端html访问指定name的url的方法
                            url: "{% url "register" %}",
                            type: "POST",
                            data: $('#register_form').serialize(),         // 获取表单全部字段和值 + csrf_token
                            dataType: "JSON",
                            success: function (res) {
                                if (res.status) {
                                    window.location.href = res.data;
                                } else {
                                    console.log(res);
                                    $.each(res.error, function (key, value) {
                                        // 构造id 获取元素并给存放错误信息的 span写入内容
                                        $('#id_' + key).next().text(value[0]);
                                    })
                                }
                            }
                        }
                    )
                })
           }
    
    
    1. form 表单自动提交,提交按钮的属性必须为submit,后端响应数据要用render或者redirect。提交表单的url在form标签的action属性中定义。

二 、中间件会根据请求的数据,查找该session id在系统中是否存在合法登录数据,如果存在则继续后续处理,如果不存在,转跳到首页(或者登录页面)

  1. 定义中间件,将请求对应的session在系统查找相关数据,检查是否登录

    from django.utils.deprecation import MiddlewareMixin
    from web import models
    
    
    # 自定义的中间件需要去setting中注册
    class AuthMiddleWare(MiddlewareMixin):
        # 定义一个鉴权中间件,所有请求都会来判断其session中的user_id是否存在
        def process_request(self, request):
            # 取出user_id 这个动作是服务器给浏览器响应中要求浏览器返回userid吗?
            # 建立连接后,浏览器会得到服务器给得session id,以后的请求中会携带该id访问
            # 如果该id能够在服务器侧找到 user_id,则说明该用户已经登录。
            user_id = request.session.get('user_id', 0)
            user_obj = models.UserInfo.objects.filter(id=user_id).first()
            # user_id 为空则给默认值0,根据这个id去数据库中是不会找到用户信息的,
            # 此时request.auth = None,用户为登出状态
            request.auth = user_obj
            print(f"MiddlewareMixin  ==============>>>>>{user_obj}")
    
    
  2. 将中间件注册到setting中

    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',
        'web.middleware.middleware.AuthMiddleWare', # 注册自定义的中间件
    ]
    
    
  3. 此后每个请求过来都会先进行中间件中定义的判断(是否登录)

  4. 前端根据登录判断,决定首页展示个人信息(已登录),还是注册、登录入口(未登录)

    <ul class="nav navbar-nav navbar-right">
                <!--如果中间件request.auth存在 则展示用户个人信息,否则展示登录、注册-->
                    {% if request.auth %}
                        <li class="dropdown">
                            <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
                               aria-expanded="false">{{ request.auth.username }} <span class="caret"></span></a>
                            <ul class="dropdown-menu">
                                <li><a href="#">个人信息</a></li>
                                <li><a href="#">修改密码</a></li>
                                <li><a href="{% url 'logout' %}">退出登录</a></li>
                            </ul>
                        </li>
                    {% else %}
                        <li><a href="{% url "login" %}">登 录</a></li>
                        <li><a href="{% url "register" %}">注 册</a></li>
    
                    {% endif %}
    
                </ul>
    

三、urls.py 收到后对url进行解析,并将请求发送给相关view函数

  1. django路由分发

    # 一级路由---->创建项目时生成的urls.py文件
    from django.conf.urls import url, include
    from django.contrib import admin
    # incude(),路由分发,namespace 避免分发的路由出现重名的
    # include() 只能使用include('xxx.urls','app_namespase',namespace='xxxx')的方式,否则会报错。应该是版本问题
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # url(r'^web/', include(('web.urls', 'web'), namespace='web_namespace')),
        url(r'^web/', include('web.urls')),
    ]
    
    # 二级路由-------->创建APP时,手动在APP目录下创建的urls.py
    
    from django.conf.urls import url
    from django.contrib import admin
    from web.views import account
    
    '''
    增加name属性是为了方便反向解析url
    name属性,在view函数中可以通过reverse('name')的方式反向解析name对应的url;
    在html函数中用{% url 'name' %}的方式反向解析name对应的url
    '''
    
    urlpatterns = [
        # url(r'^admin/', admin.site.urls, name="web_admin"),
        url(r'^register/$', account.register, name="register"),
        url(r'^send/sms/$', account.send_sms, name="send_sms"),
        url(r'^login_sms/$', account.sms_login, name="sms_login"),
        url(r'^login/$', account.login, name="login"),
        url(r'^logout/$', account.logout, name="logout"),
        url(r'^image_code/$', account.image_code, name="image_code"),
        url(r'^home/$', account.home, name="web_home"),
    ]
    

view 对请求进行处理

  1. 请求数据传递,request参数会携带前端请求的相关数据

    reuqest.method 请求方法

    request.method.GET get请求的参数内容

    request.method.POST post请求的参数内容

    from django.shortcuts import render, reverse, HttpResponse, redirect
    # view 中定义的函数必须带request参数
    def register(request):
        # 调用form定义的类,获取类属性作为前端展示的内容
        form = account.RegisterModelForm()
        print(form)
        if request.method == 'POST':
            print(f"post content -------------->{request.POST}")
            form = account.RegisterModelForm(data=request.POST)  # 将用户提交的数据,传给RegisterModelForm
            if form.is_valid():  # 开启字段校验,并判断校验结果是否为True(通过)
                form.save()
                # 校验成功(注册成功)后,返回一个页面,让前端可以跳转到登录页面
                return JsonResponse({'status': True, reverse('login'))
            else:
                print("校验没通过,返回false")
                return JsonResponse({'status': False, 'error': form.errors})
        return render(request, 'web/register.html', {'form': form})
    
    
  2. 如果要操作session,可以考虑在review函数中处理校验

    # 账号密码校验,在view函数中判断账号密码是否正确
    def login(request):
        if request.method == "GET":
            form = account.LoginModelForm()
            return render(request, 'web/login.html', {'form': form})
        # 需要操作session时,建议将账号密码校验放到view,方便处理session
        form = account.LoginModelForm(request, data=request.POST)
        if form.is_valid():
            print(f'form ------------->{form}')
            username = form.cleaned_data['username']
            password = form.cleaned_data['password']
            # import django.db.models import Q .多条件查询
            user_obj = models.UserInfo.objects.filter(Q(mail=username) | Q(mobile_phone=username)).filter(
                Q(password=password)).first()
            # 操作session,登录成功后将用户id存入session并设置失效时长
            if user_obj :
                request.session['user_id'] = user_obj.id
                request.session.set_expiry(60 * 60 * 24 * 14)
                return redirect(reverse('web_home'))
            form.add_error('password', "账号或者密码错误"))
        return render(request, 'web/login.html', {'form': form})
    
    # 手机号验证码登录,在form中进行账号密码是否一致的判断
    def sms_login(request):
        form = account.SmsLoginForm()
        if request.method == "POST":
            form = account.SmsLoginForm(request.POST)
            if form.is_valid()# form 返回的mobile_phone是查询结果
                mobile_phone = form.cleaned_data['mobile_phone']
                # 登录成功需要将session中存入用户id信息
                request.session['user_id'] = form.cleaned_data['mobile_phone'].id
                request.session.set_expiry(60 * 60 * 24 * 14)
                # 前端通过ajax提交的数据,所以用JsonResponse返回json数据给前端处理
                return JsonResponse({'status': True, 'data': "/web/home/"})
            else:
                return JsonResponse({'status': False, 'error': form.errors})
    
        return render(request, 'web/sms_login.html', {'form': form})
    

四、通常将字段判断等内容交给form函数处理,处理完将数据返回给view

  1. 希望将数据库字段返回到前端页面的,在form中可以继承forms.ModelForm

    # 注册页面展示的字段内容都是ModelForm弄出来的
    '''
    	view函数通过form=RegisterModelForm()的方式获取展示字段。
    	view函数通过form=RegisterModelForm(request.POST)的方式将前端的参数传递给form。
    	form.field.name  字段名 username
    	form.field.label 前端展示的文本框标题 ‘用户名’
    	form.cleaned_data form校验通过的字段信息 :{'orm.field.name':'clean_name()函数的返回值'}
    '''
    class RegisterModelForm(Bootstrp, forms.ModelForm):
        username = forms.CharField(label='用户名',
                                   min_length=6,
                                   max_length=32,
                                   error_messages={
                                       'min_length': web_error.username_min_error,
                                       'max_length': web_error.username_max_error,
                                   })
        mobile_phone = forms.CharField(label="手机号",
                                       validators=[RegexValidator(r'^(1[3456789])\d{9}', message='手机号格式错误')])
        password = forms.CharField(label='密码', widget=forms.PasswordInput())
        # 表中没有的数据想要在前端展示,在此定义即可
        comfire_password = forms.CharField(label='密码确认', widget=forms.PasswordInput())
        code = forms.CharField(label='验证码', widget=forms.TextInput(), max_length=6, min_length=6)
        education = form_model.ModelChoiceField(required=False, label='最高学历',
                                                queryset=models.global_downlist_value.objects.filter(
                                                    type='education'))
    
        class Meta:
            model = models.UserInfo
            # fields = "__all__" 不能控制展示顺序
            # 按照列表的顺序进行校验
            fields = ['username', 'password', 'comfire_password', 'mail', 'education', 'mobile_phone', 'code']
    
        # # 重新定义 init函数,目的是给每一个field(input标签)添加一个标签的class,便于前端美化页面
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            # 取出field 添加class属性
            for name, field in self.fields.items():
                # name ->字段名称;field ->imput标签
                field.widget.attrs['class'] = 'form-control'
                field.widget.attrs['placeholder'] = '请输入{}'.format(field.label)
    
        # 自定义方法(局部钩子),密码必须包含字母和数字,函数名固定写法 “clean_接字段名"
        # 钩子会在其它字段校验都完成后才会进行,所以此时cleaned_data(存放剔除校验未通过的字段、值)
        def clean_password(self):
            password = self.cleaned_data['password']
            if self.cleaned_data.get('password').isdigit() or self.cleaned_data.get('password').isalpha():
                raise ValidationError("密码必须同时包含字母和数字")
            # password加密返回
            return md5(password)
    
        def clean_code(self):
            conn = get_redis_connection()
            # redis中获取到的数据时二进制的
            code = self.cleaned_data.get("code")
            print(f"code ---------------{code}")
            # stored_code = conn.get(self.cleaned_data.get("mobile_phone")).decode('utf-8')
    
            stored_code = code
            print(f"stored_code ---------------{stored_code}")
            # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
            if code.strip() == stored_code:
                return self.cleaned_data.get("code")
            else:
                raise ValidationError("验证码错误")
    
        def clean_comfire_password(self):
            comfire_password = self.cleaned_data.get('comfire_password')
            secret_comfire_password = md5(comfire_password)
            if self.cleaned_data.get('password') != secret_comfire_password:
                # 所以此处使用该方法将报错信息添加到comfire_password中,用于前端展示,展示位置                                         # ('#id_comfire_password').next()
                self.add_error('comfire_password', "两次密码不一致")  
    
                raise ValidationError("两次密码不一致")  # 全局钩子抛出的异常是在error.__all__中,不属于任何字段,所以error.0取不到
                # ValidationError 执行默认会执行一次add_error,两者差异在于add_error被执行后后面的代码不会中断。
            return self.cleaned_data
    
        # 自定义方法(全局钩子, 检验两个字段),检验两次密码一致;
        # 重写clean方法,需要带入self._validate_unique=True,否则会丢掉唯一性判断。唯一性判断会根据表字段是否唯一决定结果。
        # def clean(self):
        #     self._validate_unique = True
        #     # 应为密码已经加密,所以comfire_password也需要加密后才能比较
        #     comfire_password = self.cleaned_data.get('comfire_password')
        #     secret_comfire_password = md5(comfire_password)
        #     if self.cleaned_data.get('password') != secret_comfire_password:
        #         self.add_error('comfire_password', "两次密码不一致")  # 所以此处使用该方法将报错信息添加到re_pwd中,用于前端展示,
        #         raise ValidationError("两次密码不一致")  # 全局钩子抛出的异常是在error.__all__中,不属于任何字段,所以error.0取不到
        #         # ValidationError 执行默认会执行一次add_error,两者差异在于add_error被执行后后面的代码不会中断。
        #     return self.cleaned_data
    
    
  2. 与数据库无关内容展示到页面,继承forms.Form

    # 手机号登录的form数据处理
    # Bootstrp 将初始化返回input标签属性的初始化方法剥离出来 ,SmsLoginForm本身没有定义初始化函数,所以会先执行父类Bootstrp的初始化函数,
    class SmsLoginForm(Bootstrp, forms.Form):
        # 定义前端要展示的页面
        mobile_phone = forms.CharField(label="手机号", validators=[RegexValidator(r'^(1[3456789])\d{9}', message='手机号格式错误')])
        code = forms.CharField(label="验证码",
                               widget=forms.TextInput(),
                               min_length=6,
                               max_length=6,
                               error_messages={
                                   'min_length': '验证码长度不够6位',
                                   'max_length': '验证码长度超过6位',
                               }
                               )
    
        def clean_mobile_phone(self):
            print("进入  clean_mobile_phone")
            # 获取mobile_phone
            mobile_phone = self.cleaned_data.get('mobile_phone')
            # 检查手机号是否存在数据库
            obj = models.UserInfo.objects.filter(mobile_phone=mobile_phone).first()
            print(f"obj ------------>{obj}")
            # print(f"phone  obj  {obj.mobile_phone}")
            if not obj:
                raise ValidationError("手机号未注册")
            # return obj 即将self.cleaned_data中mobile_phone字段的值由手机号变更为查询结果。这样view就可以根据查询结果去
            # 设置session
            return obj
        
    
        # 测试结果,无论前面的局部钩子是否抛出异常,后面的局部钩子都会被执行
        # 测试结果,如果局部钩子校验失败,对象的数据会从self.cleaned_data中被剔除,
        # 如果校验成功,返回值中,key值一定是字段的name属性值
    
        def clean_code(self):
    
            print(f"进入  clean_code")
            # print(f"-------------self.cleaned_data: {self.cleaned_data}")
            code = self.cleaned_data.get('code')
            conn = get_redis_connection()
            if self.cleaned_data.get('mobile_phone'):
                # store_code = conn.get(self.cleaned_data.get('mobile_phone').mobile_phone).encoding('utf-8')
                store_code = code.strip()
                print(f'store_code   -----> {store_code}')
                if code.strip() != store_code:
                    raise ValidationError("验证码错误")
            return code
    

五、view拿到处理结果后,将内容返回给前端

  1. 返回数据

    form = account.RegisterModelForm()
    '''
    	view函数通过form=RegisterModelForm()的方式获取展示字段。
    	view函数通过form=RegisterModelForm(request.POST)的方式将前端的参数传递给form。
    	form.field.name  字段名 username
    	form.field.label 前端展示的文本框标题 ‘用户名’
    	form.cleaned_data form校验通过的字段信息 :{'orm.field.name':'clean_name()函数的返回值'}
    '''
    
  2. 前端使用ajax提交数据到后端,view返回HttpResponse给前端

  3. 前端使用submit按钮提交数据到后端,view返回JsonResponse

技术点

前端

//给按钮绑定事件
$('#id').click.(function fun-name(){
                	//事件
                })
//ajax传递数据给后端
$.ajax({
    url : "{% url 'urlname' %}",
    type: "POST",
    data : "传递数据",
    success : function (res){
        // res为后端响应的内容
        
        if(res.status){
            //响应status= true (后端返回{'status' : True})
            
        }else{
             //响应status= false (后端返回{'status' : False})
            //错误信息存放res.error; $('#id_' + key) input标签中id=id_key;.next()下一个元素 ; text()写入内容
            $.each(res.error, function (key, value) {
                                $('#id_' + key).next().text(value[0])
        }
    }
})
    
       /*
        * 倒计时函数
        * */
        function sendSmsRemind() {
            // 定位按钮 点击发送验证码
            var $btnSms = $('#getCodeBtn');
            // 增加按钮属性,不可点击
            $btnSms.prop('disabled', true);
            var time = 60;
            var obj = setInterval(function () {
                // 按钮元素上显示内容修改
                $btnSms.val(time + "后重新发送");
                time = time - 1;
                if (time < 1) {
                    clearInterval(obj)
                    $btnSms.val("点击发送验证码").prop('disabled', false);
                }
            }, 1000)
 }

后端

form

from django.forms import ModelForm

from django.forms import Form

通过重写__init__方法传递request到lForm
# view.py
form = account.CheckPhoneAndTPL(request, data=request.GET)
# account.py
class CheckPhoneAndTPL(forms.Form):
    def __init__(self, request=None, *args, **kwargs):
        """
        重新定义init函数,接收view函数中的数据
        """
        super().__init__(*args, **kwargs)
        # 将视图函数中的request传递过来了
        self.request = request
通过重写__init__方法增加返回的input标签属性
# 重新定义个类,让需要增加input属性的FORM类继承
class Bootstrp(object):
    '''
    function:   重新定义 init函数,目的是给每一个field添加一个标签的class,便于前端美化页面
    '''
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 取出field 添加class属性,fields是一个字典key = field.name  value=inpiut标签的属性
        for name, field in self.fields.items():
            field.widget.attrs['class'] = 'form-control'
            field.widget.attrs['placeholder'] = '请输入{}'.format(field.label)
ModelFrom的格式
class RegisterModelForm(Bootstrp, forms.ModelForm):
    # 类属性写前端需要展示字段的长度、正则等校验
    username = forms.CharField(label='用户名',
                               min_length=6,
                               max_length=32,
                               strip=True                   #是否移除用户输入空白
                               error_messages={
                                   'min_length': web_error.username_min_error,
                                   'max_length': web_error.username_max_error,
                               })
    # validators=[RegexValidator(r'^(1[3456789])\d{9}', message='手机号格式错误')] 正则示例 
    mobile_phone = forms.CharField(label="手机号",
                                   validators=[RegexValidator(r'^(1[3456789])\d{9}', message='手机号格式错误')])
    password = forms.CharField(label='密码', widget=forms.PasswordInput())
    # 单选Select widget=forms.widgets.Select()
	#
    education = form_model.ModelChoiceField(required=False, label='最高学历',
                                            queryset=models.global_downlist_value.objects.filter(
                                                type='education'))
    # 表中不存在的字段,但是需要在前端页面展示的可以写在这里
    comfire_password = forms.CharField(label='密码确认', widget=forms.PasswordInput())
    code = forms.CharField(label='验证码', widget=forms.TextInput(), max_length=6, min_length=6)
    
	# 固定写法
    class Meta:
        model = models.UserInfo
        # fields = "__all__" 不能控制展示顺序
        fields = ['username', 'password', 'comfire_password', 'mail', 'education', 'mobile_phone', 'code']

    # 自定义方法(局部钩子),密码必须包含字母和数字,函数名固定写法 “clean_接字段名"
    # 钩子会在其它字段校验都完成后才会进行,cleaned_data(存放已经完成校验的字段、值)
    def clean_password(self):
		pass

    def clean_code(self):
		pass

    def clean_comfire_password(self):
		pass

    # 自定义方法(全局钩子, 检验两个字段),检验两次密码一致;
    # 重写clean方法,需要带入self._validate_unique=True,否则会丢掉唯一性判断。唯一性判断会根据表字段是否唯一决定结果。
    # def clean(self):
    #     self._validate_unique = True
    #     # 应为密码已经加密,所以comfire_password也需要加密后才能比较
    #     comfire_password = self.cleaned_data.get('comfire_password')
    #     secret_comfire_password = md5(comfire_password)
    #     if self.cleaned_data.get('password') != secret_comfire_password:
    #         self.add_error('comfire_password', "两次密码不一致")  # 所以此处使用该方法将报错信息添加到re_pwd中,用于前端展示,
    #         raise ValidationError("两次密码不一致")  # 全局钩子抛出的异常是在error.__all__中,不属于任何字段,所以error.0取不到
    #         # ValidationError 执行默认会执行一次add_error,两者差异在于add_error被执行后后面的代码不会中断。
    #     return self.cleaned_data

中间件
自定义用于判断request的用户是否登录
from django.utils.deprecation import MiddlewareMixin
from web import models


# 自定义的中间件需要去setting中注册
class AuthMiddleWare(MiddlewareMixin):
    # 定义一个鉴权中间件,所有请求都会来判断其session中的user_id是否存在
    def process_request(self, request):
        # 取出user_id 这个动作是服务器给浏览器响应中要求浏览器返回userid吗?
        # 建立连接后,浏览器会得到服务器给得session id,以后的请求中会携带该id访问
        # 如果该id能够在服务器侧找到 user_id,则说明该用户已经登录。
        user_id = request.session.get('user_id', 0)
        user_obj = models.UserInfo.objects.filter(id=user_id).first()
        # user_id 为空则给默认值0,根据这个id去数据库中是不会找到用户信息的,
        # 此时request.auth = None,用户为登出状态
        request.auth = user_obj
        print(f"MiddlewareMixin  ==============>>>>>{user_obj}")


ORM
  1. 下拉列表中的值如何返回给前端
# model.py 
class global_downlist_value(models.Model):
    attr = models.CharField(max_length=32)
    type = models.CharField(max_length=16)
# 前端展示的是下拉列表,重定义str方法,将返回值从id改为atrr
    def __str__(self):
        return self.attr

# form
class RegisterModelForm(Bootstrp, forms.ModelForm):
    # 前端页面显示的下拉列表 最高学历;
    education = form_model.ModelChoiceField(required=False, label='最高学历',
                                            queryset=models.global_downlist_value.objects.filter(type='education'))
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值