Flask中用户登录的两种方式·2

  1. 获取POST请求参数(表单数据):

Flask中用户登录的两种方式2   通过使用ajax的方式提交

总结:第一步登录功能:controllers/user.py进行判断,支持GET和POST,GET进行页面展示,POST是数据处理层,通过一个方法get、post实现两种逻辑。

注意点1. 密码是怎么存的? 密码在数据库中是存的加密后的密码【通过用户设置的密码+系统生成的字符串统一通过某种算法生成了数据库中保存的密码值】(算法被写成了统一公用的算法common/libs/user/UserService.py中的genePwds()方法使用MD5进行对base64加密再加密)

通过用户自己设定的用户名、系统统一生成的salt以及用户自己设置的密码、用户登录密码进行对比,如果对比成功则登录成功,否则登录失败。登陆成功后为了将登陆状态保存,我们将登陆状态保存在cookie里,为了保证cookie值的安全,我们使用了授权token来对cookie进行校验,所以我们将cookie将授权码和uid通过#组成,这就实现了我们的登录和cookie。之后使用Flask拦截器对需要登陆的页面进行拦截,判断是否已经登陆就是把cookie的值取出来进行逆向运算,再将授权码#uid分割开,通过uid去数据库里查询用户是否是存在的,如果存在则拿去用户信息生成token和我们cookie里的授权码进行对比,一致则登陆状态保持,不一致则说明cookie已经被串改了,不安全的,将页面重定向。

问题0:授权token如何校验cookie来保证cookie值的安全?

授权token可以通过校验cookie来保证cookie值的安全。具体的步骤如下:

  1. 在用户登录成功后,服务端生成一个授权token,并将该token与用户的身份信息关联起来。
  2. 将授权token存储在服务端的数据库或缓存中,并将该token作为cookie的值返回给客户端。
  3. 客户端在后续的请求中,会自动携带该cookie(包含授权token)。
  4. 服务端在接收到请求时,会从cookie中获取授权token。
  5. 服务端校验授权token的有效性,包括检查token是否存在、是否过期以及与用户身份信息的匹配性。
  6. 如果授权token校验通过,则服务端可以信任该请求,并继续处理业务逻辑。
  7. 如果授权token校验不通过,则服务端会拒绝该请求,并返回相应的错误信息。

通过以上步骤,服务端可以校验cookie中的授权token,从而保证cookie值的安全性

{% block content %}

	<div class="col-md-6">
			<div class="ibox-content">
				<div class="m-t login_wrap" role="form" >
                    <div class="form-group text-center">
                        <h2 class="font-bold">登录</h2>
                    </div>
					<div class="form-group">
						<input type="text" name="login_name" class="form-control" placeholder="请输入登录用户名">
					</div>
					<div class="form-group">
						<input type="password" name="login_pwd" class="form-control" placeholder="请输入登录密码">
					</div>
					<button type="button" class="btn btn-primary block full-width m-b do-login">登录</button>
                <h3>账号和密码请关注左侧公众号码 回复"<span class="text-danger">订餐小程序</span>"获取,每日更新一次 </h3>
			</div>
		</div>
	</div>


{% endblock %}


{% block js %}
    <script src="{{ buildStaticUrl('/js/user/login.js') }}"></script>
{% endblock %}

-----------------------------------------------------------------------------------------------------------------------------

问题1 ·这里为什么要将<button type="submit">更换为<button type="button">呢?

<button type=“button”>和<button type=‘submit’>在Python中有以下区别:

  1. type=“button”:这表示按钮是一个普通的按钮,点击它不会触发任何默认行为或提交表单。它通常用于执行自定义的JavaScript函数或操作。

  2. type=“submit”:这表示按钮是一个提交按钮,点击它会触发表单的提交行为。当用户点击这个按钮时,表单中的数据将被提交到服务器进行处理。

    <form action="/submit" method="post">
      <input type="text" name="username" placeholder="Username">
      <input type="password" name="password" placeholder="Password">
      <button type="button" onclick="validateForm()">Validate</button>
      <button type="submit">Submit</button>
    </form>
    
    <script>
      function validateForm() {
        // 自定义的表单验证逻辑
        // 如果验证通过,可以使用JavaScript代码手动提交表单
        document.querySelector('form').submit();
      }
    </script>

    在上面的示例中,第一个按钮使用了type=“button”,并绑定了一个JavaScript函数validateForm(),用于验证表单数据。当用户点击这个按钮时,会执行validateForm()函数,如果验证通过,可以使用JavaScript代码手动提交表单。

    第二个按钮使用了type=“submit”,它会触发表单的默认提交行为,将表单数据提交到服务器进行处理

---------------------------------------------------------------------------------------------------------------------------------

class UrlManager(object):
    def __init__(self):
        pass
    
    @staticmethod
    #@staticmethod是一个装饰器,用于将类中的方法转换为静态方法。
    # 静态方法不需要访问类或实例的任何属性,因此可以直接从类中调用,而无需创建类的实例。
    def buildStaticUrl(path):
        ver = "%s"%( 22222222 )
        path =  "/static" + path + "?ver=" + ver
        return UrlManager.buildUrl( path )


问题2: 这里为什么要蹦出个buildStaticUrl() 函数出来多次一举呢?这个函数到底起什么作用?

@staticmethod是一个装饰器,用于将类中的方法转换为静态方法。静态方法不需要访问类或实例的任何属性,因此可以直接从类中调用,而无需创建类的实例。

        在给定的代码中,buildStaticUrl是一个静态方法。它接受一个参数path,并根据该参数构建一个静态URL。具体来说,它将路径path添加到"/static"之后,并附加一个查询参数"ver",该参数的值是一个固定的字符串"22222222"。最后,它调用UrlManager类的buildUrl方法,将构建的URL作为参数传递给该方法。

        这个函数的作用是为了构建静态资源的URL。在给定的代码中,它被用于构建一个JavaScript文件的URL,并在HTML模板中使用该URL引入该文件。

