django的模型层

model(数据库模型)基于ORM来操纵的。

ORM是一个框架,是用来通过Python的类来操纵数据库的表。

数据库表与表之间的关系(两张表):

  以员工信息表与部门信息表为例。表之间通过外键联系。不依赖于任何表的那张表是主表,所有员工信息表是部门信息表的子表。

  • 一对一:详细的信息分为两部分。
  • 一对多:以员工信息表与部门信息表为例。
  • 多对多:以图书表与作者表为例。需要建立第三张表来描述它们的关系!

一、django中ORM的概念

ORM----->object relation mapping。对象关系映射表。

Python的类:

  1. 创建一个类就是创建一个数据库表。
  2. 类里面的属性就是数据库表里的字段。
  3. 实例这个类就可以得到一个对象,一个对象就是一条记录。对象可以调用里面的属性,记录也可以被取出来。

为什么django要用ORM?

  1、sql语句的性能问题年轻程序员并不知道。

  2、使用方便。

如果想看每一条语句翻译成sql是什么,在配置文件settings.py里面加入LOGGING配置文件就可以了:

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'handlers': {
        'console':{
            'level':'DEBUG',
            'class':'logging.StreamHandler',
        },
    },
    'loggers': {
        'django.db.backends': {
            'handlers': ['console'],
            'propagate': True,
            'level':'DEBUG',
        },
    }
}

二、数据库的配置

1、django默认支持sqlite,mysql,Oracle,postgresql数据库。

  sqlite是django默认的数据库,特点是小跟简单。

2、在django的项目中更改mysql数据库。在配置文件settings.py中操作如下:

注意:一定要自己先手动创建好数据库!

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',     数据库引擎
        'NAME': 'books',      数据库名字
        'USER': 'root',       数据库的用户名
        'PASSWORD': '121352', 数据库的密码
        'HOST': '',  数据库主机,IP地址,留空默认为localhost
        'PORT': '3306',       端口号
    }
}

3、因为django默认的驱动引擎是MySQLdb,所以还需要在项目名文件下的__init__.py,里面写入:就是告诉django驱动引擎替换成pymysql。

import pymysql
pymysql.install_as_MySQLdb()

三、在django项目中创建一张表

 models.py:

from django.db import models

# Create your models here.

# 创建一张书籍的表,但是这个类必须继承models.Model类,这样django才知道这是一张表。
class Books(models.Model):       #create table book (
    # 创建字段,字段的数据类型(约束性条件)
    name = models.CharField(max_length=16)       #name varchar(16),
    price= models.FloatField()                     #price float,
    pub_date = models.DateField()                  #pub_date 

我们也可以在建表里面加一个这样的代码,表示我们在打印实例化对象的时候显示实例化对象的name值。

    def __str__(self):
        return self.name

比如:

<QuerySet [<Books: python实战>, <Books: mysql实战>, <Books: 西游记>, <Books: 红楼梦>, <Books: django开发>, <Books: go开发秘籍>]>
python实战

按照创建的类去数据库生成对应的表:在终端操作

python3 manage.py makemigrations

执行完这条命令之后,会生成一个内容,将自己创建的类对应上了。id自动且添加主键自增。

# -*- coding: utf-8 -*-
# Generated by Django 1.11.9 on 2020-04-14 14:34
from __future__ import unicode_literals

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Books',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=16)),
            ],
        ),
    ]
0001_initial.py
python3 manage.py migrate

再这行完这条命令数据库才生成内容。内部生成了很多张表。

如果再增加字段可以设置默认值或者重新写一个model.py

四、创建多张表

再写其他的类就可以了。

五、ORM对单表的增删改查 

表我们已经创建好了我们就需要写路由,视图函数和模板了。

models.py:

from django.db import models
# Create your models here.
class Books(models.Model):
    name = models.CharField(max_length=16)
    price = models.FloatField()
    pub_date = models.DateField()
    author = models.CharField(max_length=32,null=False)

urls.py:

views.py:

templates:

表单条记录的添加:

  1、create方法

from django.shortcuts import render,HttpResponse

# Create your views here.
# 引入类
from app01.models import *
def index(request):
    return render(request,'index.html')

