• Django 基于ORM的CURD、外键关联,请求的生命周期


    基于ORM进行的CURD

    本质上就是通过面向对象的方式,对数据库的数据进行增、删、改、查。

    这里将会将我们之前所有内容结合到一起,首先确保基于上序操作已经建立好了UserInfo表,那么我们还需要建立几个HTML文件,只需要关注与提交数据有关的标签

    user_list:作为主页使用

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div class="container">
            <div class="row">
                <div class="col-md-8 col-md-offset-2" >
    
                    <h1 class="text-center">用户列表展示</h1>
                    <hr>
                    <a href="/add/" class="btn btn-info" >添加</a>
                    <table class="table table-striped table-bordered">
                        <thread>
                            <tr>
                                <th class="text-center">ID</th>
                                <th class="text-center">username</th>
                                <th class="text-center">password</th>
                                <th class="text-center">gender</th>
                                <th class="text-center">action</th>
                            </tr>
                        </thread>
                        <tbody>
                            {% for foo in user_obj %}
                            	<tr>
                                <td class="text-center" >{{ foo.id }}</td>
                                <td class="text-center" >{{ foo.username }}</td>
                                <td class="text-center" >{{ foo.password }}</td>
                                <td class="text-center" >{{ foo.gender }}</td>
                                <td>
                                    <a href="/edit/?id={{ foo.id }}" class="btn btn-success" style="margin-left: 65px;">修改</a>&nbsp;&nbsp;
                                    <a href="/delete/?id={{ foo.pk }}" class="btn btn-danger ">删除</a>
                                </td>
                            </tr>
                            {% endfor %}
    
                        </tbody>
                    </table>
    
                </div>
            </div>
        </div>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49

    主页已经建立好了,现在我们需要配置路由文件urls.py。根据点击主页的按钮跳转的页面来配置路由。
    在这里插入图片描述

    路由文件urls.py配置如下:
    在这里插入图片描述

    如果前后端不是同一个人开发的话,这些url必须要提前规定好。
    针对主页的视图函数
    在这里插入图片描述


    add.html:用于新增用户的数据页

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div class="container">
            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    <h1 class="text-center">添加用户</h1>
                    <hr>
                    <form action="" method="post">
                        <div class="form-group">
                            username: <input type="text" class="form-control" name="username" placeholder="请输入用户名">
                        </div>
    
                        <div class="form-group">
                            password: <input type="password" class="form-control" name="password" placeholder="请输入密码">
                        </div>
    
                        <div class="form-group">
                            gender: <input type="text" class="form-control" name="gender" placeholder="请输入性别">
                        </div>
    
                        <div class="form-group">
                            <input type="submit" class="btn btn-block btn-success" value="提交">
                        </div>
    
                    </form>
    
                </div>
            </div>
        </div>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    根据上面表单的action可以看出,数据是提交到原地提交post请求的。

    add页面视图函数如下:

    	def add(request):
        if request.method == 'POST':  # 接收用户增加数据发送的post请求
            username = request.POST.get('username')
            password = request.POST.get('password')
            gender = request.POST.get('gender')
    		
    		'数据库中添加数据的'
    		'操作数据库添加数据'
            add_obj=models.UserInfo.objects.create(username=username, password=password, gender=gender)
            '返回的是当前记录的对象'
    		# print(add_obj) # jack
    		# print(add_obj.gender) # male
    		
            return redirect('/user_list/')  # 重定向到主页
    
        return render(request, 'add.html', locals())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    当原地提交post请求的数据会被我们当前视图函数接收到,然后再写入数据库内。

    此时我们就可以从主页点击添加按钮,然后输入完毕后,来检验效果:
    在这里插入图片描述
    在这里插入图片描述


    此时已经达到了数据同步到web页面的效果了,那么我们再来尝试修改。

    edit.html:修改数据的页面

    <!DOCTYPE html>
    <html lang="en">
    <head>
        {% load static %}
        <meta charset="UTF-8">
        <title>Title</title>
        <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.7.1/jquery.min.js"></script>
        <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
        <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
    </head>
    <body>
        <div class="container">
            <div class="row">
                <div class="col-md-8 col-md-offset-2">
                    <h1 class="text-center">修改页面</h1>
                    <hr>
                    <form action="" method="post">
                        <div class="form-group">
                            username: <input type="text" class="form-control" name="username" value="{{ edit_obj.username }}">
                        </div>
                        <div class="form-group">
                            password: <input type="password" class="form-control" name="password" value="{{ edit_obj.password }}">
                        </div>
                        <div class="form-group">
                            gender: <input type="text" class="form-control" name="gender" value="{{ edit_obj.gender }}">
                        </div>
    
                        <div class="form-group">
                            <input type="submit" class="btn btn-block btn-success" value="提交">
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </body>
    </html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    修改页面的套路基本和添加数据页面差不多,观察表单的提交地址是原地址,再根据input元素的name属性值在后端接收数据。

    因为我们在user_list页面内定义了,点击修改按钮,URL地址中还会携带一个用户的id编号,那么我们需要接收这个编号,再根据它来修改用户信息。

    	def edit(request):
        edit_id = request.GET.get('id')  # GET可以获取URL内,问号后面的数据
    
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            gender = request.POST.get('gender')
    	
    	'''数据库中的修改字段语法update userinfo set username='', password='' where id=1;'''
    	# 第一种方式
    		models.UserInfo.objects.filter(pk=edit_id).update(username=username,password=password,gender=gender)
    		使用update这种语句方法不需要save保存
    	
    	# 第二种方式
    		edit_obj = models.UserInfo.objects.filter(id=edit_id).first()  # 获取这个用户对象
    		edit_obj.username = username  # 修改这个用户的姓名
    		edit_obj.password = password  # 修改这个用户的密码
    		edit_obj.gender = gender   # 修改性别
    		edit_obj.save()  # 将修改后的数据保存到数据库
    		
            return redirect('/user_list/')
        return render(request, 'edit.html', locals())
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述
    在这里插入图片描述


    删除自然就不需要什么页面了,在主页点击后就会跳转到一个URL执行一个视图函数,并且这个URL内携带用户的编号,那么基本操作套路就是一样了。

    	def delete(request):
        del_id = request.GET.get('id')
        print(del_id)
        '''数据库中删除字段语法delete from userinfo where id = 1;'''
        models.UserInfo.objects.filter(pk=del_id).delete()  # 删除数据库内,和页面传递过来相同编号的用户
    
        return redirect('/user_list/')  # 重定向到主页,达到一个刷新的效果
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述
    已经达到了我们预期的效果,点击一下删除按钮整行数据。


    那么来总结一下上序所操作所用到的内容。

    	1.查
    		models.User.objects.filter(name=username, pwd=password)
    		如何获取对象 可以使用first()方法 如果没有值会返回None 我们if判断即可
    		
    		obj = User.object.get(id=edit_id) # 获取一个用户对象
    		print(obj.name) # 查询这个用户的name值
    		
    	2.增
    		方法一:
    		models.User.objects.create(name='jack',password=123)
    		# 向数据库写入一条记录,name字段值为jack,password字段值为123
    		方法二:
    		obj = models.User(username=username,password=password,gender=gender)
            obj.save()
    		
    	3.改
    		方法一:
    		models.User.objects.filter(id=1).update(name='tom')
    		方法二:
    		obj = models.User.objects.filter(id=1).first()
    		obj.name = 'tom' # 修改这个用户的name属性值
    		obj.age = 18 # 修改这个用户的age属性值
    		obj.save() # 将修改后的属性值,同步到数据库
    		
    	4.删
    		models.User.objects.filter(id=1).delete()  # 在数据库内删除这个用户
    
    	5.获取所有用户对象
    		obj_all = User.object.all()
    		也可以用获取局部所有变量的方法locals()
    		
    	6.获取指定一个对象
    		obj = User.object.filter('id').first()
    		'filter类比数据库中where的使用'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34

    至此已经完成了基本操作,可以通过面向对象的形式来操作数据库里面的数据,但前提是模型类是已经存在的数据库表,如果不存在则当我们执行迁移时,Django帮助我们自动创建。


    那么如果要导入已经存在的表到我们的模型里面呢。那么我们来了解一下吧!

    导入已存在的表

    在Django内操作数据库是通过模型models.py里面的类,而我们目前只了解怎么通过它创建数据库表,而没有了解过如何使用它导入已经存在数据库内的表。

    其方式有两种:

    • 在模型内,按照表的完整数据结构创建类名、类属性,整体代码如下:
    	class Book(models.Model):
        name = models.CharField(max_length=30, blank=True, null=True)
        price = models.FloatField(blank=True, null=True)
        author = models.CharField(max_length=20, blank=True, null=True)
    
        class Meta:
            db_table = 'book'
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    会发现多出来一个Meta内部类,其作用我们目前不深究,知道此时它的作用即可:通过db_table属性,指定模型类对应的数据库表名。

    • 偷懒方式:通过Django自带的命令inspectdb将数据库内的表名,生成上面这种形式:
      在这里插入图片描述
      在这里插入图片描述

    为什么不执行迁移操作?因为我们并没有向模型类执行:新增表、或者新增、修改字段等操作。


    ORM外键关联

    		关联类型主要分为三类 跟MySQL类型一样
    		一对多
    			外键字段建在多的一方
    		多对多
    			外键字段建在第三张关系表
    		一对一
    			外键字段建在查询频率较高的表中
    		
    		ORM
    			一对多
    		    	外键字段建在多的一方
    		    publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)
    		   	
    		 	多对多
    		    	外键字段可以直接写在某张表中 orm会自动帮你创建第三张表
    		    authors = models.ManyToManyField(to='Authors')
    		   	一对一
    		    	外键字段建在查询频率较高的表中
    		    detail = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    		'''Django1.x版本无需写级联删除级联更新,2.x需要,此处是以2.x展示'''
    		class Book(models.Model):
    	    title = models.CharField(max_length=32)
    	    # 书与出版社是一对多 书是多
    	    publish = models.ForeignKey(to='Publish',on_delete=models.CASCADE)	
    	    	''' 级联删除 注意主键不需要自己去添加ID ORM会自动添加 '''
    	    # 书与作者是多对多
    	    authors = models.ManyToManyField(to='Authors')
    	
    		class Publish(models.Model):
    		    pub_name = models.CharField(max_length=32)
    		
    		class Authors(models.Model):
    		    name = models.CharField(max_length=32)
    		    detail = models.OneToOneField(to='AuthorDetail',on_delete=models.CASCADE)
    		
    		class AuthorDetail(models.Model):
    		    phone = models.BigIntegerField()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    Django请求的生命周期流程图

    	django的生命周期是从用户发送HTTP请求数据到网站响应的过程。
    	整个过程的流程包括:
    	
    	浏览器发送HTTE请求(通过orm) MySI获取数据->wsgiref服务>视图层一>中间件->templates模板层
    	->路由层urls->视图层渲染->视图层views-> 中间件smodels模型层->响应内容给浏览器一>
    	
    	1.首先,用户在浏览器中输入一个url,发送一个GET方法的reguest请求。
    	2.在django中有一个封装了socket的方法模块wsgiref,监听端口接受request请求,初步封装传送到中间件。
    	3.由中间件传输到路由系统中进行路由分发,匹配对应的视图函数。
    	4.将request请求传输到views视图函数中进行逻辑处理。
    	5.调用models中表对象,通过orm操作数据库拿到数据,同时去templates中相应的模板进行渲染
    	6.用response响应传输到中间件,依次处理,响应给浏览器展示给用户
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    在这里插入图片描述
    在这里插入图片描述

    Web服务器网关接口(Python Web Server Gateway Interface,缩写为WSGI)是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。当然我们也可以称它为:WSGI协议

    而wsgiref模块就是python基于WSGI协议开发的服务模块。其支持的并发量不高,但用于我们开发环境足够了,待程序的上线再使用其他的Web服务提高我们运行程序的服务器性能。

  • 相关阅读:
    聊一聊 Monitor.Wait 和 Pulse 的底层玩法
    oracle多变量批量造测试数据
    Android Graphics 显示系统 - 如何模拟多(物理)显示屏?
    从1000篇热门笔记,看小红书的种草趋势
    2.MySQL 安装
    【无标题】
    美团面试官:高并发、任务执行时间短的业务怎样使用线程池?
    buuctf-[WUSTCTF2020]朴实无华
    华中某科技大学校园网疑似dns劫持的解决方法
    [Note] 汉明码与汉明距离的思考
  • 原文地址:https://blog.csdn.net/achen_m/article/details/134340198