Django ORM

Django ORM


orm不会创建库,只能创建到表的层面。需要自己手动敲命令创建库

1、创建模型表

ORM:"""对象关系映射"""
作用:能够让一个不会用sql语句的小白,也能通过python面向对象的代码简单快捷的操作数据库
不足之处:封装成都太高,有时候sql效率偏低,需要自己写sql语句


类				     表
	
对象					记录

对象属性			记录某个字段对应的值
  1. 第一步:先去应用下的models.py中书写一个模型类
# 应用下的models.py

class User(models.Model):
    # id int primary key auto_increment
    id = models.AutoField(parmary_key=True)
    # username varchar(32)
    username = models.CharField(max_length=32)
    # passwrod int
    password = models.IntegerField()
   

************************************2.数据库迁移命令**************************************************
 python manage.py makemigrations  将操作记录记录到小本本上(migrations文件夹)
 python manage.py migrate   将操作真正同步到数据库中
********************************************************************************************************

#应用下的modles.py
from django.db import models


# Create your models here.

class User(models.Model):
    # id int primary key auto_increment
    id = models.AutoField(primary_key=True,verbose_name='主键')
    # username varchar(32)
    username = models.CharField(max_length=32, verbose_name='用户名')

    """
    CharField必须指定max_length参数,不指定会直接报错
    verhose_name该参数是所有字段都有的,就是用来对字段的解释
    """
    # passwrod int
    password = models.IntegerField(verbose_name='密码')


class Author(models.Model):
    # 由于一张表中必须要有一个主键字段,并且一般情况下都叫id字段
    # 所以orm当不定义主键字段的时候,orm会自动创建一个名为id字段
    # 也就意味着后续再创建模型表的时候,如果主键字段名没有额外的叫法,那么主键字段可以省略不写

    username = models.CharField(max_length=32)
    password = models.IntegerField()
  1. 第二步:数据库迁移命令
 python manage.py makemigrations   #⽣成数据库迁移⽂件

image-20221022111412105

应用文件夹下的migrations文件夹下多了一个0001._initial.py日志文件

image-20221022111604561

 python manage.py migrate  #⽣成数据库表 
#将操作真正同步到数据库中

image-20221022112226431

数据库迁移的两条命令输入完成后,此时数据库中会出现很多张表

image-20221022115814598

一个Djanog项目可以有多个应用,那么多个应用之间可能会出现表名冲突的情况,那么加上前缀就可以完全避免冲突

image-20221022120128278

"""
只要修改了models.py中跟数据库相关的代码,就必须重新执行数据迁移的两条命令
"""

2、字段的增删改查

2. 1、 字段的增加
"""
1.可以在终端内直接给出默认值
	age=models.IntegerField(verbose_name='年龄')
2.该字段可以为空
	 info = models.CharField(max_length=32,verbose_name='信息', null=True)
3.直接给字段设置默认值 
    hobby = models.CharField(max_length=32,verbose_name='爱好', default='play')
"""

终端内直接给默认值操作如下图

image-20221022124444920

切记只要动了数据库相关的代码就必须执行数据库迁移的两条命令

******************************************************************
python manage.py makemigrations
python manage.py migrate
******************************************************************
2. 2、字段的修改
"""直接修改代码然后执行数据库迁移的两条命令即可"""

image-20221022125639587

2. 3、字段的删除
直接注释掉对应的字段代码,然后执行数据迁移的两条命令即可
执行完毕后,字段对应的数据都没有了

"""
在操作models.py时,一定要细心

执行迁移命令之前一定要检查一下代码
"""

3、数据的增删改查

3. 1、 查数据
#views.py
def userlist(request):
    # 查询出user用户表里的所有数据.
    # 方式一
    # data = models.User.objects.filter()
    # print(data)

    # 方式二:
    user_queryset = models.User.objects.all()
    
    return render(request, 'userlist.html', locals())
# views.py
from app02 import  models

#res=models.User.objects.filter(username=username)
# user_obj=res[0]

"""
返回值先看成是一个列表套数据对象的格式
也支持索引取值,切片操作,但是不支持负数索引
同样也不推荐使用索引方式取值
"""

 # 下面这条代码等价于 select * from user where username='zhao';
user_obj=models.User.objects.filter(username=username).first()

print(user_obj)
print(user_obj.username)
print(user_obj.password)


filter括号内可以携带多个参数,参数与参数之间默认是and关系
可以把filter联想成MySQL中的where

user_obj=models.User.objects.filter(username=username,password=password).first()
#select * from user where username='zhao' and password=132;

登录功能

# views.py

def login(request):
   
    if request.method == 'POST':
        
        # 获取用户的用户名和密码,然后利用orm操作数据库,校验数据是否正确
        username = request.POST.get('username')
        password = request.POST.get('password')
        # 去数据库中查询数据
        from app02 import models
        # select * from user where username='zhao';
        user_obj = models.User.objects.filter(username=username).first()

        # < QuerySet[ < User: Userobject(1) >] >  [数据对象1,数据对象2......]
        # print(res)
        
        # user_obj=res[0]
        # print(user_obj)
        # print(user_obj.username)
        # print(user_obj.password)
        if user_obj:
            # 比对密码是否一致
            if password == user_obj.password:
                return HttpResponse('登录成功')
            else:
                return HttpResponse('密码错误')
        else:
            return HttpResponse('用户不存在')




    return render(request, 'login.html')