def addbook(request):
    # 通过objects去调用create()方法
    # 找到类创建实例对象,加上字段
    Books.objects.create(name='mysql实战',price=55,author='yangjing',pub_date='2018-01-13')
    return HttpResponse('添加成功')
views.py

  2、save方法:

from django.shortcuts import render,HttpResponse

# Create your views here.
# 引入类
from app01.models import *
def index(request):
    return render(request,'index.html')

def addbook(request):
    #给表记录添加内容就是类实例化得到一个对象
    python= Books(name='python实战',price=45,author='zhangrenguo',pub_date='2018-01-13')
    #实例化得到对象如果想要存到数据库还得条用对象的save()方法。     
    python.save()
    
    return HttpResponse('添加成功')
views.py

数据来源于用户的输入与选择!form表单、ajax、、传给后端我们接收到的内容。以字典数据存的。要保证字典里面的键是前端input标签里的name属性的值,只要保证前端input标签里的name属性的值跟数据库里面的字段是一样话,就可以**dic。因为dic本身就是人家返回给你的数据对象就是一组组键值对。

单条表记录的修改:推荐使用update方法

def updatebook(request):
    # 通过filter筛选要找到的条件,再条用update()方法进行对应字段记录的修改
    Books.objects.filter(id=2).update(name='python基础进阶')
    return HttpResponse('修改成功了')
update方法

还有一种修改实例对象的属性的方法。

  1. 第一步找到要操作的这个对象。
  2. 第二步对这个对象的属性重新赋值。
def updatebook(request):
    # 通过filter筛选要找到的对象,赋给一个变量b
    b = Books.objects.get(author='yangjing')
    # 这里的b是Queryset数据类型。它不是一个对象而是对象集合。
    print(b)         #<QuerySet [<Books: Books object>]>
    print(type(b))   #<class 'django.db.models.query.QuerySet'>
    # 集合需要切片拿到对象,对属性重新赋值
    b.price=120
    # 只要是通过类的对象的形式的操作一定要进行保存。
    b.save()

    return HttpResponse('修改成功了')

注意:

  1. update是QuerySet对象的方法。
  2. filter返回的是一个QuerySet对象集合。
  3. get返回的是一个model对象。

单条表记录的删除:

def deletebook(request):
    #先找到要删除的记录
    Books.objects.filter(id=2).delete()
    return HttpResponse('已经删除成功了!')

单表记录的查询:

  浏览器发送请求去url里,进行路由分配,映射到视图函数,执行逻辑代码从数据库拿到数据,将数据通过模板语言嵌套到html文件,最后返回给浏览器渲染展示。

from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^index/', views.index),
    url(r'^addbook/', views.addbook),
    url(r'^updatebook/', views.updatebook),
    url(r'^deletebook/', views.deletebook),
    url(r'^selectbook/', views.selectbook),
]
urls.py
from django.shortcuts import render, HttpResponse

# Create your views here.
# 引入类
from app01.models import *


def index(request):
    return render(request, 'index.html')

def addbook(request):
    # 通过objects去调用create()方法
    # 找到类创建实例对象,加上字段
    # Books.objects.create(name='mysql实战', price=55, author='yangjing', pub_date='2018-01-13')
    # Books.objects.create(name='西游记', price=95, author='吴承恩', pub_date='2018-01-16')
    # Books.objects.create(name='红楼梦', price=935, author='曹雪芹', pub_date='1998-01-16')
    # Books.objects.create(name='django开发', price=395, author='张仁国', pub_date='2018-01-16')
    # Books.objects.create(name='go开发秘籍', price=85, author='杨天王', pub_date='2020-11-26')
    return HttpResponse('添加成功')


def updatebook(request):
    # 通过filter筛选要找到的条件,再条用update()方法进行对应字段记录的修改
    Books.objects.filter(id=2).update(name='python基础进阶')
    return HttpResponse('修改成功了')

def deletebook(request):
    # 先找到要删除的记录
    Books.objects.filter(id=2).delete()
    return HttpResponse('已经删除成功了!')

