Django ORM
Django ORM
目录
orm不会创建库,只能创建到表的层面。需要自己手动敲命令创建库
1、创建模型表
ORM:"""对象关系映射"""
作用:能够让一个不会用sql语句的小白,也能通过python面向对象的代码简单快捷的操作数据库
不足之处:封装成都太高,有时候sql效率偏低,需要自己写sql语句
类 表
对象 记录
对象属性 记录某个字段对应的值
- 第一步:先去应用下的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()
- 第二步:数据库迁移命令
python manage.py makemigrations #⽣成数据库迁移⽂件
应用文件夹下的migrations文件夹下多了一个0001._initial.py日志文件
python manage.py migrate #⽣成数据库表
#将操作真正同步到数据库中
数据库迁移的两条命令输入完成后,此时数据库中会出现很多张表
一个Djanog项目可以有多个应用,那么多个应用之间可能会出现表名冲突的情况,那么加上前缀就可以完全避免冲突
"""
只要修改了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')
"""
终端内直接给默认值操作如下图
切记,只要动了数据库相关的代码就必须执行数据库迁移的两条命令
******************************************************************
python manage.py makemigrations
python manage.py migrate
******************************************************************
2. 2、字段的修改
"""直接修改代码然后执行数据库迁移的两条命令即可"""
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这四个方法
"""
# 总结:
只需要掌握全自动和半自动,半自动扩展性高,一般都采用半自动,
本文来自博客园,作者:ExpiredSaury,转载请注明原文链接:https://www.cnblogs.com/saury/p/16976236.html