3. 2 、增加数据
#第一种方法  create()
        from app02 import models
        res = models.User.objects.create(username=username, password=password)
        # 返回值就是当前被创建的对象本身
        
        print(res, res.username, res.password)
        
        
 # 第二种方法  对象.save()
        from app02 import models
   		 #生成一个类对象
        user_obj = models.User(username=username, password=password)
        #对象调用save方法
        user_obj.save()#保存数据

注册功能

# views.py
def register(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        # 直接获取用户数据存入数据库
        from app02 import models
        res = models.User.objects.create(username=username, password=password)
        # 返回值就是当前被创建的对象本身
        print(res, res.username, res.password)

    # 先给用户返回已给注册页面
    return render(request, 'register.html')
3. 3 、修改数据
  # 修改数据方式一
        # 获取到用户想要删除 的数据id值
   	 	delete_id = request.GET('user_id')
     	models.User.objects.filter(id=edit_id).update(username=username, password=password)
        """
        将filter查询出来的列表中所有对象全部更新         批量更新
        只修改被修改的字段
        """
  # 修改数据方式二
		edit_obj = models.User.objects.filter(id=edit_id).first()
        edit_obj.username = username
        edit_obj.password = password
        edit_obj.save()
        """
        方式二当字段特别多的时候效率很低
        从头到尾将数据的所有字段全部更新一遍,无论该字段是否被修改
        """
3. 4、 删除数据
# 删除用户
def delete_user(request):
    # 获取到用户想要删除 的数据id值
    delete_id = request.GET('user_id')

    # 直接去数据库找到对应的数据删除即可
    models.User.objects.filter(id=delete_id).delete()
    """
    批量删除
    """
    #跳转到展示页面
    return redirect('/userlist/')

真正删除数据是要有二次确认的,
删除数据内部其实不是真正的删除,我们会给数据添加一个标识字段用来标识当前数据是否被删除,如果删除了,仅仅是将一个字段修改了一个状态
3.5、示例
#先将数据库中的数据全部展示到前端,然后给一个数据两个按钮,一个编辑,一个删除

#编辑功能
	#点击编辑按钮,朝后端发送编辑数据的请求
   """如何告诉后端用户想要编辑哪条数据?
   		将编辑按钮所在的那一行数据的主键值发送给后端
   			利用url问号后面携带参数的方式
   """ 
    #后端查询出用户想要编辑的数据对象,展示到前端页面,供用户查看和编辑
 #删除功能
	将数据从前端页面删除
  • 数据展示到前端页面
<!-- userlist.html---> 

<h2 class="text-center">数据展示</h2>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-offset-2">
            <table class="table table-striped table-hover ">
                <thead>
                <tr>
                    <th>ID</th>
                    <th>username</th>
                    <th>password</th>
                    <th class="text-center">action</th>
                </tr>
                </thead>
                <tbody>
                {% for user_obj in user_queryset %}
                    <tr>
                        <td>{{ user_obj.id }}</td>
                        <td>{{ user_obj.username }}</td>
                        <td>{{ user_obj.password }}</td>
                        <td class="text-center">
                            <a href="/edit_user/?user_id={{ user_obj.id }}" class="btn btn-primary btn-xs">编辑</a>
                            <a href="/delete_user/user_id={{ user_obj.id }}" class="btn btn-danger btn-xs">删除</a>
                        </td>
                    </tr>

                {% endfor %}

                </tbody>
            </table>
        </div>
    </div>
</div>
# views.py

# 展示用户列表

def userlist(request):
    # 查询出user用户表里的所有数据.
    # 方式一
    # data = models.User.objects.filter()
    # print(data)

    # 方式二:
    user_queryset = models.User.objects.all()
    
    return render(request, 'userlist.html', locals())
  • 编辑用户数据
<!-- edit_user.html--->

<h1 class="text-center">编辑</h1>
<div class="container">
    <div class="row">
        <div class="col-md-offset-2 col-md-8">
            <form action="" method="post">
                <p>username:<input type="text" name="username" class="form-control" value="{{ edit_obj.username }}"></p>
                <p>password:<input type="password" name="password" class="form-control" value="{{ edit_obj.password }}"></p>
                <input type="submit" class="btn btn-info btn-block" value="编辑">

            </form>
        </div>
    </div>
</div>
#views.py
from app03 import models
def edit_user(request):
    # 获取url问号后面的参数
    edit_id = request.GET.get('user_id')
    # 查询当前用户想要编辑的数据对象
    edit_obj = models.User.objects.filter(id=edit_id).first()

    if request.method == 'POST':
        username = request.POST.get('username')
        password = request.POST.get('password')

        # 去数据库中修改对应的数据内容

        # 修改数据方式一
        # models.User.objects.filter(id=edit_id).update(username=username, password=password)
        """
        将filter查询出来的列表中所有对象全部更新         批量更新
        只修改被修改的字段
        """
        # 修改数据方式二
        edit_obj.username = username
        edit_obj.password = password
        edit_obj.save()
        """
        方式二当字段特别多的时候效率很低
        从头到尾将数据的所有字段全部更新一遍,无论该字段是否被修改
        """

        # 跳转到数据的展示页面
        return redirect('/userlist/')

    # 将数据展示到页面上
    return render(request, 'edit_user.html', locals())


  • 删除数据
<!-- userlist.html--->  

<a href="/delete_user/user_id={{ user_obj.id }}" class="btn btn-danger btn-xs">删除</a>
#views.py
# 删除用户
def delete_user(request):
    # 获取到用户想要删除 的数据id值
    delete_id = request.GET.get('user_id')

    # 直接去数据库找到对应的数据删除即可
    models.User.objects.filter(id=delete_id).delete()
    """
    批量删除
    """
    #跳转到展示页面
    return redirect('/userlist/')

4、orm中创建表关系(外键

"""
表与表关系
	一对多
		models.ForeignKey(to='Publish', on_delete=models.CASCADE)
	多对多
		models.ManyToManyField(to='Author')
	一对一
		models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)

判断表关系方式:换位思考

"""
# 创建表关系, 先将基表创建出来,然后在添加外键字段
class Book(models.Model):
    title = models.CharField(max_length=32, verbose_name='书名')
    price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='价格')
    # 小数总共8位,小数点后占2位

    """
    图书和出版社是一对多,并且书是多的一方,所以外键字段放在书表里面
    """
    publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)  # 默认就是与出版社表的主键字段做外键关联
    """
    如果字段对应的是ForeignKey,那么orm会自动在字段的后面加_id
    如果自己手动的加了_id,那么orm还是会在后面加_id
    
    """

    """
    图书 和作者 是多对多的关系,外键字段建在任意一方即可,推荐建在查询频率较高的一方,
    
    """
    authors = models.ManyToManyField(to='Author')
    """
    authors是一个虚拟字段,主要是用来告诉orm,书籍表与作者表是多对多的关系
    让orm自动创建第三章关系表
    """