def selectbook(request):

    book_list = Books.objects.all()
    print(book_list)#是QuerySet对象结合。
    return render(request,'book.html',{'book_list':book_list})
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>首页</title>
    <style>
        *{
            padding: 0;
            margin: 0;
        }
        .header{
            background-color: darkcyan;
            line-height: 50px;
            color: white;
            text-align: center;
        }
    </style>
</head>
<body>
<div class="outter">
    <div class="header">
        标题
    </div>
    <div class="content">
        <a href="/addbook/">添加书籍</a>
        <a href="/updatebook/">修改书籍</a>
        <a href="/deletebook/">删除书籍</a>
        <a href="/selectbook/">查询书籍</a>
    </div>
</div>
</body>
</html>
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>Title</title>
</head>
<body>
<table border="1" cellpadding="10">
    <thead>
    <tr>
        <th>id</th>
        <th>书名</th>
        <th>价格</th>
        <th>出版日期</th>
        <th>作者</th>
    </tr>
    </thead>
    <tbody>
    {% for book in book_list %}
        <tr>
            <td>{{ book.id }}</td>
            <td>{{ book.name }}</td>
            <td>{{ book.price }}</td>
            <td>{{ book.pub_date }}</td>
            <td>{{ book.author }}</td>
        </tr>
    {% endfor %}
    </tbody>
</table>
</body>
</html>
book.html

 

查询相关的API:

语法:表名(类名).objects.具体方法

filter()方法:括号里面写筛选条件(字段),会查询到与所给筛选条件相匹配的对象

all()方法:查询所有的记录。

支持切片比如取前三条:all()[:3]   切片也支持设置步长,如果步长设为-1就是倒着取的意思。

filter和all从数据库获取到的是queryset对象。 

first():查询第一个

last():查询最后一个

get():括号里写要匹配的字段,直接取对象。如果没有记录或者有多条记录都会报错。

.values():括号里写你要匹配的字段,只取对象的某个属性。

查询出来的结果数据类型是个字典集合。

比如我们只需要取出作者是张仁国的所有书名:

bname_list = Books.objects.filter(author='张仁国').values('name')

可以查询多个,只需要逗号分隔开即可

bname_list = Books.objects.filter(author='张仁国').values('name','price')

.values_list():这样查询的结果是元组形式。

exclude():与filter相反,括号里写排除不选的条件。

order_by():对结果进行排序

reverse():

distinct():去重

count():统计个数

模糊查询

 双下划线:__

models.Tb1.objects.filter(id__lt=10, id__gt=1)   # 获取id小于1 且 大于10的值
 
models.Tb1.objects.filter(id__in=[11, 22, 33])   # 获取id等于11、22、33的数据
models.Tb1.objects.exclude(id__in=[11, 22, 33])  # not in
 
models.Tb1.objects.filter(name__contains="ven")  #包括ven的
models.Tb1.objects.filter(name__icontains="ven") # icontains不区分大小写
 
models.Tb1.objects.filter(id__range=[1, 2])      # 范围bettwen and
 
startswith,istartswith, endswith, iendswith
对象可以调用自己的属性,用一个点就可以
还可以通过双下划线
    models.Book.objects.filter(price__gt=100)   价格大于100的书
    models.Book.objects.filter(author__startwith= "")    查看作者的名字是以张开头的
    主键大于5的且小于2
    price__gte=99大于等于
    publishDate__year =2017,publishDate__month = 10   查看2017年10月份的数据

 六、ORM对多表的操作

创表写类之前搞清楚他们之间的关系,我们新创:建图书表、出版社表、作者表。

图书表与出版社表他们之间的关系是:一对多。

  一本书由一家出版社出版,但是一家出版社可以出版很多书。

  书是多的一方,建外键一定是建在多的那一方!  

class Book(models.Model):
   # 语法格式:跟哪一张表建立关联关系,默认是关联主键。
    publish = models.ForeignKey('Publish')

  django会给数据库外键字段名字在你自己赋值的前提上加上_id

图书表与作者表之间的关系是:多对多。

ManyToManyField()会自动创建第三张表。但不会在表里面生成任何列。

