Django从入门到精通(三)

目录

七、ORM操作

7.1、表结构

常见字段

参数

示例

7.2、表关系

一对多

多对多

第一种方式

第二种方式

7.3、连接MYSQL

7.4、数据库连接池

7.5、多数据库

读写分离

[分库(多个app ->多数据库)](#分库(多个app ->多数据库))

分库(单app)

注意事项

7.6、表关系

单表

一对多

多对多

一对一

7.7、数据操作

单表

增加

删除

修改

查询

一对多

增加

删除

修改

查询

多对多

添加

查询

八、session和cookie

8.1、cookie

8.2、session

存入文件

数据库

缓存(redis)


七、ORM操作

其实说白了,就是对数据库进行增删改查操作。

7.1、表结构

**实现:**创建表、修改表、删除表。

在app中的models.py中按照规则编写类 ===> 表结构。

第一步:编写实体类

app01/models.py

python 复制代码
from django.db import models

class UserInfo(models.Model):
    name = models.CharField(max_length=16)
    age = models.IntegerField()

app02/models.py

python 复制代码
from django.db import models

class Role(models.Model):
    roleName = models.CharField(max_length=16)
    count = models.IntegerField()

第二步:注册app

python 复制代码
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'apps.app01.apps.App01Config',
    'apps.app02.apps.App02Config'
]

第三步:命令,django根据models中类生成一个 `对数据库操作的配置文件` => `migrations`

bash 复制代码
python manage.py makemigrations

注意:假如我们要添加个字段或者修改一个字段,亦或者又增加了一个实体类,那么再次运行此命令即可,django会自动帮我们检测我们做了哪些修改。

第四步:配置数据库信息

默认的如下:

第五步:执行命令生成表

bash 复制代码
python manage.py migrate

读取已经注册的app中的migrations目录将配置文件 -> 转换成:生成表,修改表 SQL -> 连接数据库去运行。

第六步:打开sqlite3数据库

常见问题:请不要再手动去修改数据的表结构 + 时刻保证 ORM和数据表是对应。

必须先修改实体类字段,再执行那两条命令。

常见字段

CharField -> 字符串

SmallIntegerField

IntegerField -> 整型

BigIntegerField

DateField -> 年月入

DateTimeField -> 年月入时分秒

BooleanField -> 其实数据库不支持真假,根据SmallIntegerField创造出来出来。 0 1

DecimalField -> 精确的小数

参数

CharField

**verbose_name="姓名":**表示这个字段的注释

**max_length:**最大长度

**null=True:**表示数据库是否可以为null

**blank=True:**表示用户输入字段是否可以为空,和null=True一般搭配使用

**db_index=True:**为这个字段添加索引

**unique=True:**为这个字段增加唯一约束

**default:**默认值

**choices:**元组套元组,限制存储值显示值

DateField

**auto_now=True:**自动给数据库赋值当前日期,常用于创建时间字段

DecimalField

**max_digits=10:**总共长度是10个数

**decimal_places=2:**小数部分有两位

示例

python 复制代码
from django.db import models


class UserInfo(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=16, db_index=True)
    age = models.PositiveIntegerField(verbose_name="年龄")
    email = models.CharField(verbose_name="邮箱", max_length=128, unique=True)
    amount = models.DecimalField(verbose_name="余额", max_digits=10, decimal_places=2, default=0)
    register_date = models.DateField(verbose_name="注册时间", auto_now=True)


class Goods(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)
    # detail = models.CharField(verbose_name="详细信息", max_length=255)
    detail = models.TextField(verbose_name="详细信息")
    price = models.PositiveIntegerField(verbose_name="价格")
    count = models.PositiveBigIntegerField(verbose_name="库存", default=0)

7.2、表关系

一对多

很明显1个部门对应多个用户。

python 复制代码
from django.db import models


class Department(models.Model):
    """部门表"""
    title = models.CharField(verbose_name="标题")

class UserInfo(models.Model):
    name = models.CharField(max_length=16)
    depart_id = models.ForeignKey(verbose_name="部门ID", to="Department", to_field="id", on_delete=models.CASCADE)

注意:on_delete=models.CASCADE 意思就是级联删除,比如我要删除某个部门,部门下没有用户关联还好,如果有关联就把关联的用户删掉。也可以on_delete=models.SET_NULL,如果删除部门,那就将部门下的员工信息所关联的depart_id字段设置为null。

多对多

第一种方式
第二种方式

我们就可以省略中间表的实体类代码,直接使用ManyToManyField,Django会自动为我们生成中间表。

注意:ManyToManyField生成的表字段只能id/bid/gid。

