Django框架05 /orm单表操作

Posted liubing8

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django框架05 /orm单表操作相关的知识,希望对你有一定的参考价值。

Django框架05 /orm单表操作

昨日内容回顾

  • 模板相关

  • 模板继承(母版继承)

1. 创建一个xx.html页面(作为母版,其他页面来继承它使用)
2. 在母版中定义block块(可以定义多个,整个页面任意位置)
    {% block content %}  <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 -->
    {% endblock %}
3 其他页面继承写法
    {% extends 'base.html' %}  必须放在页面开头
4 页面中写和母版中名字相同的block块,从而来显示自定义的内容
    {% block content %}  <!-- 预留的钩子,共其他需要继承它的html,自定义自己的内容 -->
        {{ block.super }}  #这是显示继承的母版中的content这个快中的内容
        这是xx1
    {% endblock %}
  • 组件

1 创建html页面,里面写上自己封装的组件内容,xx.html
2 新的html页面使用这个组件
    {% include 'xx.html' %}
  • 自定义标签和过滤器

1 在应用下创建一个叫做templatetags的文件夹(名称不能改),在里面创建一个py文件,例如xx.py

2 在xx.py文件中引用django提供的template类,写法
    from django import template
    register = template.Library() #register变量名称不能改
    
    定义过滤器
        @register.filter   参数至多两个
        def xx(v1,v2):
            return xxx
    使用:
        {% load xx %}
        {{ name|xx:'oo' }}
    
    # 自定义标签 没有参数个数限制
    @register.simple_tag
    def huxtag(n1,n2):  #冯强xx  '牛欢喜'
        '''
        :param n1:  变量的值 管道前面的
        :param n2:  传的参数 管道后面的,如果不需要传参,就不要添加这个参数
        :return:
        '''
        return n1+n2

    # inclusion_tag 返回html片段的标签
    @register.inclusion_tag('result.html')
    def res(n1): #n1 : ['aa','bb','cc']

        return {'li':n1 }
    使用:
        {% res a %}
  • 静态文件配置

1 项目目录下创建一个文件夹,例如名为jingtaiwenjianjia,将所有静态文件放到这个文件夹中
2 settings配置文件中进行下面的配置
    # 静态文件相关配置
    STATIC_URL = '/abc/'  #静态文件路径别名

    STATICFILES_DIRS = [
        os.path.join(BASE_DIR, 'jingtaiwenjianjia'),
    ]

3 引入<link rel="stylesheet" href="/abc/css/index.css">
  • url别名和反向解析

写法
    url(r'^index2/', views.index,name='index'),
    url(r'^index2/(d+)/', views.index,name='index'),
反向解析
    后端: from django.urls import reverse
         reverse('别名')  例如:reverse('index') -- /index2/
         带参数的反向解析:reverse('index',args=(10,11,))    -- /index2/10/
    html: {% url '别名' %} -- 例如:{% url 'index' %} -- /index2/
         带参数的反向解析:{% url '别名' 参数1 参数2 %} 例如:{% url 'index' 10 %} -- /index2/10/  <a href='/index2/10/'>hhh</a>
  • url命名空间

路由分发 include

1 在每个app下创建urls.py文件,写上自己app的路径
2 在项目目录下的urls.py文件中做一下路径分发,看下面内容
    from django.conf.urls import url,include
    from django.contrib import admin

    urlpatterns = [
        # url(r'^admin/', admin.site.urls),
        url(r'^app01/', include('app01.urls')),#app01/home/
        url(r'^app02/', include('app02.urls')),
    ]

命名空间namespace

from django.conf.urls import url,include
from django.contrib import admin
urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^app01/',     include('app01.urls',namespace='app01')),#app01/home/
    url(r'^app02/', include('app02.urls',namespace='app02')),
]


使用:
    后端:reverse('命名空间名称:别名') -- reverse('app01:home') 
    hmtl:{% url '命名空间名称:别名' %}  -- {% url 'app01:home' %}