附加问题:  这个buildStaticUrl函数是不是多此一举?

buildStaticUrl函数的作用是构建静态资源的URL,其中包括了资源的路径和版本号。使用buildStaticUrl函数的好处是可以确保每次静态资源更新后,浏览器会重新请求最新的资源,而不是使用缓存中的旧版本资源。这样可以避免浏览器缓存导致的静态资源不更新的问题。

        另外,使用buildStaticUrl函数还可以方便地管理静态资源的路径和版本号,使代码更加清晰和易于维护。如果直接在模板中写死静态资源的路径和版本号,当需要修改路径或版本号时,需要在多个地方进行修改,容易出错。而使用buildStaticUrl函数,只需要在函数内部修改一次,就可以自动应用到所有使用该函数的地方。

        因此,使用buildStaticUrl函数并不是多此一举,而是一种良好的编程实践,可以提高代码的可维护性和可扩展性。


然后看下在static/js/user/user.js里通过ajax编程的js代码

;
var user_login_ops ={
    init:function(){
        this.eventBind();
    },

    eventBind:function(){
        $(".login_wrap .do-login").click( function(){
            var btn_target = $(this);
            if( btn_target.hasClass('disabled')){
                common_ops.alert("正在处理!请不要重复提交~~");
                return;
            }

            var login_name = $(".login_wrap inpuut[name=login_name]").val();
            var login_pwd = $(".login_wrap input[name=login_pwd]").val();

            if( login_name == undefined || login_name.length < 1){
                common_ops.alert("请输入正确的登录用户名~~");
                return;
            }
            if(login_pwd == undefined || login_pwd.length <1){
                common_ops.alert("请输入正确的密码~~");
                return;
            }
            btn_target.addClass("disabled");
            $.ajax({
                url:common_ops.buildUrl("/user/login"),
                    type:'POST',
                    data:{'login_name':login_name, 'login_pwd':login_pwd},
                    dataType:'json',
                    success:function(res){
                        btn_target.removeClass("disabled");
                        var callback = null;
                        if(res.code == 200){
                            callback = function(){
                                window.location.href = common_ops.buildUrl('/');
                            }
                        }
                        common_ops.alert( res.msg, callback);
                }
            });

        });
    }

};

$(document).ready( function(){
    user_login_ops.init();
})

看点1: 上来的; 可以排除很多解析错误

var btn_target = $(this); 的作用是将 当前点击的按钮对象  赋值给  变量btn_target。这样可以方便地在后续的代码中使用该变量来操作按钮对象,例如添加或移除类、修改按钮的属性等操作。