7.3、连接MYSQL

第一步:settings.py文件

python 复制代码
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'django-test',  # 数据库名字
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',  # ip
        'PORT': 3306,
    }
}

第二步:安装第三方组件

pymysql

bash 复制代码
pip install pymysql
python 复制代码
项目根目录/项目名目录/__init__.py
	import pymysql
	pymysql.install_as_MySQLdb()

mysqlclient

bash 复制代码
pip install mysqlclient

7.4、数据库连接池

django默认内置没有数据库连接池 。

bash 复制代码
pip install django-db-connection-pool
python 复制代码
DATABASES = {
    "default": {
        'ENGINE': 'dj_db_conn_pool.backends.mysql',
        'NAME': 'django-test',  # 数据库名字
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',  # ip
        'PORT': 3306,
        'POOL_OPTIONS': {
            'POOL_SIZE': 10,  # 最小
            'MAX_OVERFLOW': 10,  # 在最小的基础上,还可以增加10个,即:最大20个。
            'RECYCLE': 24 * 60 * 60,  # 连接可以被重复用多久,超过会重新创建,-1表示永久。
            'TIMEOUT':30, # 池中没有连接最多等待的时间。
        }
    }
}

注意:如果你不用连接池,那ENGINE属性值就是django.db.backends.mysql。

7.5、多数据库

django支持项目连接多个数据库。

python 复制代码
DATABASES = {
    "default": {
        'ENGINE': 'dj_db_conn_pool.backends.mysql',
        'NAME': 'django-test',  # 数据库名字
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',  # ip
        'PORT': 3306,
        'POOL_OPTIONS': {
            'POOL_SIZE': 10,  # 最小
            'MAX_OVERFLOW': 10,  # 在最小的基础上,还可以增加10个,即:最大20个。
            'RECYCLE': 24 * 60 * 60,  # 连接可以被重复用多久,超过会重新创建,-1表示永久。
            'TIMEOUT': 30,  # 池中没有连接最多等待的时间。
        }
    },
    "bak": {
        'ENGINE': 'dj_db_conn_pool.backends.mysql',
        'NAME': 'django-test-bak',  # 数据库名字
        'USER': 'root',
        'PASSWORD': 'root',
        'HOST': '127.0.0.1',  # ip
        'PORT': 3306,
        'POOL_OPTIONS': {
            'POOL_SIZE': 10,  # 最小
            'MAX_OVERFLOW': 10,  # 在最小的基础上,还可以增加10个,即:最大20个。
            'RECYCLE': 24 * 60 * 60,  # 连接可以被重复用多久,超过会重新创建,-1表示永久。
            'TIMEOUT': 30,  # 池中没有连接最多等待的时间。
        }
    },
}

读写分离

生成数据库表

bash 复制代码
python manage.py makemigrations    # 找到所有已注册的app中的models.py中的类读取 -> migrations配置

python manage.py migrate
python manage.py migrate --database=default
python manage.py migrate --database=bak

后续再进行开发时

python 复制代码
models.UserInfo.objects.using("default").create(title="编程抗氧化")

models.UserInfo.objects.using("bak").all()

编写router类,简化【后续再进行开发时】

python 复制代码
class DemoRouter(object):
    
    def db_for_read(...):
        return "bak"
    
    def db_for_write(...):
        return "default"
python 复制代码
router = ["DemoRouter"]

分库(多个app ->多数据库)

100张表,50表-A数据库【app01】;50表-B数据库【app02】。

app01/models

python 复制代码
from django.db import models


class UserInfo(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)

app02/models

python 复制代码
from django.db import models


class Role(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)

命令

python 复制代码
python manage.py makemigrations
python manage.py migrate app01 --database=default
python manage.py migrate app02 --database=bak

读写操作

python 复制代码
from django.shortcuts import render, HttpResponse

from app01 import models as m1
from app02 import models as m2


def index(request):
    # app01中的操作 -> default
    v1 = m1.UserInfo.objects.all()
    print(v1)

    # app02中的操作 -> bak
    v2 = m2.Role.objects.using('bak').all()
    print(v2)
    return HttpResponse("返回")

router

分库(单app)

100张表,50表-A数据库;50表-B数据库。

注意:因为单个app是无法通过命令去生成哪张表去A库,哪张表去B库的,所以要借用路由的allow_migrate方法。

python 复制代码
from django.shortcuts import render, HttpResponse

from app01 import models as m1


def index(request):
    # app01中的操作 -> default
    v1 = m1.UserInfo.objects.all()
    print(v1)

    # app01中的操作 -> bak
    v2 = m1.Role.objects.using('bak').all()
    print(v2)

    return HttpResponse("返回")