今日内容

orm单表操作 对象关系映射(object relational mapping)

orm语句 -- sql -- 调用pymysql客户端发送sql -- mysql服务端接收到指令并执行

1.orm介绍

django 连接mysql
1 settings配置文件中
    DATABASES = {
        'default': {
            'ENGINE': 'django.db.backends.mysql',
            'NAME': 'orm02',
            'USER':'root',
            'PASSWORD':'123',
            'HOST':'127.0.0.1',
            'PORT':3306,
        }
    }
2 项目文件夹下的init文件中写上下面内容,用pymysql替换mysqldb
    import pymysql
    pymysql.install_as_MySQLdb()

3 models文件中创建一个类

# class UserInfo(models.Model):
#     id = models.AutoField(primary_key=True)
#     name = models.CharField(max_length=10)
#     bday = models.DateField()
#     checked = models.BooleanField()

#BooleanField()不能设置空值

4 执行数据库同步指令,添加字段的时候别忘了,该字段不能为空,所有要么给默认值,要么设置它允许为空 null=True
django连操作数据库默认是不能为空的
# python manage.py makemigrations
# python manage.py migrate

5 创建记录(实例一个对象,调用save方法)
from app01 import models
def query(request):
    # 创建一条记录,增

    new_obj = models.UserInfo(
        id=2,
        name='二狗',
        bday='2019-09-27',
        checked=1,

    )
    new_obj.save()  #翻译成sql语句,然后调用pymysql,发送给服务端  insert into app01_userinfo values(2,'二狗','2019-09-27',1)

    return HttpResponse('xxx')

2.增:

方式1:
    new_obj = models.UserInfo(
        id=2,
        name='二狗',
        bday='2019-09-27',
        checked=1,

    )
    new_obj.save() 
方式2:
    # ret 是创建的新的记录的model对象(重点)
    ret = models.UserInfo.objects.create(
        name='大狗',
        bday='2019-08-07',
        checked=0
    )

    print(ret)  #UserInfo object  大狗
    print(ret.name)  #UserInfo object
    print(ret.bday)  #UserInfo object


3.时间问题

models.UserInfo.objects.create(
        name='大狗2',
        bday=current_date,
        # now=current_date,  直接插入时间没有时区问题
        checked=0
    )
    但是如果让这个字段自动来插入时间,就会有时区的问题,auto_now_add创建记录时自动添加当前创建记录时的时间,存在时区问题
now = models.DateTimeField(auto_now_add=True,null=True)
解决方法:
    settings配置文件中将USE_TZ的值改为False
    # USE_TZ = True
    USE_TZ = False  # 告诉mysql存储时间时按照当地时间来寸,不要用utc时间
使用pycharm的数据库客户端的时候,时区问题要注意

4.删

简单查询:filter()  -- 结果是queryset类型的数据里面是一个个的model对象,类似于列表
    models.UserInfo.objects.filter(id=7).delete()  #queryset对象调用
    models.UserInfo.objects.filter(id=7)[0].delete()  #model对象调用
    

5.改

方式1:update
    # models.UserInfo.objects.filter(id=2).update(
    #     name='peng',
    #     checked = 0,
    #
    # )
    # 错误示例,model对象不能调用update方法
    # models.UserInfo.objects.filter(id=2)[0].update(
    #     name='peng+2',
    #     # checked = 0,
    # )
方式2 
    ret = models.UserInfo.objects.filter(id=2)[0]
    ret.name = 'peng+2'
    ret.checked = 1
    ret.save()
    

更新时的auto_now参数
    # 更新记录时,自动更新时间,创建新纪录时也会帮你自动添加创建时的时间,但是在更新时只有使用save方法的方式2的形式更新才能自动更新时间,有缺陷,放弃
    now2 = models.DateTimeField(auto_now=True,null=True)

