天天看点

Django学习笔记:模型层之ORM

一、添加表记录

# 方式一:
    book=Book(title="GO",price="99",pub_date="2018-12-31",publish="人民出版社")
    book.save()
    print(book.nid)  # 返回值就是 Book 生成的对象

# 方式二:
    # 注意:create 方法的返回当前生成的表记录对象
    book = Book.objects.create(title="GO",price="99",pub_date="2018-12-31",publish="人民出版社")
           

注:关于create和save方法2种方式的不同,具体详见原文链接:

https://blog.csdn.net/weixin_42134789/article/details/80203270

深入理解Django创建对象的create和save方法:

Django的模型(Model)的本质是类,并不是一个具体的对象(Object)。当你设计好模型后,你就可以对Model进行实例化从而创建一个一个具体的对象。Django对于创建对象提供了2种不同的save与create方法,我们来仔细分析下这两种方式有什么不同。

用save方法创建对象

用save方法创建一个名叫john的具体对象,我们可以这么做。记住你只有用了save()方法后,Django才会将这个对象的信息存储到数据库中。

用create方法创建对象

正因为用save方法创建对象有2步,而且编程人员容易忘记加上save(),Django提供了一个更便捷的create方法,如下。如果你使用create方法,无需再加上save()。create方法不仅创建了新的对象,而且直接将信息存储到数据库里。

save与create方法比较:

create只能用于创建新的对象,在数据库层总是执行insert的操作。save不仅用于创建新的对象,也能用于更新对象的现有数据,在数据库层总是先执行update,找不到具体对象后再执行insert的操作。对于创建全新的对象,两者都可以。如果更新已有对象信息,只能用save()方法。

User自带的create_user方法

如果你要Auth自带的User模型创建新对象,你需要使用create_user方法,而不是create方法,如下所示。create_user方法很有用,自动会给密码加Hash。

————————————————

版权声明:本文为CSDN博主「大江狗」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/weixin_42134789/article/details/80203270

二 、查询表记录

1、查询API:

all(): 查询所有结果
filter(**kwargs): 包含了与所给筛选条件相匹配的对象
get(**kwargs): 返回与所给筛选条件相匹配的对象,返回结果有且只有一个
exclude(**kwargs): 包含了与所给筛选条件不匹配的对象
order_by(*field): 对查询结果排序
reverse(): 对查询结果反向排序
order_by(*field): 对查询结果排序
count(): 返回数据库中匹配查询(QuerySet)的对象数量。
first(): 返回第一条记录
last(): 返回最后一条记录
exists(): 如果QuerySet包含数据,就返回True,否则返回False
distinct(): 从返回结果中剔除重复记录
"""以下演示单表查询的代码"""

    # 1、all(): 查询所有结果 返回值是 queryset
    ret = Book.objects.all()
    print(ret)  # <QuerySet [<Book: Book object (22)>, <Book: Book object (23)>, <Book: Book object (24)>, <Book: Book object (25)>]>

    # 2、filter(): 查询包含了与所给筛选条件相匹配的对象
    ret = Book.objects.filter(title="JAVA",price="88")  # 多条件查询 当一个条件不满足时,显示为空- “且”的关系。<QuerySet []>
    print(ret)  # <QuerySet [<Book: Book object (23)>]>

    # 3、get(): # 查询结果有且只有一个才执行。
    ret = Book.objects.get(price="88")  # 报错:get() returned more than one Book -- it returned 3! 如果符合筛选条件的对象超过一个或者没有都会抛出错误。
    ret = Book.objects.get(title="JAVA")  # get() 返回与所给筛选条件相匹配的对象,返回结果有且只有一个
 	print(ret.title)  # JAVA

    # 4、first() last()  # 返回第一条记录 model对象
    ret = Book.objects.all()[0]
    ret = Book.objects.all().first()
    ret = Book.objects.all().last()

    # 5、exclude()  # 返回值是 queryset
    ret = Book.objects.exclude(price=88)
    print(ret)  # <QuerySet [<Book: Book object (25)>]>

    # 6、order_by  # 排序,返回值是 queryset
    ret = Book.objects.all().order_by("price")  # 按价格升序
    ret = Book.objects.all().order_by("-price")  # 按价格降序

    # 7、count()  # 计数,返回数据库中匹配查询(QuerySet)的对象数量。返回值是 int 类型
    ret = Book.objects.all().count()
    print(ret)  # 4

    # 8、reverse()  # 对查询结果反向排序
    Book.objects.all().order_by("price").reverse()

    # 9、exists()  # 逻辑判断!如果QuerySet包含数据,就返回True,否则返回False
    is_exist = Book.objects.all().exists()  # b'SELECT (1) AS `a` FROM `app01_book`  LIMIT 1'; args=()
    if is_exist:
        print("OK")

    # ------------------------------------------------------------------------------------------------
    # 重点!!
    # 10、values()  # 返回值是 queryset
    ret = Book.objects.all().values("title","price")   # 返回一个ValueQuerySet——一个特殊的QuerySet 列表套字典 [{...}]
    print(ret)  # <QuerySet [{'title': 'python', 'price': Decimal('99.00')}, {'title': 'JAVA', 'price': Decimal('88.00')}, {'title': 'JavaScript', 'price': Decimal('88.00')}, {'title': 'GO', 'price': Decimal('66.00')}]>

    # 11、values_list()  # 返回值是 queryset

    # 12、distinct()  # 从返回结果中剔除重复记录,返回值是 queryset
    ret = Book.objects.all().distinct()  # 针对这种 all()再调用 distinct 没有意义,因为对象包含了主键 nid,不可能重复!
    ret = Book.objects.all().values("title").distinct()  # 总共5本书,去重后结果是4本。配合匹配 values 去重功能才会显现
    print(ret)  # <QuerySet [{'title': 'python'}, {'title': 'JAVA'}, {'title': 'JavaScript'}, {'title': 'GO'}]>
           

2、基于双下划线的模糊查询:

"""查询价格"""
    ret = Book.objects.filter(price__in=[88,99]).values("price")  
    # 查询价格区间在 88~99 的书籍
    ret = Book.objects.filter(price__lt=100).values("price")  
    # 查询价格小于等于 100 的书籍
    ret = Book.objects.filter(price__gt=100).values("price")  
    # 查询价格大于等于 100 的书籍
    ret = Book.objects.filter(price__gte=80).values("price")  
    # 查询价格大于等于 88 的书籍
    
    """查询名称以 “J” 开头的"""
    ret = Book.objects.filter(title__startswith="J").values("title")  
    # 查询结果区分大小写
    ret = Book.objects.filter(title__istartswith="j").values("title")  
    # 查询结果不区分大小写
    ret = Book.objects.filter(title__contains="S").values("title")  
    # 查询结果只要包含S的,区分大小写
    ret = Book.objects.filter(title__icontains="S").values("title")  
    # 查询结果不区分大小写

    """查询时间:2018年发布的"""
    ret = Book.objects.filter(pub_date__year=2018).values("title")  
    # 仅查询发布年份
    ret = Book.objects.filter(pub_date__year=2018,pub_date__month=10).values("title")  
    # 查询2018年10月发布的
    print(ret)  
    # <QuerySet []> 输出为空的原因:遇到时间偏差,因为时间模块出问题,需要到 settings.py 中修改 :USE_TZ = True 改为 False
    #  <QuerySet [{'title': 'C++'}]>  这是修改以后的输出,问题解决!
           

注意:

最后查询年月打印输出为空的原因:遇到时间偏差,因为时间模块出问题,需要到 settings.py 中修改 :USE_TZ = True 改为 False

<QuerySet [{‘title’: ‘C++’}]> 这是修改以后的输出,问题解决。

三、删除表记录

删除方法就是 delete()。它运行时立即删除对象而不返回任何值。例如:

也可以一次性删除多个对象。每个 QuerySet 都有一个 delete() 方法,它一次性删除 QuerySet 中所有的对象。

示例:下面的代码将删除 book_price 是 123 的 Book 对象:

# 以下2种写法都可以
Book.objects.filter(price=123).delete()

Book.objects.filter(price=delete_book_price).delete()
           

四、修改表记录

update()方法对于任何结果集(QuerySet)均有效,这意味着你可以同时更新多条记录update()方法会返回一个整型数值,表示受影响的记录条数。

其实以上只单纯演示语法,它需要在浏览器中输入对应的值才能执行操作。相信没有人愿意这样做。在下面的案例练习中会结合HTML页面按钮,来实现增、删、改、查的操作。

练习:图书管理系统

urls.py:

from django.contrib import admin
from django.urls import path, re_path
from app01 import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('books/', views.books, name="books"),
    path('books/add/', views.addbook),
    # re_path('books/delete/(\d+)', views.delbook, name="books"),  # 这里仅用于删除!
    re_path('books/delete/(\d+)', views.delbook),  # name="books"是唯一的,就不能再用了!
    re_path('books/edit/(\d+)', views.editbook),
]
           

app01\views.py:

from django.shortcuts import render,HttpResponse,redirect
from app01.models import Book
from django.urls import reverse

def addbook(request):
	"""添加功能"""
    if request.method == "POST":
        # 获取用户提交的数据
        print(request.POST)
        # ---------------------------------------------------------------------------------------
        # 方式 1 :逐个取主键来创建数据,比较麻烦,特别是数据量大的情况下。
        title = request.POST.get("title")
        price = request.POST.get("price")
        pub_date = request.POST.get("pub_date")
        publish = request.POST.get("publish")
        book = Book.objects.create(title=title,price=price,pub_date=pub_date,publish=publish)
        # ---------------------------------------------------------------------------------------
        # 方式 2 :先转成字典,再进行添加操作,相对于上面的方式1,方便许多!但是不直观!
        # data = request.POST.dict()
        # del data["csrfmiddlewaretoken"]
        # book = Book.objects.create(**data)
        # ---------------------------------------------------------------------------------------
        return redirect(reverse("books"))
    else:
        return render(request,"addbook.html")

def books(request):
	"""查询功能"""
    book_list = Book.objects.all() # 查所有
    # print(book_list) # [obj1, obj2, obj3...]
    # print(book_list[0].title)
    return render(request,"books.html",{"book_list":book_list})

def delbook(request,delete_book_id):
	"""删除功能"""
    Book.objects.filter(nid=delete_book_id).delete()
    return redirect(reverse("books"))

def editbook(request,edit_book_id):
    """修改功能"""
    # 以下2行代码只是演示了2种功能,查询与编辑同时进行
    # Book.objects.filter(nid=edit_book_id).update(price=88,title="Django")  # 只要输入符合的ID,都会修改为:price=88,title="Django"
    # Book.objects.filter(price=88).update(publish="工业出版社")  # 只要输入符合的 price,都会修改为:publish="工业出版社"
    
    if request.method == "GET":  # GET请求
        edit_book = Book.objects.filter(nid=edit_book_id)[0]
        return render(request, "editbook.html",{"edit_book":edit_book})
        
    else:  # POST请求
        title = request.POST.get("title")
        price = request.POST.get("price")
        pub_date = request.POST.get("pub_date")
        publish = request.POST.get("publish")
        Book.objects.filter(nid=edit_book_id).update(title=title, price=price, pub_date=pub_date, publish=publish)

    return redirect("/books/")
           

models.py:

from django.db import models
# 存放表结构

class Book(models.Model):
    nid = models.AutoField(primary_key=True) #自动递增主键
    title = models.CharField(max_length=32)
    price = models.DecimalField(max_digits=8, decimal_places=2) #999999.99
    pub_date = models.DateTimeField() #"2019-10-01"
    publish = models.CharField(max_length=32)