注意事项

一定不要跨数据库做关联 -> django不支持

那怎么办呢?

尽可能的将有关联的表放在一个库中。

7.6、表关系

单表

python 复制代码
class Role(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)

一对多

多对多

如果中间表中只有3列。

python 复制代码
class Boy(models.Model):
    name = models.CharField(verbose_name="标题", max_length=32, unique=True)
    b = models.ManyToManyField(to="Girl")

class Girl(models.Model):
    name = models.CharField(verbose_name="标题", max_length=32, unique=True)
python 复制代码
class Boy(models.Model):
    name = models.CharField(verbose_name="标题", max_length=32, unique=True)
    
class Girl(models.Model):
    name = models.CharField(verbose_name="标题", max_length=32, unique=True)
    b = models.ManyToManyField(to="Boy")

如果中间表不止3列。

python 复制代码
class Boy(models.Model):
    name = models.CharField(verbose_name="标题", max_length=32, unique=True)


class Girl(models.Model):
    name = models.CharField(verbose_name="标题", max_length=32, unique=True)


class B2G(models.Model):
    bid = models.ForeignKey(to="Boy", on_delete=models.CASCADE)
    gid = models.ForeignKey(to="Girl", on_delete=models.CASCADE)
    address = models.CharField(verbose_name="地点", max_length=32)

一对一

博客园为例:

  • 注册,用户名、密码,无法创建博客

  • 开通博客 地址

7.7、数据操作

单表

python 复制代码
class Role(models.Model):
    title = models.CharField(verbose_name="标题", max_length=32)
增加
python 复制代码
# obj1 = models.Role.objects.create(title="管理员", od=1)
# obj2 = models.Role.objects.create(**{"title": "管理员", "od": 1})

# 内存 -> save
# obj = models.Role(title="客户", od=1)
# obj.od = 100
# obj.save()

# obj = models.Role(**{"title": "管理员", "od": 1})
# obj.od = 100
# obj.save()
删除
python 复制代码
# models.Role.objects.all().delete()
models.Role.objects.filter(title="管理员").delete()
修改
python 复制代码
models.Role.objects.all().update(od=99)
models.Role.objects.filter(id=7).update(od=99, title="管理员")
models.Role.objects.filter(id=7).update(**{"od": 99, "title": "管理员"})
查询
python 复制代码
# select * from role;
v1 = models.Role.objects.all()
for obj in v1:
    print(obj, obj.id, obj.title, obj.od)

# select * from role where od = 99 and id = 99;
# v2 = models.Role.objects.filter(od=99, id=99)
v2 = models.Role.objects.filter(**{"od": 99, "id": 99})
for obj in v2:
    print(obj, obj.id, obj.title, obj.od)
    

# select * from role where id = 99;
v3 = models.Role.objects.filter(id=99)
print(v3.query)

# select * from role where id > 2;
v3 = models.Role.objects.filter(id__gt=2)
print(v3.query)

# select * from role where id >= 2;
v3 = models.Role.objects.filter(id__gte=2)
print(v3.query)

# select * from role where id < 2;
v3 = models.Role.objects.filter(id__lt=2)
print(v3.query)

# select * from role where id in (11,22,33);
v3 = models.Role.objects.filter(id__in=[11, 22, 33])
print(v3.query)

v3 = models.Role.objects.filter(title__contains="户")
print(v3.query)

v3 = models.Role.objects.filter(title__startswith="户")
print(v3.query)

# select * from role where title is null;
v3 = models.Role.objects.filter(title__isnull=True)
print(v3.query)

# select * from role where id != 99 and od = 88;
v3 = models.Role.objects.exclude(id=99).filter(od=88)
print(v3.query)

# 取数据集的第一个
v3 = models.Role.objects.filter(id__gt=0).first()
# print(v3)  # 对象

# 判断数据是否存在
v3 = models.Role.objects.filter(id__gt=10).exists()
print(v3)  # True/False

# asc 排序
v3 = models.Role.objects.filter(id__gt=0).order_by("id")

# id desc  od asc
v3 = models.Role.objects.filter(id__gt=0).order_by("-id", 'od')

当查询返回QuerySet[obj,obj]怎么办?

python 复制代码
# queryset=[obj,obj]
v3 = models.Role.objects.filter(id=99)

# queryset=[{'id': 6, 'title': '客户'}, {'id': 7, 'title': '客户'}]
v4 = models.Role.objects.filter(id__gt=0).values("id", 'title')

# QuerySet = [(6, '客户'), (7, '客户')]
v5 = models.Role.objects.filter(id__gt=0).values_list("id", 'title')
print(v5[0])