6.批量插入 -- bulk_create

    book_list = []
    for i in range(10):
        bk_obj = models.Book(
            name='peng%s'%i,
            addr='北京%s'%i
        )
        book_list.append(bk_obj)

    models.Book.objects.bulk_create(book_list) #批量插入,速度快

7.查询api

  • all()

查询所有结果,结果是queryset类型
ret = models.Books.objects.all()
print(ret)
< QuerySet[ < Books: Books object >, < Books: Books object >, < Books: Books object >] >
  • filter(**kwargs) -- 条件查询

包含与所给筛选条件相匹配的对象,结果也是queryset类型 

查询条件不能匹配到数据时,不会报错,返回一个空的queryset,<QuerySet []>,
如果没有写查询条件会获取所有数据,queryset类型的数据还能够继续调用fitler方法
ret = models.Books.objects.filter(name='linux')
print(ret)
<QuerySet [<Books: Books object>, <Books: Books object>]>

#多条件查询用,隔开--是and的关系
ret = models.Books.objects.filter(name='linux',price=113)
print(ret)
<QuerySet [<Books: Books object>, <Books: Books object>]>
  • get(**kwargs)

返回与所给筛选条件相匹配的对象,不是queryset类型,是model对象,返回结果有且只有一个,如果符合筛选条件的对象超过一个或者没有都会抛出错误。捕获异常try。  Book.objects.get(id=1)

报错:
1. 查不到数据会报错 :Book matching query does not exist.
2. 超过一个就报错 :returned more than one Book -- it returned 13!
ret = models.Books.objects.get(id=5)
print(ret)
Books object
  • exclude(**kwargs) -- 排除

排除的意思,它包含了与所给筛选条件不匹配的对象,没有不等于的操作,用这个exclude,返回值是queryset类型

model对象和queryset对象都可以调用
Book.objects.exclude(id=6),返回id不等于6的所有的对象,Book.objects.all().exclude(id=6),在queryset基础上调用
model对象调用:
ret = models.Books.objects.exclude(name='python')
print(ret)

<QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>]>

queryset对象调用:
ret = models.Books.objects.all().exclude(name='python')
print(ret)

<QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>]>
  • order_by(*field) -- 排序

queryset类型的数据来调用,对查询结果排序,默认是按照id来升序排列的,返回值还是queryset类型

升序排序:
models.Book.objects.all().order_by('price') #默认是按照price升序排列

降序排序:
models.Book.objects.all().order_by('-price') #按照字段降序排列,就写个负号就行了

多条件排序:
models.Book.objects.all().order_by('price','id')是多条件排序,按照price进行升序,price相同的数据,按照id进行升序
ret = models.Books.objects.all().order_by('price')
print(ret)

<QuerySet [<Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>, <Books: Books object>]>
  • reverse() -- 反转

queryset类型的数据来调用,返回值还是queryset类型,对查询结果反向排序,必须是在排序之后才能使用
  • count() -- 计数、统计返回结果的数量

queryset类型的数据来调用,返回数据库中匹配查询(QuerySet)的对象数量。
  • first()

queryset类型的数据来调用,得到的都是model对象,返回第一条记录 Book.objects.all()[0] = Book.objects.all().first(),得到的都是model对象,不是queryset
  • last()

 queryset类型的数据来调用,返回最后一条记录
  • exists() -- 判断返回结果是否有数据

queryset类型的数据来调用,如果QuerySet包含数据,就返回True,否则返回False,效率高

models.Book.objects.all().exists() 
#翻译成的sql是SELECT (1) AS `a` FROM `app01_book` LIMIT 1,
就是通过limit 1,取一条来看看是不是有数据
ret = models.Books.objects.all().exists()
print(ret)

True
#exists() 括号内不能放数据
  • values(*field)

1.queryset类型的数据来调用,返回一个ValueQuerySet——一个特殊的QuerySet,运行后得到的并不是一系列
2.model的实例化对象来调用,而是一个可迭代的字典序列,只要是返回的queryset类型,就可以继续链式调用queryset类型的其他的查找方法,其他方法也是一样的。
#调用values或者values_list的是objects控制器,那么返回所有数据 
ret = models.Books.objects.all().values('name')
print(ret)