if( btn_target.hasClass('disabled')){ common_ops.alert("正在处理!请不要重复提交~~"); return;

 这段代码是一个条件判断语句,判断btn_target是否具有disabled类。如果具有该类,则执行以下操作:

  1. 调用common_ops.alert函数,弹出提示框显示"正在处理!请不要重复提交~~"。
  2. 返回,结束当前函数的执行。

这段代码的作用是在按钮被点击时,如果按钮已经被禁用,则弹出提示框并阻止重复提交。

  1. "hasClass"是一个jQuery方法,用于检查元素是否具有指定的类。它接受一个参数,即要检查的类名,并返回一个布尔值,表示元素是否具有该类。

  2. "disabled"是一个HTML属性,用于禁用表单元素或按钮。当一个元素具有"disabled"属性时,它将被禁用,用户无法与之交互。

if (btn_target.hasClass('disabled')) {
    common_ops.alert("正在处理!请不要重复提交~~");
    return;
}

在上述代码中,首先使用"hasClass"方法检查"btn_target"元素是否具有"disabled"类。如果具有该类,则显示一个警告消息,并返回。这样可以防止用户重复提交表单或按钮。


btn_target.addClass("disabled");

这行代码使用了jQuery的addClass()方法,它会给选中的元素添加指定的类名。在这个例子中,btn_target是一个jQuery选择器选中的元素,.addClass("disabled")会给这个元素添加一个名为"disabled"的类。这通常用于禁用按钮或者添加样式。


知识点1: ajax 中的eventBind function(){}

$.ajax({
  beforeSend: function() {
    // 在发送Ajax请求之前执行的操作
    eventBind();
  },
  success: function(response) {
    // 请求成功后执行的操作
  },
  error: function(xhr, status, error) {
    // 请求失败后执行的操作
  }
});

function eventBind() {
  // 在这里编写需要执行的操作
}

这段代码定义了一个名为user_login_ops的对象(问题3: 对象!!为啥不是变量?),其中包含一个名为init的方法和一个名为eventBind的方法。init方法用于初始化对象,而eventBind方法用于绑定事件。在示例代码中,init方法被调用以初始化user_login_ops对象。

由知识点1可以看出,此刻我们用的eventBind是在发送Ajax请求之前执行的操作。


$.ajax({  ... . .

})

        这段代码是一个使用jQuery的AJAX请求的示例。它通过发送一个POST请求到指定的URL,并传递了两个参数:‘login_name’和’login_pwd’。请求的数据类型被设置为JSON,意味着服务器应该返回一个JSON格式的响应。

        如果请求成功,即响应的状态码为200,那么会执行success函数。在这个函数中,首先移除了一个名为"disabled"的CSS类,然后根据响应的code属性的值进行判断。如果code等于200,那么会定义一个名为callback的函数,该函数将重定向到网站的根目录。最后,调用common_ops.alert函数来显示响应的msg属性的值,并将callback函数作为参数传递给它。

        这段代码的作用是在用户登录后,根据服务器返回的响应来执行不同的操作,例如重定向到首页或显示错误信息

        在这段代码中,开头的$符号是jQuery的简写形式。它是一个JavaScript库,提供了许多简化操作DOM、处理事件、执行动画等功能的方法。在这里,$表示调用jQuery库中的方法。

callback是一个变量,用于存储一个函数。在这段代码中,如果服务器返回的状态码为200,那么callback函数会被赋值为一个匿名函数。这个匿名函数的作用是将浏览器的URL重定向到common_ops.buildUrl(‘/’)所返回的URL。

window.location.href是JavaScript中用于获取或设置当前页面的URL的属性。在这段代码中,当服务器返回的状态码为200时,callback函数会将浏览器的URL重定向到common_ops.buildUrl(‘/’)所返回的URL。

res是一个参数,用于存储从服务器返回的响应数据。在这个例子中,res是一个JSON对象,包含了服务器返回的数据。通过使用res.coderes.msg,我们可以访问服务器返回的状态码和消息。

res.code用于获取服务器返回的状态码,例如200表示成功,404表示未找到等等。通过检查状态码,我们可以根据不同的情况执行不同的操作。

res.msg用于获取服务器返回的消息,例如成功登录的提示信息或者错误信息等等。我们可以将这个消息显示给用户,或者根据消息执行相应的操作。

总之,res是一个存储服务器返回数据的对象,通过访问其中的属性,我们可以获取服务器返回的状态码和消息。

在这段代码中,res是一个变量,可以根据需要替换为其他字母或单词。只要确保替换后的变量名在代码的其他部分没有被使用即可。

例如,你可以将res替换为response或者其他任何你喜欢的变量名。只需确保在替换后的代码中,所有引用到该变量的地方都进行了相应的修改。

$.ajax({
    url: common_ops.buildUrl("/user/login"),
    type: "POST",
    data: {
        'login_name': login_name,
        'login_pwd': login_pwd
    },
    dataType: "json",
    success: function(response) {
        btn_target.removeClass("disabled");
        var callback = null;
        if (response.code == 200) {
            callback = function() {
                window.location.href = common_ops.buildUrl('/');
            }
        }
        common_ops.alert(response.msg, callback);
    }
});

问题3 var对象而不是变量?

        在JavaScript中,使用var关键字定义的变量可以是任何类型,包括基本类型和对象类型。在这段代码中,var user_login_ops定义的是一个对象,而不是一个变量。这是因为在JavaScript中,对象是一种复合数据类型,可以包含多个属性和方法。通过定义一个对象,我们可以将相关的属性和方法组织在一起,以便更好地管理和使用。在这段代码中,user_login_ops是一个对象,其中包含了一个init方法和一个eventBind方法。通过调用user_login_ops.init(),我们可以执行init方法,并开始执行相应的操作。

知识点2: 在js中 || 就是python中的or   或

还有就是static/js/common.js中关于函数buildUrl:function(){}的定义

var common_ops = {
    init:function(){
        this.eventBind();
        this.setMenuIconHighLight();
    },
    eventBind:function(){
        $('.navbar-minimalize').click(function () {
            $("body").toggleClass("mini-navbar");
            SmoothlyMenu();
        });

        $(window).bind("load resize scroll", function () {
            if (!$("body").hasClass('body-small')) {
                fix_height();
            }
        });
    },
    setMenuIconHighLight:function(){
         if( $("#side-menu li").size() < 1 ){
            return;
        }
        },
     buildUrl:function( path, params){
        var url = ""+path;
        var _paramUrl = "";
        if( params ){
            _paramUrl = Object.keys( params).map( function (k){
                return [encodeURIComponent(k), encodeURIComponent( params[k])].join("=");
            }).join("&");
            _paramUrl = "r" +_paramUrl;
        }
        return url + _paramUrl;
    },

    }

};

这段代码是一个JavaScript对象,名为common_ops。它包含了一些方法和属性。下面是对这段代码的介绍:

  1. init方法:初始化方法,用于绑定事件和设置菜单图标高亮。
  2. eventBind方法:事件绑定方法,用于绑定点击事件和窗口加载、调整大小、滚动事件。
  3. setMenuIconHighLight方法:设置菜单图标高亮方法,用于检查菜单项数量并设置高亮。
  4. buildUrl方法:构建URL方法,用于构建URL路径和参数。

这段代码的作用是初始化页面,并提供了一些常用的方法,例如绑定事件、设置菜单图标高亮和构建URL。你可以根据需要使用这些方法来实现相应的功能。


问题4: javascript 在同目录下的不同级别的js文件中,javascript对象不需要在别的文件中引入吗?

在同目录下的不同级别的JavaScript文件中,如果你想在一个文件中使用另一个文件中定义的JavaScript对象,你需要在使用的文件中引入该对象所在的文件。以下是两种常见的引入方式:

  1. 使用<script>标签:
    <script src="另一个文件.js"></script>

这种方式会将另一个文件中的JavaScript代码直接嵌入到当前文件中。

      2.使用import语句(ES6模块):

import { 对象名 } from './另一个文件.js';

import { 对象名 } from './另一个文件.js';

这种方式使用ES6模块的语法,可以在当前文件中引入另一个文件中导出的对象。

需要注意的是,使用import语句需要在支持ES6模块的环境中运行,或者使用工具(如Babel)将ES6模块转换为普通的JavaScript代码。


这真就和浪子老师说的一样色的: 链接管理 就是一门艺术。

这就像一个人在冰面走着走着,莫名地掉进了一个冰窟窿里,醍醐灌顶啊!


buildUrl:function(path, params){}