一对多

python 复制代码
from django.db import models

class Depart(models.Model):
    """ 部门 """
    title = models.CharField(verbose_name="标题", max_length=32)


class Admin(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=32)
    pwd = models.CharField(verbose_name="密码", max_length=32)

    depart = models.ForeignKey(verbose_name="部门", to="Depart", on_delete=models.CASCADE)

一个部门对应多个员工。

生成表后是这样的:

我们先手动往部门表里添加几条数据

增加
python 复制代码
# 第一种方式:直接添加值
# models.Admin.objects.create(name='编程抗氧化', pwd='123456', depart_id=1)


# 第二种方式:先查出你要添加用户的部门信息,再动态添加用户
obj = models.Depart.objects.filter(id=2).first()
models.Admin.objects.create(name='苏格拉底', pwd='123456', depart=obj)
models.Admin.objects.create(name='柏拉图', pwd='123456', depart_id=obj.id)
删除
python 复制代码
# 找到部门id=3的所有的员工,直接删除
# models.Admin.objects.filter(depart_id=3).delete()

# 删除销售部的所有员工
# obj = models.Depart.objects.filter(title="销售部").first()
# models.Admin.objects.filter(depart_id=obj.id).delete()

# filter后面的条件代表 部门表的title='软件部' and 用户表的name='苏格拉底'
# 相当于使用了inner join
models.Admin.objects.filter(depart__title="软件部", name='苏格拉底').delete()
修改
python 复制代码
models.Admin.objects.filter(id=2).update(name='xxx', pwd='xxxx')
models.Admin.objects.filter(name="苏格拉底").update(depart_id=1)
查询
python 复制代码
# 1. select * from admin; 只查询admin表数据
v1 = models.Admin.objects.filter(id__gt=0)
for obj in v1:
	print(obj.name, obj.pwd, obj.id, obj.depart_id)

# 2. select * from admin inner join depart      queryset=[obj,obj,]
v2 = models.Admin.objects.filter(id__gt=0).select_related("depart")
for obj in v2:
	print(obj.name, obj.pwd, obj.id, obj.depart_id, obj.depart.title)

# 3. select id,name.. from admin inner join depart      queryset=[{},{}]
v3 = models.Admin.objects.filter(id__gt=0).values("id", 'name', 'pwd', "depart__title")
print(v3)

# 4. select id,name.. from admin inner join depart      queryset=[(),()]
v4 = models.Admin.objects.filter(id__gt=0).values_list("id", 'name', 'pwd', "depart__title")
print(v4)

多对多

python 复制代码
class Boy(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=32, db_index=True)


class Girl(models.Model):
    name = models.CharField(verbose_name="姓名", max_length=32, db_index=True)


class B2G(models.Model):
    bid = models.ForeignKey(to="Boy", on_delete=models.CASCADE)
    gid = models.ForeignKey(to="Girl", on_delete=models.CASCADE)
    address = models.CharField(verbose_name="地点", max_length=32)
添加

先添加boy表和girl表数据

python 复制代码
models.Boy.objects.create(name="宝强")
models.Boy.objects.create(name="羽凡")
models.Boy.objects.create(name="乃亮")

# 批量添加
models.Girl.objects.bulk_create(
	objs=[models.Girl(name="小路"), models.Girl(name="百合"), models.Girl(name="马蓉")],
	batch_size=3
)

然后创建这两张表的关系,往中间表添加数据

python 复制代码
# 创建关系
b_obj = models.Boy.objects.filter(name='宝强').first()
g_object = models.Girl.objects.filter(name="小路").first()
models.B2G.objects.create(bid=b_obj, gid=g_object, address="北京")
查询
python 复制代码
# 1.宝强都与谁约会。
q = models.B2G.objects.filter(bid__name='宝强').select_related("gid")
for item in q:
	print(item.id, item.address, item.bid.name, item.gid.name)


q = models.B2G.objects.filter(bid__name='宝强').values("id", 'bid__name', 'gid__name')
for item in q:
	print(item['id'], item['bid__name'], item['gid__name'])

# 2.百合 都与谁约会。
q = models.B2G.objects.filter(gid__name='百合').values("id", 'bid__name', 'gid__name')
for item in q:
	print(item['id'], item['bid__name'], item['gid__name'])

八、session和cookie

8.1、cookie

python 复制代码
def login(request):
    res = HttpResponse('登录...')
    res.set_cookie("v1", "123456", max_age=100, path="/")
    return res
python 复制代码
def home(request):
    v1 = request.COOKIES.get("v1")
    print(v1)
    return HttpResponse('home')