<QuerySet [{'name': 'python'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'Go'}]>
ret = models.Books.objects.values('name')
print(ret)

<QuerySet [{'name': 'python'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'python'}, {'name': 'linux'}, {'name': 'Go'}]>
#调用values或者values_list的对象是objects控制器,那么返回所有数据
  • values_list(*field)

它与values()非常相似,它返回的是一个元组序列,values返回的是一个字典序列
ret = models.Books.objects.all().values_list('name')
print(ret)
<QuerySet [('python',), ('python',), ('linux',), ('python',), ('linux',), ('Go',)]>
  • distinct() -- 去重、配置values和values_list来使用

distinct()括号里不能加去重的条件
values和values_list得到的queryset类型的数据来调用,从返回结果中剔除重复纪录
ret = models.Books.objects.values('name').distinct()
print(ret)

<QuerySet [{'name': 'python'}, {'name': 'linux'}, {'name': 'Go'}]>

错误示例:
ret = models.Books.objects.all().distinct()
print(ret)
<QuerySet [<Books: python>, <Books: python>, <Books: linux>, <Books: python>, <Books: linux>, <Books: Go>]>

注意:
不在values()、values_list()后面使用没有意义,因为要是所有的内容全相同才会去重

8.基于双下划线的模糊查询 -- filter双下划线查询

1.Book.objects.filter(price__in=[100,200,300]) #price值等于这三个里面的任意一个的对象

2.Book.objects.filter(price__gt=100)  #大于

3.price__gte=100,大于等于,别写price>100,这种参数不支持

2.Book.objects.filter(price__lt=100)  #小于

3.price__lte=100,小于等于,别写price>100,这种参数不支持

5.Book.objects.filter(price__range=[100,200])  #sql的between and,大于等于100,小于等于200

6.Book.objects.filter(title__contains="python")  #title值中包含python的

7.Book.objects.filter(title__icontains="python") #不区分大小写

8.Book.objects.filter(title__startswith="py") #以什么开头,

9.Book.objects.filter(title__istartswith="py") #不区分大小写

#日期时间
10.Book.objects.filter(pub_date='2012-9-12')
11.Book.objects.filter(pub_date__year=2012)
12.Book.objects.filter(pub_date__ year_ gt='2018') #大于2018年的、2018数字类型也可以
13.Book.objects.filter(pub_date__year='2019' ,pub_ date__ month='8') #某年某月
14.Book.objects.filter(pub_date__ year='2019' ,pub_date__month='8',pub_date__day='01') #某年某月某日

#找字段数据为空的双下滑线
15.models.Book.objects.filter(publish_date__isnull=True) #这个字段值为空的那些数据

9.总结

总结1

1.新增字段(注意设置可以为空或者设置默认值)
2.UTC时间格式格林尼治时间
3.model对象不能调用update方法

orm1 > settings.py

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'orm1',
        'HOST':'127.0.0.1',
        'PORT':3306,
        'USER':'root',
        'PASSWORD':'123'
    }
}


# USE_TZ = True
#告诉mysql默认使用当地时间
USE_TZ = False

#不是跨时区的应用,不需要考虑时区问题,就将这个值改为False,mysql是对时区不敏感,django往mysql里面出数据的时候,如果这里的值为True,那么将让mysql强制使用UTC时间,那么我们存储进入的时间,当你查询的时候,你就会发现,时间晚了8小时,也就是说你存时间的时候被改为了UTC时间,本地是东八区,比UTC时间多8小时

orm1 > __init__.py

import pymysql
pymysql.install_as_MySQLdb()

models.py

from django.db import models