class Book(models.Model):
    name = models.CharField(max_length=16)
    price = models.FloatField()
    pub_date = models.DateField()
    # 一对多语法格式:跟哪一张表建立关联关系,默认是关联主键。
    publish = models.ForeignKey('Publish')
    # 两张表建立多对多关系语法:
    author = models.ManyToManyField('Author')

一对多的添加记录:

第一步:先需要引入要操作的类

第二步:在视图函数里需要确定对哪张表进行操作

第三步:对表加字段也就是加记录,需要注意的是外键字段,表对应的属性是数据库字段。

django会给数据库外键字段名字在你自己赋值的前提上加上_id
    Book.objects.create(name='python开发',price=34.8,pub_date='2018-3-8',publish_id=1)
    Book.objects.create(name='go开发',price=24.8,pub_date='2018-4-8',publish_id=2)
    Book.objects.create(name='php开发',price=54.8,pub_date='2015-6-8',publish_id=3)
    Book.objects.create(name='java开发',price=324.8,pub_date='2013-3-28',publish_id=2)
    Book.objects.create(name='mysql数据库',price=134.8,pub_date='2016-2-13',publish_id=1)
addbook的create方法

 上面是对所有的数据库字段进行赋值,如果我们只想对里面的publish属性对象进行赋值怎么操作呢?

  1、首先找到出版社对象(关联的外键表的对象)。比如给书添加人民邮电出版社,添加时不写publish_id等于一个数字而是直接publish等于人民邮电出版社对象。

  2、将出版社对象赋值给publish。

publish_obj = Publish.objects.get('人民邮电出版社')
Book.objects.create(name
='linux私房菜', price=134.8, pub_date='2016-2-13', publish=publish_obj)

一对多的修改记录:

一对多的删除记录:

需要先查到想要删除的内容。

filter条件跨表必须使用双下划线。

一对多的查询记录:

通过查书的名字查书的出版社怎么查?

通过一个类实例出来一个对象,这一个对象可以去调用它的属性!

外键属性是另一个类的实例对象!

def selectbook(request):
    book_obj = Book.objects.get('python开发')
    print(book_obj.name)
    print(book_obj.price)
    print(book_obj.publish.name)
    print(book_obj.publish.city)

通过双下划线:

    res = Book.objects.filter(name='linux私房菜').values('publish__name')
    print(res)

根据类名反向查询:

    res = Publish.objects.filter(book__name='mysql数据库').values('name')
    print(res)

查某个出版社出版了哪些书怎么查?

1、原始方法:通过出版社对象去书里匹配

def selectbook(request):
    pub_obj = Publish.objects.get('南京出版社')
    res = Book.objects.filter(publish=pub_obj).values('name','city')
    print(res)

2、通过外键关联关系:1、拿到出版社对象 2、找到关联的book表 3、返回所有的对象集合。反向查询进行跨表

纵然publish出版社表里没有foreignkey字段,而其它表有foreignkey字段跟它进行关联,那publish出版社这张表就隐含了一个字段,隐含的字段名称叫:跟它关联表的表名(类名)再加上一个下划线_再加上一个set。

def selectbook(request):
    pub_obj = Publish.objects.get('南京出版社')
    res = pub_obj.book_set.all().values('name','price')
    print(res)

3、通过双下划线:publish是外键字段名字,通过外键名字找对应的对象,然后去取对象的name,然后再做筛选。跨表查询用__

    res = Book.objects.filter(publish__name='人民邮电出版社').values('name','price')
    print(res)

 查地址是北京的出版社出版的书怎么查?

    res = Book.objects.filter(publish__city='北京').values('name','price')
    print(res)

多对多的增加记录: 

给书增加作者:

    book_obj = Book.objects.get(id=3)
    author_obj = Author.objects.get(id=2)
    book_obj.author.add(author_obj)

如果想对第三张表进行直接操作的话就不能用ManyToManyField()字段。只能自己手写。如果自己手写的话就不要在book类里写author的ManyToManyField。

class Book_Author(models.Model):
    book = models.ForeignKey('Book')
    author = models.ForeignKey('Author')

有了我们自己手写的这第三张表我们就可以直接在里面插记录了:

Book_Author.objects.create(book_id=2,author_id=3)