8.2、session

默认情况下,Django将Session存入数据库中。为了追求更高的速度,可以把Session存到别的地方,比如文件系统和Cache中。

存入文件

settings.py

python 复制代码
# session
SESSION_ENGINE = 'django.contrib.sessions.backends.file'
SESSION_FILE_PATH = 'session_data' # 需要你在项目下创建名为session_data的文件夹

SESSION_COOKIE_NAME = "sid"  # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
SESSION_COOKIE_PATH = "/"  # Session的cookie保存的路径
SESSION_COOKIE_DOMAIN = None  # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False  # 是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True  # 是否Session的cookie只支持http传输
SESSION_COOKIE_AGE = 1209600  # Session的cookie失效日期(2周)

SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否关闭浏览器使得Session过期
SESSION_SAVE_EVERY_REQUEST = True  # 是否每次请求都保存Session,默认修改之后才保存

views.py

python 复制代码
def login(request):
    # 在session中设置值 + cookie中写入凭证
    request.session["user_info"] = '编程抗氧化'
    return HttpResponse('登录...')

def home(request):
    # 获取session
    user_info = request.session.get("user_info")
    print(user_info)
    return HttpResponse('home')

解析代码:

request.session["user_info"] = '编程抗氧化' 这句代码所做的哪些操作?

首先往session中存入user_info = '编程抗氧化' ,然后往cookie中设置了sid = 2dsjd8sdsk2sdsdd。

下一次用户再次访问带着sid = 2dsjd8sdsk2sdsdd,我们根据sid获取存在session里的信息。

数据库

settings.py

python 复制代码
# session
SESSION_ENGINE = 'django.contrib.sessions.backends.db'

SESSION_COOKIE_NAME = "sid"  # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
SESSION_COOKIE_PATH = "/"  # Session的cookie保存的路径
SESSION_COOKIE_DOMAIN = None  # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False  # 是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True  # 是否Session的cookie只支持http传输
SESSION_COOKIE_AGE = 1209600  # Session的cookie失效日期(2周)

SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否关闭浏览器使得Session过期
SESSION_SAVE_EVERY_REQUEST = True  # 是否每次请求都保存Session,默认修改之后才保存

缓存(redis)

安装连接redis包

python 复制代码
pip install django-redis

settings.py

python 复制代码
CACHES = {
    "default": {
        "BACKEND": "django_redis.cache.RedisCache",
        "LOCATION": "redis://127.0.0.1:6379",
        "OPTIONS": {
            "CLIENT_CLASS": "django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS": {"max_connections": 100}
            # "PASSWORD": "密码",
        }
    }
}


# session
SESSION_ENGINE = 'django.contrib.sessions.backends.cache'
SESSION_CACHE_ALIAS = 'default'

SESSION_COOKIE_NAME = "sid"  # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串
SESSION_COOKIE_PATH = "/"  # Session的cookie保存的路径
SESSION_COOKIE_DOMAIN = None  # Session的cookie保存的域名
SESSION_COOKIE_SECURE = False  # 是否Https传输cookie
SESSION_COOKIE_HTTPONLY = True  # 是否Session的cookie只支持http传输
SESSION_COOKIE_AGE = 1209600  # Session的cookie失效日期(2周)

SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否关闭浏览器使得Session过期
SESSION_SAVE_EVERY_REQUEST = True  # 是否每次请求都保存Session,默认修改之后才保存

手动操作redis

python 复制代码
from django_redis import get_redis_connection

conn = get_redis_connection("default")
conn.set("xx","123123")
conn.get("xx")
相关推荐
woshilys21 分钟前
sql server 查询对象的修改时间
运维·数据库·sqlserver
Hacker_LaoYi22 分钟前
SQL注入的那些面试题总结
数据库·sql
建投数据1 小时前
建投数据与腾讯云数据库TDSQL完成产品兼容性互认证
数据库·腾讯云
Hacker_LaoYi2 小时前
【渗透技术总结】SQL手工注入总结
数据库·sql
岁月变迁呀2 小时前
Redis梳理
数据库·redis·缓存
独行soc2 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍06-基于子查询的SQL注入(Subquery-Based SQL Injection)
数据库·sql·安全·web安全·漏洞挖掘·hw
梧桐树04293 小时前
python常用内建模块:collections
python
Dream_Snowar3 小时前
速通Python 第三节
开发语言·python
你的微笑,乱了夏天3 小时前
linux centos 7 安装 mongodb7
数据库·mongodb
工业甲酰苯胺3 小时前
分布式系统架构:服务容错
数据库·架构