# Create your models here.
class Userinfo(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=16)
    register_time = models.DateField(null=True)  
    #auto_now_add=True  修改记录不会改变
    update_time = models.DateTimeField(auto_now=True,null=True) 
    #auto_now=True,  修改记录用方式一/update不会改变、用方式二/ret.save()会更新
    checked = models.BooleanField(default=0)

    def __str__(self):
        return self.name

views.py

from django.shortcuts import render,HttpResponse

# Create your views here.
from app01 import models
from datetime import datetime


# def query(request):
    #创建记录
    #方式一
    # current_time = datetime.now()
    # new_obj = models.Userinfo(
    #     id = 1,
    #     name = 'peng'
    # )
    # new_obj.save()
    
    #方式二
    # ret =models.Userinfo.objects.create(
    #     name='wang',
    #     register_time='2019-8-8',
    #     update_time='2019-8-10 12:12:12',
    #     checked=1,
    #
    # )
    # ret = models.Userinfo.objects.filter(name='wang')
    # print(ret)
    #返回一个

    #删除
    # ret = models.Userinfo.objects.filter(id=7)[0].delete()
    # print(ret)
    #将符合条件的第一条记录删除
    
    # ret = models.Userinfo.objects.filter(id=7).delete()
    # print(ret)
    #将符合条件的所有记录删除
    #注意:filter搜索出来的是queryset类型的列表:queryset<[对象1,对象2,对象3]>
    
    #修改
    #方式一
    # models.Userinfo.objects.filter(id=1).update(
    #     name='peng',
    #     checked=1,
        # register_time = '2019-1-1',
        # update_time = '2020-06-03',
    # )

    # 方式二
    # ret = models.Userinfo.objects.filter(id=1)[0]
    # ret.name='zhao'
    # ret.save()
    # return HttpResponse('完啦')
    #注意:model对象不能调用update()方法

总结2

1.带有a标签属性的button按钮

<td>
    <a href="" class="btn btn-warning">编辑</a>
    <a href="" class="btn btn-danger"> 删除</a>
</td>

2.number类型的input标签

<div class="form-group">
    <label for="price"> 价格</label>
    <input type="number" class="form-control" id="price" name="price">
</div>

3.date类型的input标签

<div class="form-group">
    <label for="publish_ datel">出版8期</label>
    <input type="date" class="form-control" id="publish_ date" placeholder="Password">
</div>

4.重定向路径已经取别名后,重定向后面写别名就行

return redirect('showbooks')

5.**在接收到get或者post提交数据后的应用

if request.method == 'POST':
    print(request. POST)
    # title = request.POST.get( 'title')
    # price = request. POST.get( 'price')
    # publish_ date = request. POST. get( 'publish_ date')
    # publish = request. POST.get( 'publish')
    data = request.POST.dict()  #将querydict类型转换成dict类型
    models.Book.objects.create(
    # title=title,
    # price=price,
    # publish_ date=publish_ date,
    # publish=publish 
    **data
    #{'title': ['asdf '],'price':. ['212.'], 'publish date': ['2019-09-12'],. 'publish': ['asdf ']}
    return redirect('showbooks')

dic = {"key":1,"key1":34}
**dic --- "key"=1,"key1"=34     

6.pk代替id

方式一:别名的反向解析、id字段可以用pk来代替(primary_key)
<td>
    <a href="" class=btn btn-warning">编辑</a>
    <a href="{% url 'delete_ book' book:pk %}" class="btn btn-dangerl>删除</a>
</td>

方式二:
<a href="/remove_books/{{ i.id }}">
    <button type="submit" class="btn btn-danger">
        <span class="glyphicon glyphicon-remove" aria-hidden="true"></span>删除
    </button>
</a>

以上是关于Django框架05 /orm单表操作的主要内容,如果未能解决你的问题,请参考以下文章

Django基础之django ORM单表操作

Django基础之django ORM单表操作

Django开发:(3.1)ORM:单表操作

Django模型层:单表操作

Django 数据库ORM操作 - 单表的创建,增加,删除,更改和查询

Django 基础 之ORM简介与单表操作