class Publish(models.Model):
    name = models.CharField(max_length=32, verbose_name='出版社')

    addr = models.CharField(max_length=32, verbose_name='地址')


class Author(models.Model):
    name = models.CharField(max_length=32, verbose_name='作者名')
    age = models.IntegerField(verbose_name='年龄')

    """
    
    作者与作者详情是一对一的关系,外键字段建立在任意放一方都可以,但是建议建立在查询频率较高的地方
    
    """
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE)  # 级联删除
    """
    OneToOneFiel也会自动给字段加_id后缀,不需要自己加
    """


class AuthorDetail(models.Model):
    phone = models.BigIntegerField(verbose_name='电话')
    addr = models.CharField(max_length=32, verbose_name='作者地址')

    
    
"""

orm中如何定义表关系

publish = models.ForeignKey(to='Publish', on_delete=models.CASCADE)
author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.CASCADE) 
authors = models.ManyToManyField(to='Author')



ForeignKey与OneToOneField会自动在字段后面加_id后缀
"""

5、多对多关系的三种创建方式

  • 全自动
#全自动:利用orm自动帮我们创建第三张关系表
class Book(models.Model):
    name=models.CharField(max_length=32)
    authors=models.ManyToManyField(to='Author')
class Author(models.Model):
    name=models.CharField(max_length=32)

    """
   优点:代码不需要自己写,还支持orm提供的第三张关系表的方法:(add,remove,clear,set)
   缺点:第三张关系表扩展性极差,(不能额外的添加字段)
    """
    


  • 纯手动
class Book(models.Model):
    name=models.CharField(max_length=32)
    
class Author(models.Model):
    name=models.CharField(max_length=32)
    
class BookToAuthor(models.Model):
    book=models.ForeignKey(to='Book',on_delete=models.CASCADE)
    author=models.ForeignKey(to='Author',on_delete=models.CASCADE)
    
    """
    优点:第三张关系表完全取决于自己进行额外的拓展
    缺点:需要写代码较多,不能使用orm提供的简单方法:(add,remove,clear)
    
    
    不建议使用该方式
    """
  • 半自动
class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(to='Author',
                                     through='BookToAuthor',
                                     through_fields=('book', 'author')
                                     )


class Author(models.Model):
    name = models.CharField(max_length=32)


class BookToAuthor(models.Model):
    book = models.ForeignKey(to='Book', on_delete=models.CASCADE)
    author = models.ForeignKey(to='Author', on_delete=models.CASCADE)

    
   """through_fields字段先后顺序:
        第三张表查询对应的表,需要用到哪个字段就把哪个字段放前面,
        也就是说,当前表是谁,就把对应的关联字段放前面
        
        
        
        
        半自动可以使用orm的正反向查询,但是没有办法使用add,remove,clear,set这四个方法
    """


# 总结:
    只需要掌握全自动和半自动,半自动扩展性高,一般都采用半自动,
posted @ 2022-12-12 15:39  ExpiredSaury  阅读(40)  评论(0编辑  收藏  举报