Parte dos de la capa del modelo Django: creación de relaciones de tablas múltiples y operación de tablas múltiples

prefacio

Continuando con el contenido del artículo anterior, este artículo presenta las operaciones de varias tablas. El uso de django ORM puede crear una relación de varias tablas y también admite operaciones entre varias tablas, para crear una relación de tablas y consultar dos partes para ilustrar la operación de varias tablas de django ORM. Tome varias tablas de información sobre el autor, el libro, la editorial y el autor como ejemplos ilustrativos.

Crear relación de tabla

Nota: En el desarrollo real, no se recomienda usar claves foráneas para establecer relaciones entre tablas, es decir, no usar actualización en cascada y eliminación en cascada, sino usar relaciones de claves foráneas lógicas para establecer relaciones entre tablas.

Entre las cuatro tablas anteriores, la relación entre Books y Publishing House es una relación de uno a muchos, y la clave externa se establece en el lado con la frecuencia de consulta más alta. Las tablas de autor y detalles del autor pertenecen a una relación de uno a uno. La clave externa se establece en el lado con alta frecuencia de consulta. Los autores y los libros pertenecen a una relación de muchos a muchos. Se necesita una tercera tabla para almacenar la relación Se recomienda construir la clave externa en el lado con alta frecuencia de consulta. Asegúrese de ejecutar el comando de migración de la base de datos al crear una tabla ~

Al crear una relación de tabla, primero puede crear el modelo de tabla y luego agregar el campo de clave externa. Además, al usar django ORM para crear la relación de clave externa, el campo de clave externa asociado se agregará automáticamente después del campo, y la relación entre la tabla y los _idvalores predeterminados de la tabla Use la clave principal como el campo asociado. Además, al crear relaciones de tabla, no se recomienda utilizar claves foráneas reales para la asociación, sino especificar relaciones de tabla mediante relaciones lógicas.

class Book(models.Model):
    name = models.CharField(max_length=60, verbose_name='图书名')
    # 浮点数字段,max_digits表示数字共8位, decimal_place表示小数点占2位
    price = models.DecimalField(max_digits=8, decimal_places=2, verbose_name='图书价格')
    inventory_num = models.IntegerField(verbose_name='库存数量')
    sell_num = models.IntegerField(verbose_name='卖出数量')
    # 一对多关系外键字段创建使用 ForeigenKey(to='表名'),默认关联主键字段, db_constraint=Flase表示不建立实质的外键关系,只是逻辑上的关系
    publish = models.ForeignKey(to='Publish', on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='外键关联出版社')
    # 多对多关系,使用ManyToManyField(to='表名'),author是一个虚拟的字段,主要是用来告诉ORM,书籍和作者是多对多的关系,而且ORM会自动创建多对多关系的第三张
    author = models.ManyToManyField(to='Author', on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='外键关联作者')


class Publish(models.Model):
    name = models.CharField(max_length=12, verbose_name='出版社名称')


class Author(models.Model):
    name = models.CharField(max_length=10, verbose_name='作者名称')
    # 一对一关系使用OneToOneField(to='表名')
    author_detail = models.OneToOneField(to='AuthorDetail', on_delete=models.DO_NOTHING, db_constraint=False, verbose_name='外间关联作者详情')


class AuthorDetail(models.Model):
    age = models.IntegerField(verbose_name='年龄')
    phone = models.CharField(max_length=11, verbose_name='手机号')

Además, se debe agregar que hay tres formas de crear una relación de tablas de muchos a muchos, que son la creación totalmente automática, la creación semiautomática y la creación manual completa:

