模型

from django.db import models


class UserType(models.Model):
# 用户类型
caption = models.CharField(max_length=16)


class UserInfo(models.Model):
# 用户信息
username = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType')

数据

sqlite> SELECT * FROM app01_userinfo;
1|张珊|12344|1
2|李四|123456|3

查询

  • 基本查询

    In [10]: UserInfo.objects.all()
    Out[10]: <QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
  • values

    In [12]: UserInfo.objects.all().values("username")
    Out[12]: <QuerySet [{'username': '张珊'}, {'username': '李四'}]>
  • values_list

    In [14]: UserInfo.objects.all().values_list("username", "pwd")
    Out[14]: <QuerySet [('张珊', '12344'), ('李四', '123456')]>

一对多

模型定义

class UserType(models.Model):
# 用户类型 CEO 经理 主管 组长 员工 ...
caption = models.CharField(max_length=16)



class UserInfo(models.Model):
# 用户信息
username = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForeignKey('UserType')
# user_type_id(生成表中字段名)

  • 创建

第1种方法

In [3]: UserInfo.objects.create(username='老王',pwd='123',user_type=UserType.objects.get(id=2)) 
Out[3]: <UserInfo: UserInfo object>

多一次数据库查询

第2种方法

In [4]: UserInfo.objects.create(username='王五',pwd='123',user_type_id=2)
Out[4]: <UserInfo: UserInfo object>

第三种方法

data = {'pwd': '123', 'user_type_id': 2, 'username': '张无忌'}
In [13]: u = UserInfo(**data)
In [14]: u.save()

第四种方法

In [15]: u = UserInfo()

In [16]: u.username = "周芷若"

In [17]: u.pwd = "123"

In [18]: u.user_type = 1 # 报错
In [19]: u.user_type_id = 1
In [20]: u.save()

  • 查询

方法1

In [30]: u_type_id = UserType.objects.get(caption="CE0").id

In [31]: UserInfo.objects.filter(user_type_id=u_type_id)
Out[31]: <QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>

先查找出 外键id 主表过滤外键id集合

方法2

In [32]: UserInfo.objects.filter(user_type__caption='CE0')
Out[32]: <QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>

# 通过models模型定义的字段名(不是生成数据库的字段) user_type__caption 字段名__外键关联表的字段(两个下划线)

# 能操作方法和单表一致
In [38]: UserInfo.objects.filter(user_type__id__gte=1)
Out[38]: <QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>


In [39]: UserInfo.objects.filter(user_type__caption='CE0').values("username", 'pwd')
Out[39]: <QuerySet [{'pwd': '12344', 'username': '张珊'}, {'pwd': '123456', 'username': '李四'}, {'pwd': '123', 'username': '周芷若'}]>

方法3

只要是有关键关联 可以使用多次两下划线 __
2、三张表跨表操作
class Somthing(models.Model):
name = models.CharField(max_length=32)

class UserType(models.Model):
catption = models.CharField(max_length=32)
s = models.ForignKey('Somthing')
# ceo,经理 , 组长,...

class UserInfo(models.Model):

user = models.CharField(max_length=32)
pwd = models.CharField(max_length=32)
user_type = models.ForignKey('UserType')

UserInfo.objects.filter(user_type__s__name='xx')

多对多

class Book(models.Model):
name = models.CharField(max_length=64, verbose_name="书名")


class Tag(models.Model):
# 文学 技术 地理 文科 理科 西方文学...
tag_name = models.CharField(max_length=32, verbose_name="标签")
b = models.ManyToManyField("Book", verbose_name="关联书名")

会生成三张表
应用名_book
应用名_tag

应用名_tag_b (多对多中间表"b"是模型中的的字段来命名) 此表保存书名的id和标签id
隐式创建

数据

sqlite> SELECT * FROM app01_book;
1|莎士比亚
2|悲惨世界
3|性能之巅
4|高性能MySQL

sqlite> SELECT * FROM app01_tag;
1|IT
2|西方文学
3|文科
4|理科
5|技术

sqlite> SELECT * FROM app01_tag_b;
sqlite>


  • add

    In [11]: tag = Tag.objects.get(id=2)
    In [12]: tag.tag_name
    Out[12]: '西方文学'

    In [13]: Book.objects.get(id=1).name
    Out[13]: '莎士比亚'
    In [14]: Book.objects.get(id=2).name
    Out[14]: '悲惨世界'


    In [15]: tag.b.add(1) # 将 tag_id=2, book_id=1插入 第三张关联表中
    In [16]: tag.b.add(2) # 将 tag_id=2, book_id=1插入 第三张关联表中


    批量插入
    In [17]: tag.b.add(1,2,3,4)
    # 将 tag_id=2, book_id=1插入 第三张关联表中
    # 将 tag_id=2, book_id=2插入 第三张关联表中
    # 将 tag_id=2, book_id=3插入 第三张关联表中
    # 将 tag_id=2, book_id=4插入 第三张关联表中

    In [18]: tag.b.add(*[1,2,3,4]) # 效果同上相当于参数解包
  • tag = Tag.objects.get(id=2)

    In [19]: tag.b.remove(1) # 将 tag_id=2, book_id=1 删除此记录
    In [20]: tag.b.remove(2,4) # 将 tag_id=2, book_id=2 tag_id=2, book_id=4 删除此记录
    In [21]: tag.b.remove(*[1,2,3,4]) # 原理同上


    clear
    In [22]: tag.b.clear() # 相当于 DELECT FROM app01_tag_b WHERE tag_id=2;
  • In [1]: from app01.models import *
    In [2]: tag = Tag.objects.get(id=2)

    In [4]: tag.b.set([2,3]) # 1、隐含操作 DELECT FROM appo1_tag_b WHER tag_id = 2
    # 2、 将 tag_id=2, book_id=2 tag_id=2, book_id=3 插入
  • In [2]: tag = Tag.objects.get(id=2)

    In [12]: tag.b.all()
    Out[12]: <QuerySet [<Book: Book object>, <Book: Book object>]>



    通过标签的外键查书名

    In [34]: tag = Tag.objects.prefetch_related('b').filter(id=2).first()

    In [37]: for i in tag.b.all(): # 因为使用prefetch_related 此循环没有再次执行sql查找
    ...: print (i.name)
    ...:
    莎士比亚
    悲惨世界
    性能之巅
    高性能mysql

    使用 prefetch_related 可以优化减少查询的次数

    mysql> SELECT `app01_tag`.`id`, `app01_tag`.`tag_name` FROM `app01_tag` WHERE `app01_tag`.`id` = 2 ORDER BY `app01_tag`.`id` ASC LIMIT 1;
    +----+--------------+
    | id | tag_name |
    +----+--------------+
    | 2 | 西方文学 |
    +----+--------------+
    1 row in set (0.00 sec)

    mysql> SELECT `app01_tag_b`.`tag_id` AS `_prefetch_related_val_tag_id`, `app01_book`.`id`, `app01_book`.`name`
    FROM `app01_book`
    INNER JOIN `app01_tag_b` ON `app01_book`.`id` = `app01_tag_b`.`book_id`
    WHERE `app01_tag_b`.`tag_id` IN (2) ;
    +------------------------------+----+----------------+
    | _prefetch_related_val_tag_id | id | name |
    +------------------------------+----+----------------+
    | 2 | 1 | 莎士比亚 |
    | 2 | 2 | 悲惨世界 |
    | 2 | 3 | 性能之巅 |
    | 2 | 4 | 高性能mysql |
    +------------------------------+----+----------------+
    4 rows in set (0.00 sec)