有了我们自己手写的这第三张表我们就可以进行关联查询了:就是一对多的查询。

比如查张仁国出过的书名和价格:

    Book.objects.filter(book_author__author__name='张仁国').values('name','price')

自己创建的表就到此为止,别处写的都是djangoORM自动创建的表的操作。

----------------    ----------------- ------   --------------------------------------------

多对多的增加记录:如果用的是ManyToManyField()字段自动创建的第三张表,在model里没有对应到类。

我们对第三张表进行添加数据:ManyToManyField()字段是写在哪张表里的,就利用这个类去用这个字段。

    Book.objects.filter(id=1).first()            #找到id是1的书籍
    Book.author.add(2)                           #第三张表的id字段自增长的,我们书的id为1的添加作者id为2
    Book.author.add([3,4])              #还可以添加多个。 

多对多的删除记录:

clear清空

remove删除

多对多的修改记录:

重置:set,有的话不变,没有的话删除并且新增。

多对多的查询记录:

正向查询:通过书名去拿作者。

def selectauthor(request):
    book_obj = Book.objects.get('php开发')
    res = book_obj.author.all()     #所有的作者的对象
    print(res)

反向查询:通过作者去拿书名。

    author_obj = Author.objects.get('张仁国')
    print(author_obj.book_set.all())

查找作者是张仁国出过的书的名字和价格:

Book.objects.filter(author__name='张仁国').values('name','price')

 七、聚合查询aggrgate和分组查询annotate

聚合查询aggrgate:如果想用必须找到聚合函数

from django.db.models import Avg,Min,Max,Sum,Count

把所有书的价格平均值求出来:一定要现调aggrgate才可以用里面的聚合函数。

Book.objects.all().aggregate(Avg('price'))

查出作者是张仁国的书的总价格:要加个过滤条件

    Book.objects.filter(author__name='张仁国').aggregate(Sum('price'))

分组查询annotate:

查每一个作者出的书的价格总和:查出每本书的作者然后按照作者名字进行分组再对每组按价格进行求和。

    Book.objects.values('author__name').annotate(Sum('price'))

查每一个出版社出的书的价格最便宜的价格:

Publish.objects.values('name').annotate(Min('book__price'))

八、F查询和Q查询 

单关键字查询:一组键值对就是一个但关键字!

把所有的书的价格都加10块钱:

引入F和Q:

from django.db.models import F,Q

F查询:

  F函数里面包上你要加减的字段,这样拿到到的就是每个字段里这个字段的值。拿到这个值才进行你要的操作,比如加10

Book.objects.all().update(pcice = F('price')+10)

Q查询:构建查询条件

  查询函数可以混合使用Q 对象和关键字参数。所有提供给查询函数的参数(关键字参数或Q 对象)都将"AND”在一起。但是,如果出现Q 对象,它必须位于所有关键字参数的前面。

bookList=Book.objects.filter(Q(publishDate__year=2016) | Q(publishDate__year=2017), title__icontains="python")

  Q函数把条件包起来,如果是或的话用管道符 | 分隔开。非用 ~ 

  

九、QuerySet集合对象的特性 

QuerySet是一个结果集合,只是一堆sql语句。

惰性机制提升性能。

可以进行for循环遍历。

django给QuerySet加了一个缓存,做了一次查询之后就已经有缓存了。

生成器

 对查询结果调用一个iterator()方法就可以了,节省内存空间。

 如果量大的话用iterator()

迭代器

一个小问题:

什么是根目录:就是没有路径,只有域名、。url(r'^$')

补充一张关于wsgiref模块的图片

一、MTV模型

Django的MTV分别代表:

  Model(模型):和数据库相关的,负责业务对象与数据库的对象(ORM)

  Template(模板):放所有的html文件

           模板语法:目的是将白变量(数据库的内容)如何巧妙的嵌入到html页面中

  View(视图):负责业务逻辑,并在适当的时候调用Model和Template

  此外,Django还有一个URL分发器。它的作用是将一个个URL的页面请求分别发给不同的Views处理,Views再调用相应的Model和Template。

原文地址:https://www.cnblogs.com/zhangrenguo/p/10778519.html