# 全自动创建 - ManyToManyField,一般这种方式可以满足需求
'''
使用全自动创建多对多关系的优点就是无需手动创建第三张表,非常方便,django 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)
    
    
    
# 纯手动创建 -  ForeignKey手动创建第三张表
'''
第三张表完全取决于手动的扩展,但是需要写的代码较多,而且无法使用ORM提供的简单方法
'''
class Book(models.Model):
    name = models.CharField(max_length=32)
    
class Author(models.Model):
	name = models.CharField(max_length=32)
	
class Book2Author(models.Model):
    book_id = models.ForeignKey(to='Book')
    author_id = models.ForeignKey(to='Author')
    
# 半自动创建,通过ManyToManyField的参数控制第三张表
class Book(models.Model):
    name = models.CharField(max_length=32)
    authors = models.ManyToManyField(
        to='Author', # 告诉ORM不需要自动帮忙创建第三张关系表
        through='Book2Author', # 告诉ORM第三张关系表对应的表的外键字段
        through_fields=('book','author')  # 通过哪两个字段关联表,当前在哪张表,就先写哪个表的关联字段
                                     )
class Author(models.Model):
    name = models.CharField(max_length=32) 
    
class Book2Author(models.Model):
    book = models.ForeignKey(to='Book')
    author = models.ForeignKey(to='Author')

Operación de datos de tablas múltiples: adición, eliminación y modificación

Primero, presentaremos las operaciones de adición, eliminación y modificación de las operaciones de tablas múltiples, porque las operaciones de datos de consulta de tablas múltiples son un poco más problemáticas, por lo que haremos un pequeño trabajo por separado.

Relación uno a muchos y uno a uno: agregar, eliminar, modificar

Las operaciones de suma, eliminación y modificación uno a uno y uno a muchos son básicamente las mismas.

aumentar los datos

Hay dos formas de agregar datos, una es agregar a través de campos reales y la otra es agregar a través de la asignación de objetos de campo virtual.

# 方式1:通过实际字段
book_obj = models.Book.objects.create(name='哈利波特', price=10.2, publish_id=1)

# 方式2,先获取出版社对象,再将书籍和出版社通过出版社对象进行关联
publis_obj = models.Publish.objects.filter(pk=1).first()
book_obj = models.Book.objects.create(name='哈利波特', price=10.2, publish=publis_obj)

borrar datos

Cabe señalar que la eliminación de datos en el desarrollo del proyecto real no se elimina realmente, sino que se utiliza un campo booleano para indicar si se eliminan los datos.

Si no especifica cuándo eliminar datos, on_delete=models.DO_NOTHINGel valor predeterminado es actualización en cascada y eliminación en cascada.

models.Publish.objects.filter(pk=1).delete()

cambiar los datos

Hay dos formas de modificar datos y agregar datos.

# 方式1
models.Book.objects.filter(pk=1).update(publish_id=1)

# 方式2
pub_obj = models.Publish.objects.filter(pk=2).first()
models.Book.objects.filter(pk=1).update(publish=pub_obj)

Relación de muchos a muchos: agregar, eliminar, modificar

En primer lugar, debe quedar claro que las adiciones, eliminaciones y modificaciones de muchos a muchos están operando en la tercera tabla relacional, pero Django crea automáticamente la tercera tabla relacional. ¿Cómo ingresar a la tercera tabla a través del código? La relación de clave externa de muchos a muchos se crea en la tabla del libro, y el campo de clave externa de muchos a muchos es authorun campo, por lo que book_obj.authorla tercera tabla se puede operar pasándola.

Para la relación muchos a muchos de la tercera tabla creada automáticamente por django, django proporciona métodos adicionales para operar con los datos.

Agregar una relación de muchos a muchos - add()

add()El método agrega datos a la tercera tabla relacional. Tanto los números como los objetos se pueden pasar entre paréntesis y se admiten múltiples operaciones simultáneas.

# 方式1,直接添加id值
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.add(1)		# 增加 1 1记录,即id为1的书绑定id为1的作者
book_obj.author.add(2, 3)   # 增加两条记录,1 2 和 1 3

# 方式2,通过对象添加关系
book_obj = models.Book.objects.filter(pk=2).first()
author_obj1 = models.Author.objects.filter(pk=1).first()
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj.author.add(author_obj1)				# 增加1条记录
book_obj.author.add(author_obj2, author_obj3)	# 增加2条

Eliminar una relación de muchos a muchos - remove()

remove()El método se utiliza para eliminar datos para la tercera tabla. De manera similar, tanto los números como los objetos se pueden pasar entre corchetes, y se pueden operar múltiples datos al mismo tiempo.

# 方式1:直接删除值
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.remove(2)  # 删除book_id为1和author_id都为2的记录
book_obj.authors.remove(1, 3)  # 删除多条

# 方式2:通过对象删除
author_obj1 = models.Author.objects.filter(pk=2).first()
author_obj2 = models.Author.objects.filter(pk=3).first()
book_obj.authors.remove(author_obj1, author_obj2)

Modificar la relación de muchos a muchos - set ()

set()El método se utiliza para modificar la tercera tabla. Este método es una operación de sobrescritura, que sobrescribe la relación anterior con la nueva relación. El parámetro de este método debe ser una lista o tupla, indicando números u objetos, y también admite múltiples datos. operaciones al mismo tiempo.

# 方式1:直接通过值进行修改
book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.set([2])  # 将book_id为1对应的author_id修改为2
book_obj.authors.set([1, 2])  # 将书的作者设置为id=1 和id=2的作者

# 方式2:通过对象进行修改
author_obj2 = models.Author.objects.filter(pk=2).first()
author_obj3 = models.Author.objects.filter(pk=3).first()
book_obj.authors.set([author_obj2, author_obj3])

Borrar la relación vinculante de un objeto en la tercera tabla - clear()

clear()El método borrará la relación vinculante de un objeto en la tercera tabla de relaciones.

book_obj = models.Book.objects.filter(pk=1).first()
book_obj.author.clear()

consulta de varias tablas

Antes de realizar operaciones de consulta de tablas múltiples, debe comprender un concepto, qué es una consulta directa y una consulta inversa .

Consulta directa: en qué tabla es la clave externa, consultar la tabla asociada es una consulta directa, como consultar la editorial a través de libros;

Consulta inversa: la tabla asociada busca la tabla donde se encuentra el campo de clave externa es una consulta inversa, como consultar libros a través de una editorial.

subconsulta

Si la consulta es más complicada, puede utilizar el método de subconsulta. La subconsulta significa consulta paso a paso, y el resultado obtenido por la primera consulta se utiliza como condición para la consulta posterior.

búsqueda directa

Reenviar consulta por campo, si se requieren múltiples resultados 外键字段.all(), ¿cómo juzgar que hay múltiples resultados de consulta? Si .all()el resultado obtenido sin sumar es 应用名.模型名.None, por ejemplo, first.Author.Noneen este caso, significa que no hay ningún error en la sentencia ORM, pero hay múltiples resultados de consulta, es necesario sumar .all(). Cuando solo hay un resultado de consulta, se obtiene un objeto modelo, y si hay más de uno, es un objeto QuerySet.

# 一对多关系查询:查询书籍主键为1的书籍由哪个出版社出版
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.publish  # Publish object (1)
print(res.name)

# 多对多关系查询:查询数据主键为1的作者
book_obj = models.Book.objects.filter(pk=1).first()
res = book_obj.author  # first.Author.None,说明结果有多个
res_many = book_obj.author.all()  # <QuerySet [<Author: Author object (1)>, <Author: Author object (2)>]>
    
# 一对一关系查询:查询作者lili的年龄
author_obj = models.Author.objects.filter(name='lili').first()
res = author_obj.author_detail
print(res.phone)

búsqueda inversa

Si la consulta inversa es uno a uno 表名小写, es verdadero si es uno a muchos o muchos a muchos 表明小写——set. Además, si hay varios resultados, debe agregarse después de indicar minúsculas _set.all(). El método de juzgar si hay múltiples resultados es lo mismo que reenviar La consulta es la misma. Cuando solo hay un resultado de consulta, se obtiene un objeto modelo, y si hay más de uno, es un objeto QuerySet.

# 一对多关系查询,查询出版社是东方出版社出版的书
publish_obj = models.Publish.objects.filter(name='东方').first()
res = publish_obj.book_set.all()  # <QuerySet [<Book: Book object (1)>, <Book: Book object (2)>]>

# 多对多关系查询,查询作者是lili写过的书
author_obj = models.Author.objects.filter(name='lili').first()
res = author_obj.book_set  # first.Book.None,说明有多个结果
res_many = author_obj.book_set.all()
print(res_many)  # <QuerySet [<Book: Book object (1)>]>

# 一对一关系查询,查询手机号是119的作者
author_detail_obj = models.AuthorDetail.objects.filter(phone='119').first()
res = author_detail_obj.author
print(res.name)

Unirse a consulta de tabla

La consulta de tabla conjunta es como la consulta de tabla conjunta de la declaración SQL en MySQ, excepto que la consulta de tabla conjunta de doble guión bajo (consulta de tabla cruzada) se usa en el ORM de django . Puede usar una línea de código para consultar los resultados de la consulta de la tabla conjunta, y la consulta de la tabla conjunta también sigue la relación directa e inversa.

búsqueda directa

# 一对多关系查询:查询书籍主键为1的出版社名称和书名
# 首先获取书籍对象,书籍是查询publish的基表,因此获取书名直接values('names')即可,而出版社的名字是通过外键字段跳到出版社的表中农,需要通过__找到需要的字段值
res = models.Book.objects.filter(pk=1).values('name', 'publish__name')  # <QuerySet [{'name': '哈利波特', 'publish__name': '东方'}]>

# 多对多关系查询,查询书籍主键为1的作者姓名
res = models.Book.objects.filter(pk=1).values('author__name')  # <QuerySet [{'author__name': 'lili'}, {'author__name': 'nana'}]>

# 一对一关系查询,查询lili的手机号和姓名
res = models.Author.objects.filter(name='lili').values('name', 'author_detail__phone').first()
print(res.get('name'), res.get('author_detail__phone'))

búsqueda inversa

# 一对多关系查询:查询数据主键为1的出版社名称和书的名字
res = models.Publish.objects.filter(book__id=1).values('name', 'book__name')  # <QuerySet [{'name': '东方', 'book__name': '哈利波特'}]>

# 多对多关系查询:查询书籍主键为1的作者姓名和书名
res = models.Author.objects.filter(book__id=1).values('name', 'book__name')  # <QuerySet [{'name': 'lili', 'book__name': '哈利波特'}, {'name': 'nana', 'book__name': '哈利波特'}]>

# 一对一关系查询:查询作者id是1作者的姓名和手机号
res = models.AuthorDetail.objects.filter(author__id=1).values('author__name', 'phone')  # <QuerySet [{'author__name': 'lili', 'phone': '119'}]>

# 综合大查询:查询书籍主键是1的作者的手机号,首先获取书籍对象,书籍关联了作者表,作者表又关联了作者详情表 
res = models.Book.objects.filter(pk=1).values('author__author_detail__phone')  # <QuerySet [{'author__author_detail__phone': '119'}, {'author__author_detail__phone': '120'}]>

consulta de agregación

La consulta de agregación generalmente se usa junto con la agrupación. La consulta de agregación usa algunas herramientas estadísticas, como el valor máximo, el valor mínimo, el valor promedio, etc., y el método de importación de la función de agregación. Si usa la función de agregación sin agrupar, debe usar en from django.db.models import Max, Min, Sum, Count, Avgel aggregate()método utilizado dentro.

from django.db.models import Min,Max,Sum,Count,Avg
# 统计书的平均价格
res = models.Book.objects.aggregate(Avg('price'))
print(res)
# 可以将这些聚合函数同时使用
res = models.Book.objects.aggregate(Max('price'),Sum('price'),Count('pk'))
print(res)

consulta de grupo

Las funciones de agregación se suelen utilizar junto con las de agrupamiento. El método de consulta de agrupamiento es utilizar annotatecomo base de agrupamiento el predeterminado models.分组依据, es decir, la clave principal de la tabla a agrupar. Si aparece annotate()antes del método , se agrupará values()según el valor especificado en . valuesLa consulta de grupo admite __la consulta entre tablas.

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

# 1.统计每本书的作者个数
res = models.Book.objects.annotate(author_num=Count('author')).values('name', 'author_num')  # author_num是自己定义的字段用来存储统计出来的每本书对应的作者个数,暂时存为表中的字段

# 2.统计每个出版社卖的最便宜的书的价格
res = models.Publish.objects.annotate(min_price=Min('book__price')).values('name', 'min_price')

# 3.统计不止一个作者的图书
# 先按照图书分组,算出每本书的作者数量,再过滤出作者数量大于1的数据
res = models.Book.objects.annotate(author_num=Count('author')).filter(author_num__gt=1).values('name', 'author_num')

# 4.查询每个作者出版书的总价格
res = models.Author.objects.annotate(sum_price=Sum('book__price')).values('name', 'sum_price')

Consulta F y Q

consulta f

La consulta F puede obtener el valor de datos de un determinado campo en la tabla, especialmente adecuado para operaciones de comparación entre dos campos en la tabla. Cuando opera datos de tipo de carácter, F no puede empalmar cadenas directamente y necesita ayuda Concat和Value.

from django.db.models import F

# 1.查询卖出数量大于库存数量的书籍
res = models.Book.objects.filter(sell_num__gt=F('inventory_num'))

# 将所有书籍的价格提升20元
res = models.Book.objects.update(price=F('price')+20)

ConcatLa consulta F requiere la ayuda de dos métodos para operaciones con cadenas Value:

# 将所有书的名称后面加上爆款两个字
from django.db.models.functions import Concat
from django.db.models import F, Value

models.Book.objects.update(name=Concat(F('name'),Value('爆款')))

Q consulta

Cuando se utiliza filter()el filtrado condicional, se utiliza la operación lógica Y. andSi desea cambiar varias condiciones de filtrado a oruna notrelación O, debe utilizar la consulta Q. |La relación expresada en la consulta Q or, la relación ~expresada not.

import django.db.models import Q

# 查询卖出数量大于100或者价格小于20的书籍
res = models.Book.objects.filter(~Q(sell_num__gt=100) | Q(price__lt=20))

Además, existe otro uso más avanzado de la consulta Q, es decir, el lado izquierdo de la condición de consulta también se puede convertir en una cadena.

# 先产生一个Q的实例
q = Q()
# 修改q的连接条件的关系
q.connector = 'or'
q.children.append(('sell_num__gt',100))
q.children.append(('price__lt',200))
res = models.Book.objects.filter(q)
# filter的条件是Q实例化产生的对象,每个条件默认还是and关系,可以修改
print(res)

transacción de inicio de django

MySQL tiene un mecanismo de transacción para garantizar la seguridad de los datos.Dado que django puede conectarse a MySQL, django puede admitir MySQL 事务机制. El siguiente código es para iniciar una transacción en django:

from django.db import transaction

try:
    with transaction.atomic():		 # 在with代码快内书写的所有orm操作都属于同一个事务
        ...
except Exception as e:
    print(r)
...

Supongo que te gusta

Origin blog.csdn.net/nhb687095/article/details/130475199
Recomendado
Clasificación