这段代码是一个JavaScript函数,用于构建URL。下面是代码中各部分的详细作用:

  1. var url = ""+path;:将传入的path参数赋值给url变量。

  2. var _paramUrl = "";:初始化一个空字符串变量_paramUrl,用于存储参数部分的URL。

  3. if( params ){...}:判断是否存在参数。如果存在参数,则执行以下代码块。

  4. _paramUrl = Object.keys( params).map( function (k){...}).join("&");:使用Object.keys()方法获取参数对象params的所有键,并通过map()方法遍历每个键,将键和对应的值进行URL编码,并使用encodeURIComponent()方法进行编码。然后,使用join("&")方法将所有键值对用"&"连接起来,形成参数部分的URL。

  5. _paramUrl = "r" +_paramUrl;:在参数部分的URL前面添加字符"r"。

  6. return url + _paramUrl;:将url和参数部分的URL拼接起来,形成最终的URL,并将其作为函数的返回值。

这段代码的作用是根据传入的pathparams构建一个URL,并返回该URL


问题5: encodeURIComponent(k) 是哪门子编码?为什么需要encodeURIComponent(k)来编码?

encodeURIComponent(k)是JavaScript中的一个方法,用于对字符串进行编码。它的作用是将字符串中的特殊字符转换为它们的编码形式,以便在URL中传递参数时能够正确地传递和解析。

需要使用encodeURIComponent(k)来编码的原因是,URL中只能包含特定的字符,例如字母、数字和一些特殊字符(如-_.!~*'())。如果URL中包含其他字符,例如空格、中文字符或一些特殊字符(如@#$%^&+=),那么就需要对它们进行编码,以确保URL的完整性和正确性。

encodeURIComponent(k)会将字符串中的每个字符都进行编码,包括字母、数字和特殊字符。它使用一种称为百分号编码(Percent Encoding)的方式,将每个字符转换为%xx的形式,其中xx是字符的ASCII码的十六进制表示。

下面是一个使用encodeURIComponent(k)的示例:

var k = "Hello, 世界!";
var encodedK = encodeURIComponent(k);
console.log(encodedK); // 输出:Hello%2C%20%E4%B8%96%E7%95%8C%21

在这个示例中,字符串"Hello, 世界!“被编码为"Hello%2C%20%E4%B8%96%E7%95%8C%21”。这样,当我们将编码后的字符串作为URL的参数传递时,服务器就能正确地解析并处理这些特殊字符。


问题6: js 中定义的对象在另一个js中可以直接使用不需要引用吗?

在JavaScript中,如果你在一个JS文件中定义了一个对象,你可以在另一个JS文件中直接使用该对象,而不需要进行额外的引用。这是因为JavaScript是一种解释性语言,它在运行时会将所有的JS文件合并在一起,并将它们的作用域合并为一个全局作用域。因此,你可以在任何一个JS文件中访问和使用其他JS文件中定义的对象。

举个例子,假设你在一个名为"file1.js"的文件中定义了一个对象:

var myObject = {
  name: "John",
  age: 25
};

然后,在另一个名为"file2.js"的文件中,你可以直接使用"file1.js"中定义的对象:

console.log(myObject.name); // 输出:John
console.log(myObject.age); // 输出:25

这是因为在运行时,JavaScript会将这两个文件合并为一个全局作用域,所以你可以在任何一个文件中访问和使用其他文件中定义的对象。


接下来的看点就是编程大浪子整合的flask有圈有点的大框架了,请看py文件

;
var user_login_ops ={
    init:function(){
        this.eventBind();
    },

    eventBind:function(){
        $(".login_wrap .do-login").click( function(){
            var btn_target = $(this);
            if( btn_target.hasClass('disabled')){
                common_ops.alert("正在处理!请不要重复提交~~");
                return;
            }

            var login_name = $(".login_wrap input[name=login_name]").val();
            var login_pwd = $(".login_wrap input[name=login_pwd]").val();

            if( login_name == undefined || login_name.length < 1){
                common_ops.alert("请输入正确的登录用户名~~");
                return;
            }
            if(login_pwd == undefined || login_pwd.length <1){
                common_ops.alert("请输入正确的密码~~");
                return;
            }
            btn_target.addClass("disabled");
            $.ajax({
                url:common_ops.buildUrl("/user/login"),
                    type:'POST',
                    data:{'login_name':login_name, 'login_pwd':login_pwd},
                    dataType:'json',
                    success:function(res){
                        btn_target.removeClass("disabled");
                        var callback = null;
                        if(res.code == 200){
                            callback = function(){
                                window.location.href = common_ops.buildUrl('/');
                            }
                        }
                        common_ops.alert( res.msg, callback);
                }
            });

        });
    }

};

$(document).ready( function(){
    user_login_ops.init();
})

双手摇摆、饶了好久才发现,UserService.geneAuthCode(user_info) 函数使用的微妙微翘,随手捏来。这里是直接引入了自定义的UserService()类,然后使用了我们已经定义好的UserService()类里的函数,这种方式就叫【方法】

请问使用python中已定义好的类的函数 叫啥?

在Python中,使用已定义好的类的函数通常被称为"方法"。方法是与特定类相关联的函数,用于执行特定的操作或实现特定的功能。

下面是一个示例,演示了如何使用Python中已定义好的类的方法:

# 定义一个类
class MyClass:
    def __init__(self, name):
        self.name = name

    def say_hello(self):
        print("Hello, " + self.name + "!")

# 创建类的实例
my_object = MyClass("Alice")

# 调用类的方法
my_object.say_hello()  # 输出:Hello, Alice!

在上面的示例中,我们定义了一个名为MyClass的类,该类具有一个名为say_hello的方法。通过创建MyClass的实例my_object,我们可以调用say_hello方法来打印出一条问候语。

学到这里,我发现赋值有在前面类括号里的,也有在类后面的函数(即方法)里的,这有两种现象,这两种现象是混为一谈,随便凑搭、凑合着使用吗?

python中方法 的赋值有什么区别吗? 赋值给类 和 赋值给类里的函数 有区别吗

在Python中,方法的赋值有一些区别。赋值给类和赋值给类里的函数是有区别的。

  1. 赋值给类:当将一个函数赋值给一个类时,该函数将成为类的一个属性。这意味着该函数可以通过类名来访问,也可以通过类的实例来访问。但是,无论通过类名还是通过实例访问该函数,它都是一个普通的函数,没有特殊的行为。

  2. 赋值给类里的函数:当将一个函数赋值给类里的函数时,该函数将成为类的一个方法。这意味着该函数只能通过类的实例来访问,而不能通过类名来访问。当通过实例访问该方法时,该方法会自动将实例作为第一个参数传递给函数。这个参数通常被称为self,它表示对当前实例的引用。

下面是一个示例来说明这两种赋值的区别:

# 赋值给类
class MyClass:
    def func1():
        print("This is a function assigned to the class")

# 赋值给类里的函数
class MyClass2:
    def func2(self):
        print("This is a method assigned to the class")

# 通过类名访问赋值给类的函数
MyClass.func1() # 输出:This is a function assigned to the class

# 通过类名访问赋值给类里的函数
MyClass2.func2() # 报错:TypeError: func2() missing 1 required positional argument: 'self'

# 通过实例访问赋值给类里的函数
obj = MyClass2()
obj.func2() # 输出:This is a method assigned to the class

class UserService():

        def geneAuthCode(user_info=None)

                pass

UserService(user_info) 和 UserService.geneAuthCode(user_info)有什么区别吗?

class UserService(): def geneAuthCode(user_info=None) passUserService(user_info) 是定义类和创建类的实例的两种方式,而 UserService.geneAuthCode(user_info) 是调用类的方法。

  • class UserService(): def geneAuthCode(user_info=None) pass 定义了一个名为 UserService 的类,其中包含一个名为 geneAuthCode 的方法。这个方法可以接受一个名为 user_info 的参数,但是在这个例子中没有给出具体的实现代码。

  • UserService(user_info) 创建了一个 UserService 类的实例,并将 user_info 作为参数传递给类的构造函数 __init__。这个实例可以用来访问类中定义的属性和方法。

  • UserService.geneAuthCode(user_info) 是通过类名直接调用类的方法。这种方式不需要创建类的实例,可以直接调用类中定义的方法。

所以,UserService(user_info) 是创建类的实例,而 UserService.geneAuthCode(user_info) 是调用类的方法。它们的区别在于一个是创建对象,一个是调用对象的方法。

书读百遍,其意自现。  我弥陀佛、我弥陀佛....... 


呦呵,这又蹦出个啥?感情再来一边?

类的实例  和  类的方法   有什么区别?

类的实例   和  类的方法  有以下区别:

  1. 定义方式不同:类的实例方法是在类中定义的普通方法,需要通过实例对象来调用;而类的方法是使用@classmethod装饰器修饰的方法,可以直接通过类名来调用。

  2. 参数不同:类的实例方法的第一个参数通常是self,表示实例对象本身;而类的方法的第一个参数通常是cls,表示类本身。

  3. 访问权限不同:类的实例方法可以访问实例变量和实例方法,也可以访问类变量和类方法;而类的方法可以访问类变量和类方法,但不能直接访问实例变量和实例方法。

  4. 调用方式不同:类的实例方法需要通过实例对象来调用,可以访问实例属性和实例方法;而类的方法可以通过类名来调用,可以访问类属性和类方法。

  5. 使用场景不同:类的实例方法通常用于操作实例对象的属性和方法,可以根据实例的状态进行操作;而类的方法通常用于操作类的属性和方法,可以在不创建实例对象的情况下进行操作。

    class MyClass:
        class_var = 10
    
        def __init__(self, instance_var):
            self.instance_var = instance_var
    
        def instance_method(self):
            print("This is an instance method")
            print("Instance variable:", self.instance_var)
            print("Class variable:", self.class_var)
    
        @classmethod
        def class_method(cls):
            print("This is a class method")
            print("Class variable:", cls.class_var)
    
    # 创建实例对象
    obj = MyClass(20)
    
    # 调用实例方法
    obj.instance_method()
    
    # 调用类方法
    MyClass.class_method()

    话归py原项目文件,user_info从何而来?  因为在这要调用类方法UserService.geneAuthCode(user_info),不给我user_info,我类里面用@staticmethod装饰定义的类的方法就迟迟收不到动工信号呀!(user_info就是动工信号! 再描描:这不是类的实例方法~  嘻嘻嘻)的

        上面有个user_info = User.query.filter_by( login_name = login_name ).first()

下面跟着些个处理。

user_info = User.query.filter_by(login_name=login_name).first() 是使用flask-SQLAlchemy查询数据库中的用户信息的代码。这段代码的作用是根据login_name字段的值在User表中过滤出符合条件的第一个用户,并将其赋值给user_info变量。

这段代码的执行步骤如下:

  1. 使用User.query创建一个查询对象。
  2. 使用filter_by(login_name=login_name)方法对查询对象进行过滤,只保留login_name字段值等于login_name变量的记录。
  3. 使用first()方法获取过滤后的第一个结果,并将其赋值给user_info变量。
  4. 请注意,这段代码需要在正确配置了flask-SQLAlchemy和数据库连接的情况下才能正常运行。

问题7:  User 是个列表模型,import User 就可以了,但是login_name 的值从何而来?又怎么给login_name赋值呢?

顺着py文件网上看可以看到,login_name的值是从请求参数中获取的。在这个例子中,login_name的值通过request.values获取,然后通过req[‘login_name’]获取。

具体赋值的过程是在  前端页面的表单  中,用户输入登录用户名后,提交表单时会将  输入的值  作为   请求参数   发送给 后端。后端通过request.values获取到这个参数的值,然后赋值给login_name变量。

可以感受到我们编程的连贯性,就像功夫里的某套拳法。

问题8: python flask框架中如何获取请求参数?【这边老是登录不上,告诉账户不对,在这顺藤摸瓜呢。- -】

在Python Flask框架中,可以使用request对象来获取请求参数。request对象是Flask框架中的一个全局变量,用于处理HTTP请求。通过request对象的属性和方法,可以获取到请求中的各种参数。

以下是获取请求参数的几种常见方法:

  1. 获取GET请求参数:
from flask import request

@app.route('/example', methods=['GET'])
def example():
    param1 = request.args.get('param1')  # 获取单个参数
    param2 = request.args.getlist('param2')  # 获取多个参数,返回一个列表
    return 'param1: {}, param2: {}'.format(param1, param2)

2. 获取POST请求参数(表单数据):

from flask import request

@app.route('/example', methods=['POST'])
def example():
    param1 = request.form.get('param1')  # 获取单个参数
    param2 = request.form.getlist('param2')  # 获取多个参数,返回一个列表
    return 'param1: {}, param2: {}'.format(param1, param2)

3.获取POST请求参数(JSON数据):

from flask import request

@app.route('/example', methods=['POST'])
def example():
    data = request.get_json()  # 获取JSON数据
    param1 = data.get('param1')  # 获取单个参数
    param2 = data.get('param2')  # 获取单个参数
    return 'param1: {}, param2: {}'.format(param1, param2)

需要注意的是,获取请求参数前需要确保已经导入了request模块。


route_user = Blueprint('user_page', __name__)
@route_user.route('/login', methods = ['GET', 'POST'])
def login():
    if request.method =="GET":
        return render_template("user/login.html")
    resp = {'code': 200, 'msg': '登录成功~~', 'data': {}}
    req = request.values
    login_name = req['login_name'] if 'login_name' in req else ''
    login_pwd = req['login_pwd'] if 'login_pwd' in req else ''

问题9: 那这串代码通过request.values能 获得 前端 给 flask框架的后端 请求参数吗?

使用request.values可以获取请求参数。在给定的代码中,req = request.values将请求参数赋值给了req变量。

请注意,request.values返回的是一个MultiDict对象,可以通过  键  来获取对应的  值  。例如,req.get("key")可以获取名为"key"的请求参数的值。

MultiDict对象是Werkzeug库中的一个类,它是字典的子类,用于处理同一个键对应多个值的情况。比如,在文件上传字段中可能会接收多个文件,这时就可以使用MultiDict来存储这些文件对象。

from werkzeug.datastructures import MultiDict

# 创建一个MultiDict对象
data = MultiDict()

# 添加键值对
data.add('name', 'Alice')
data.add('name', 'Bob')
data.add('age', 25)

# 获取键对应的所有值
names = data.getlist('name')
print(names)  # 输出:['Alice', 'Bob']

# 获取键对应的第一个值
name = data.get('name')
print(name)  # 输出:Alice

# 获取所有键值对
for key, value in data.items():
    print(key, value)
# 输出:
# name Alice
# name Bob
# age 25

通过MultiDict对象,我们可以方便地处理同一个键对应多个值的情况,并且可以灵活地获取和操作这些值。


到这里发现还是因为获取不到login_name的值导致报错  “请输入正确的登录用户名~~”

看看前端。

问题10:前端如何操作才能让flask后端通过 request.values 来获得值?

在前端操作中,可以通过以下几种方式来让Flask后端通过request.values来获取值:

  1. 使用表单提交: 在HTML中使用<form>标签创建一个表单,并设置method属性为POSTGET,然后将表单中的输入字段命名为后端需要的参数名。当用户提交表单时,浏览器会将表单数据作为请求的一部分发送给后端,后端可以通过request.values来获取这些值。

    <form action="/submit" method="POST">
      <input type="text" name="username">
      <input type="password" name="password">
      <input type="submit" value="Submit">
    </form>
  2. 使用AJAX请求: 在前端使用JavaScript发送AJAX请求,数据以JSON格式发送给后端。可以使用XMLHttpRequest对象或者现代览器提供的fetch函数来发送请求。

    var data = {
      username: "John",
      password: "123456"
    };
    
    fetch('/submit', {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(data)
    });

    在后端,可以通过request.get_json()来获取JSON数据,并使用.values来访问其中的值。

  3. 使用URL参数: 在URL中添加参数,并使用GET请求发送给端。后端可以通过request.values来获取这些参数的。

    var username = "John";
    var password = "123456";
    var url = '/submit?username=' + username + '&password=' + password;
    
    fetch(url);

    在后端,可以通过request.values来访问URL参数的值。

【Flask】关于request.json /.values /.args /.form

args: get参数       form: post  表单           values: args + form             json: json数据


在static/js/user/login.js中有这样一段代码

 ;
var user_login_ops ={
    init:function(){
        this.eventBind();
    },

...,
           

var login_name = $(".login_wrap input[name=login_name]").val();
            var login_pwd = $(".login_wrap input[name=login_pwd]").val();

            if( login_name == undefined || login_name.length < 1){
                common_ops.alert("请输入正确的登录用户名~~");
                return;
            }
};

研究一下common_ops.alert()

var common_ops = {
    init:function(){
        this.eventBind();
        this.setMenuIconHighLight();
    },

...,

    alert:function( msg ,cb ){
        layer.alert( msg,{
            yes:function( index ){
                if( typeof cb == "function" ){
                    cb();
                }
                layer.close( index );
            }
        });
    },

这段代码定义了一个名为common_ops的对象,其中包含一个alert方法。该方法接受两个参数:msg和cb。当调用alert方法时,它会弹出一个对话框显示msg,并在用户点击确定按钮后执行回调函数cb(如果cb是一个函数)。同时,它还会关闭对话框。

这段代码的作用是封装了一个弹出对话框的功能,方便在其他地方调用。通过调用common_ops.alert(msg, cb)可以实现弹出对话框并执行回调函数的功能。

alert:function(){}  中的冒号是用来定义函数的参数的。在这个例子中,alert函数接受两个参数:msg和cb。冒号后面的部分是函数体,用来定义函数的具体操作。

layer是一个JavaScript库,用于创建弹出窗口和提示框。在给定的代码中,layer.alert()函数用于创建一个弹出提示框,其中msg参数是要显示的消息内容,cb参数是一个回调函数,当用户点击提示框的确认按钮时会调用该回调函数。

layer库通常与其他JavaScript库(如jQuery)一起使用,以便在网页中创建交互式的弹出窗口和提示

  1. var common_ops = { ... }:这行代码定义了一个变量common_ops,并将一个对象赋值给它。对象中包含了一个alert方法。

  2. alert:function( msg ,cb ){ ... }:这是alert方法的定义。它接受两个参数:msg和cb。msg是要显示的消息,cb是一个回调函数。

  3. layer.alert( msg,{ ... } ):这是调用layer.alert方法的语句。layer是一个JavaScript库,它提供了一些弹窗和提示框的功能。这里调用了layer.alert方法来显示一个弹窗,其中包含了一个消息和一个配置对象。

  4. yes:function( index ){ ... }:这是配置对象中的一个属性,它的值是一个函数。这个函数在用户点击弹窗的确定按钮时被调用。它接受一个参数index,表示弹窗的索引。

    yes是一个对象的属性,它是一个函数。在这个例子中,yes函数被用作layer.alert方法的参数。当用户点击弹出框中的"确定"按钮时,yes函数会被调用。

    yes函数的作用是   关闭弹出框并执行回调函数cb。它接受一个参数index,该参数表示弹出框的索引。在函数体内部,首先通过typeof判断cb是否为一个函数,如果是函数,则调用cb()执行回调函数。然后使用layer.close(index)关闭弹出框。

    总结来说,yes函数是用来处理弹出框的"确定"按钮点击事件的,它关闭弹出框并执行回调函数

  5. if( typeof cb == "function" ){ ... }:这是一个条件语句,用来判断cb是否是一个函数。如果是函数,则执行下面的代码。

  6. cb();:这是调用回调函数cb的语句。

  7. layer.close( index );:这是调用layer.close方法的语句,用来关闭弹窗。它接受一个参数index,表示要关闭的弹窗的索引。


问题11 : 请详细解析介绍一下yes 中的弹出框中的 确定是在哪里定义的?

yes 中的弹出框中的确定是在 layer.alert 函数中定义的。具体来说,layer.alert 函数是由 layer.js 提供的一个弹出层插件,用于显示一个带有确定按钮的弹出框。在 layer.alert 函数中,通过  传入  一个对象   作为   第二个参数    来  定义  弹出框 的配置,其中的 yes 属性是一个函数,用于定义点击确定按钮后的回调操作。在这个函数中,首先判断 cb 是否为一个函数,如果是的话,则执行 cb(),然后调用 layer.close(index) 关闭弹出框,其中的 index 是弹出框的索引值。

示例代码如下:

var common_ops = {
  alert: function(msg, cb) {
    layer.alert(msg, {
      yes: function(index) {
        if (typeof cb == "function") {
          cb();
        }
        layer.close(index);
      }
    });
  }
};

问题12: 后面的common_ops.alert()并没有给cb赋值,是怎么回事?

        代码中的common_ops.alert()函数接受两个参数msgcb,其中msg是要显示的提示信息,cb是一个回调函数。在弹出提示框后,如果cb是一个函数,则会执行该函数,然后关闭提示框。

        在代码中的条件判断语句中,如果login_name未定义或长度小于1,则会调用common_ops.alert()函数,并传入参数"请输入正确的登录用户名~~"。由于没有给cb赋值,所以在弹出提示框后不会执行任何操作。

        因此,common_ops.alert()函数中的cb参数并没有被赋值,所以在调用common_ops.alert()时不会执行任何回调函数

问题13: 后面的common_ops.alert()并没有给cb赋值,没有任何回调函数,回调函数是怎么回事?请详细解析一下回调函数的功能以及如何和cb进行共同作用的

        回调函数是一种特殊的函数,它作为参数传递给另一个函数,并在特定事件发生时被调用。在这个例子中,回调函数cb被作为参数传递给common_ops.alert函数。当用户点击提示框的确认按钮时,回调函数cb会被调用。

        在common_ops.alert函数中,layer.alert函数是一个弹出提示框的函数。它的第二个参数是一个对象,其中包含一个yes属性该属性的值是一个函数当用户点击提示框的确认按钮时,该函数会被调用

        在这个函数中,首先判断cb是否是一个函数,如果是,则调用cb函数。然后,使用layer.close函数关闭提示框。

        通过将回调函数作为参数传递给common_ops.alert函数,可以在特定事件发生时执行自定义的操作。在这个例子中,当用户点击确认按钮时,可以执行一些额外的操作,例如跳转页面或执行其他函数。

        回调函数和cb之间的共同作用是,当用户点击确认按钮时,common_ops.alert函数会调用回调函数cb。这样可以实现在特定事件发生时执行自定义的操作。


问题14: 也就是说刚才那堆就是一个弹窗,那登录的用户名信息以及登录密码是如何实现信息的JavaScript读取动作以及从前端传递到后端的呢?

在static/js/user/login.js中有个eventBind:function(){}

var user_login_ops ={
    init:function(){
        this.eventBind();
    },

    eventBind:function(){
        $(".login_wrap .do-login").click( function(){
            var btn_target = $(this);
            if( btn_target.hasClass('disabled')){
                common_ops.alert("正在处理!请不要重复提交~~");
                return;
            }

            var login_name = $(".login_wrap input[name=login_name]").val();
            var login_pwd = $(".login_wrap input[name=login_pwd]").val();
            $.ajax({
                url:common_ops.buildUrl("/user/login"),
                    type:'POST',
                    data:{'login_name':login_name, 'login_pwd':login_pwd},
                    dataType:'json',
                    success:function(res){
                        btn_target.removeClass("disabled");
                        var callback = null;
                        if(res.code == 200){
                            callback = function(){
                                window.location.href = common_ops.buildUrl('/');
                            }
                        }
                        common_ops.alert( res.msg, callback);
                }
            });

}

这段代码是一个用户登录的前端脚本,主要实现了以下功能:

  1. user_login_ops是一个对象,其中包含了两个方法:initeventBind
  2. init方法用于初始化,调用了eventBind方法。
  3. eventBind方法用于绑定事件,主要是给登录按钮添加点击事件。
  4. 当点击登录按钮时,会执行一个AJAX请求,向后端发送登录请求。
  5. 请求的URL是通过common_ops.buildUrl("/user/login")构建的,该方法会将"/user/login"拼接到当前页面的URL上。
  6. 请求的类型是POST,发送的数据包括登录名和登录密码。
  7. 请求的数据类型是JSON。
  8. 请求成功后,会执行一个回调函数。
  9. 如果返回的状态码是200,表示登录成功,会执行一个跳转到首页的回调函数。
  10. 如果返回的状态码不是200,会弹出一个提示框显示返回的消息。

这段代码的作用是实现用户登录功能,当用户点击登录按钮时,会向后端发送登录请求,并根据返回的结果进行相应的处理。

附加问题:请解析一下$('.login_wrap .do-login'),不写.do-login行不行, .do-login 在$('.login_wrap .do-login')起什么作用?

$('.login_wrap .do-login')是一个 jQuery选择器,用于选取 具有类名为do-login的元素,且这些元素是在具有类名为login_wrap的元素内部的。所以,如果不写.do-login,则无法准确地 选取到具有 该类名的 元素。

.do-login$('.login_wrap .do-login')中的作用是指定要选取的元素必须具有类名为do-login,以便对这些 元素  进行  操作  或  绑定事件。


问题15: 这段代码中var login_pwd = $(".login_wrap input[name=login_pwd]").val(); 为什么会有$符 并且input起到什么作用? name起到什么作用?

在这段代码中,var login_pwd = $(".login_wrap input[name=login_pwd]").val();是用来获取登录密码的值。

val()是jQuery的一个方法,用于获取元素的值。

这里的  符号是jQuery库的一个简写,它是一个函数,用于选择HTML元素。$(".login_wrap input[name=login_pwd]")是一个jQuery选择器,它选择了一个class为login_wrap的元素下的name属性为login_pwd的input元素。

【换句我们容易理解的大白话讲就是: 因为要获取表单的两个值嘛【登录用户名和登录密码】选取了.login_wrap类下的input框里面的name值等于login_name 然后把它的.val()值获取出来  】

在这段代码中,input元素起到了接收用户输入的作用。name属性是用来标识该输入框的名称,以便在后台处理表单数据时能够准确地获取到对应的值。


问题16:.click( function(){....}这段函数中,click是 点击事件,function(){}是 方法,请解析一下 js中事件和方法

在JavaScript中,事件  是指  用户与网页交互时发生的  动作,例如  点击、鼠标移动、键盘按下等。而  方法 是指 一段可重复使用的  代码块,用于执行特定的任务。

在给元素绑定事件时,可以使用  事件处理函数  来  定义 事件触发时 要执行的 代码。常见的 事件处理函数 有两种形式:匿名函数  和  命名函数

  1. 匿名函数:在事件绑定时  直接  定义一个 匿名函数 作为 事件处理函数
    $(".login_wrap .do-login").click(function(){
        // 事件处理代码
    });

  2. 命名函数:先定义 一个 函数,然后将 函数名 作为 事件处理函数  传递给  事件绑定方法
    function loginHandler(){
        // 事件处理代码
    }
    
    $(".login_wrap .do-login").click(loginHandler);

    在上述代码中,.login_wrap .do-login是 选择器 ,表示选择class为do-login的元素,并且该元素是.login_wrap的子元素。.click()是jQuery提供的一个事件绑定方法,用于给元素绑定点击事件。

    当用户点击.do-login元素时,事件触发,绑定的事件处理函数会被调用,执行其中的代码。


接下来我继续登录,发现数据库名字打错了,更换正确的数据库名字后,依旧报错,是cookie相关问题,简单设置了一下便登陆成功了。前天昨天和今天三天的时间解剖编程大浪子先生的这段精致又肥而不腻的代码,确实是框架结构可吹可点,感谢浪子先生。 也希望自己可以多多重复吸收这里面的精髓,真正应用到自己的小项目上。谢谢大家的观看,Thanks~BEST WISH!

问题17: 这段flask代码中,AUTH_COOKIE_NAME 有什么作用?是不是必须要设置这段代码?

AUTH_COOKIE_NAME在这段Flask代码中的作用是设置cookie的名称。它是用来存储用户身份验证信息的cookie的名称。在这段代码中,通过设置response.set_cookie()方法将用户的身份验证信息存储在名为AUTH_COOKIE_NAME的cookie中。

这段代码中设置AUTH_COOKIE_NAME是为了确保在用户登录成功后,将用户的身份验证信息存储在cookie中,以便在后续的请求中进行身份验证。这样可以方便地获取用户的身份信息,而不需要用户每次都重新登录。

在这段代码中,设置AUTH_COOKIE_NAME是可选的,你可以根据自己的需求来设置cookie的名称。如果你不设置AUTH_COOKIE_NAME,Flask会使用默认的cookie名称。但是,为了更好地管理和识别cookie,建议设置一个有意义的名称。


结语: 作为一名零基础的自学学员,没有人可以请教、没人可以沟通,是我赶上了好时代,有C知道这样的高科技睿智老师秒回复,并且回答精准有内容。放想以前的老程序员们,不知道是问了多少人,将这秒回复换作了多少的孤寂寒窗和弯腰虚心请教。

祝福祖国,CHINA!

  • 23
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

xinzheng新政

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值