django笔记(2)

1.数据库配置

  • 安装myslq依赖

pip install mysqlclient

  • 在项⽬的 settings.py ⽂件中找到 DATABASES 配置项,将其信息修改为
DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.mysql', #mysql数据库引擎
    'NAME': 'test', #数据库名
    'HOST':'localhost', #数据库服务器地址
    'USER': 'test', #mysql数据库⽤户名
    'PASSWORD': 'test123', #密码
    'PORT':3306, #端⼝号,可选
    }
}

2.ORM

  • 对象关系映射(Oject Relational Mapping,简称ORM)模式是⼀种为了解决⾯向对象与关系数据库存在的互不匹配的现象的技术。简单的说,ORM是通过使⽤描述对象和数据库之间映射的元数据,⾃动⽣成sql语句,将程序中的对象⾃动保存到关系数据库中
  • 优点
    • 隐藏了数据库访问的细节,简化了sql的使⽤,提⾼了开发效率解耦业务逻辑层(view)和数据处理层(model),简化了开发流程,提⾼了
    • 系统的可移植性
    • 提⾼了安全性
  • 缺点
    • 执⾏效率低
    • 对复杂sql⽆能为⼒
    • 增加了学习成本
  • 对象和数据库关系映射
对象数据库
对象记录
属性字段

3.定义模型类

from django.db import models
class 模型名(models.Model):
    属性名 = models.字段名(字段选项/参数)
    .....
    class Meta: #可选,任何⾮字段的设置可以写到Meta中
        db_table = 'user' #指定表名为uesr
  • 一个模型类对应一个表
  • 字段类型
字段名称字段说明参数
AutoField⼀个根据实际Id⾃动增⻓的IntegerField(通常不指定 ⾃动⽣成)
CharField字符串,默认的表单样式是TextInputmax_length=字符⻓度
TextField⼤⽂本字段,⼀般超过4000使⽤,默认的表单控件是Textarea
IntegerField整数
DecimalField使⽤python的Decimal实例表示的⼗进制浮点数max_digits总位数;decimal_places⼩数位数
FloatField⽤Python的float实例来表示的浮点数
BooleanFieldtrue/false 字段,此字段的默认表单控制是CheckboxInput
NullBooleanField⽀持null、true、false三种值
DateField使⽤Python的datetime.date实例表示的⽇期,该字段默认对应的表单控件是⼀个TextInputauto_now和auto_now_add、default这三个参数不能同时共存
TimeField使⽤Python的datetime.time实例表示的时间参数同DateField
DateTimeField使⽤Python的datetime.datetime实例表示的⽇期和时间参数同DateField
ImageField继承了FileField的所有属性和⽅法,但对上传的对象进⾏校验,确保它是个有效的image
  • auto_now: 每次保存对象时,⾃动设置该字段为当前时间,⽤于"最后⼀次修改"的时间戳,它总是使⽤当前⽇期,默认为false

  • auto_now_add: 当对象第⼀次被创建时⾃动设置当前时间,⽤于创建的时间戳,它总是使⽤当前⽇期,默认为false

  • 字段选项

可选参数说明
null如果 True ,Django将 NULL 在数据库中存储空值。默认是 False 。不要在字符串字段上使⽤。null是数据库范畴的概念
blank如果 True ,该字段允许为空。默认是 False 。同null不同,如果字段有 blank=True ,则表单验证将允许输⼊空值。如果字段有 blank=False ,则需要该字段。
db_column⽤于此字段的数据库列的名称。如果没有给出,Django将使⽤该字段的名称。
db_index如果 True ,将为此字段创建数据库常规索引。
unique如果 True ,该字段在整个表格中必须是唯⼀的。
primary_key如果 True ,此字段是模型的主键。
default默认值 当前字段如果不给值则执⾏默认值
  • Meta中常⽤设置
名称说明
db_table数据库中的表名
abstract当设置为True时,说明当前模型是抽象基类
managed如果设置False,则迁移不会创建或删除表,默认是True
ordering⽤于记录排序,ordering = ['pub_date']或降序ordering = ['-pub_date']

4.创建模型类

from django.db import models
from django.utils import timezone


class User(models.Model):
    uid = models.AutoField(primary_key=True)  # ⾃增主键
    uname = models.CharField(max_length=60)
    password = models.CharField(max_length=32)
    user_type = ((1, '超级管理员'), (2, '普通⽤户'))
    type = models.IntegerField(default=2, choices=user_type)
    regtime = models.DateTimeField(default=timezone.now)
    ip = models.IntegerField(null=True)
    login_type = ((1, '允许登录'), (2, '禁⽌登录'))  # ⽤户⾃定义类型对应mysql的enum类型
    allowed = models.IntegerField(default=1, choices=login_type)
    email = models.CharField(max_length=100, null=True)
    memo = models.CharField(max_length=1000, null=True)

    class Meta:
        db_table = 'user'  # 表名
  • python manage.py makemigrations; python manage.py migrate
  • 任何对字段或表的修改都需要重新迁移
  • 也可以创建好数据库后反向生成model

python manage.py inspectdb > App/models.py

4.1.模型增删查改

  • python manage.py shell
### 增加用户
In [1]: from app02.models import User

In [2]: from hashlib import md5

In [3]: user = User(uname='admin',password=md5(b'123').hexdigest())

In [4]: user.save()

In [9]: User.objects.create(uname='妈咪哄',password='111') # 第二个用户
In [13]: User.objects.bulk_create(User.objects.create(uname='哈哈',password='111'),User.objects.create(uname='嘻嘻',password=
    ...: '111')) # 创建多个用户
### 查询用户
In [6]: u1 = User.objects.get(pk=1)

### 修改用户
In [15]: u2 = User.objects.get(pk=2)

In [16]: u2.uname = '⼩甜甜'

In [17]: u2.save()

In [18]: users = User.objects.all()

In [19]: users.update(password=md5(b'345').hexdigest()) # 批量修改
Out[19]: 5

### 删除用户
In [14]: user.delete()

5.模型查找

  • 要从数据库检索数据,⾸先要获取⼀个查询集(QuerySet),查询集表示从数据库获取的对象集合,它可以有零个,⼀个或多个过滤器。返回查询集的⽅法,称为过滤器,过滤器根据给定的参数缩⼩查询结果范围,相当于sql语句中where或limit

  • 在管理器上调⽤过滤器⽅法会返回查询集

  • 查询集经过过滤器筛选后返回新的查询集,因此可以写成链式过滤

  • 惰性执⾏:创建查询集不会带来任何数据库的访问,直到调⽤数据时,才会访问

  • 数据库以下对查询集求值:迭代、切⽚、序列化、与if合⽤、repr()/print()/len()/list()/bool()

管理器的⽅法返回类型说明
模型类.objects.all()QuerySet返回表中所有数据
模型类.objects.filter()QuerySet返回符合条件的数据
模型类.objects.exclude()QuerySet返回不符合条件的数据
模型类.objects.order_by()QuerySet对查询结果集进⾏排序
模型类.objects.values()QuerySet返回⼀个Queryset,其中每个对象为⼀个字典
模型类.objects.values_list()QuerySet和values()基本相同,但每个对象是⼀个元组
模型类.objects.reverse()QuerySet对排序的结果反转
模型类.objects.only(字段)QuerySet只显示指定字段
模型类.objects.defer(字段)QuerySet去除指定字段
模型类.objects.get()模型对象返回⼀个满⾜条件的对象;如果没有找到符合条件的对象,会引发模型类.DoesNotExist异常;如果找到多个,会引发模型类.MultiObjectsReturned 异常
模型类.objects.first()模型对象返回第⼀条数据
模型类.objects.last()模型对象返回最后⼀条数据
模型类.objects.earliest()模型对象根据指定字段返回最早增加的记录
模型类.objects.latest(field)模型对象根据field字段返回最近增加记录
模型类.objects.exists()bool判断查询的数据是否存在
模型类.objects.count()int返回查询集中对象的数⽬
  • all()
User.objects.all()
  • fifilter(**kwargs) 返回QuerySet包含与给定查找参数匹配的新查询集。
# select * from user
User.objects.filter()

# select * from user where uid > 1 and type = 2
User.objects.filter(uid__lt=2, type=2)

# 链式调用,当匹配的条件是有关联关系的时候可能会出现意外的结果
User.objects.filter(uid__lt).filter(type=2)
  • exclude(**kwargs)
# select * from user where name != 'admin'
User.objects.exclude(name='admin')
  • order_by(*fields)
    • 可以有多个字段名,默认是生序,加上"-"为倒叙
#按uid升序排列 等价于 order by uid

User.objects().order_by('uid')

#按uid降序排列 等价于 order by uid desc

User.objects.order_by('-uid')

#多列排序 等价于 order by password,uid desc

User.objects.order_by('password','-uid')
  • values()
#返回所有字段

User.objects.values()

#返回数据:

[{'uid': 2, 'uname': '⼩甜甜', 'password':

'59f2443a4317918ce29ad28a14e1bdb7'type': '普通⽤户', 'regtime':

None, 'ip': None, 'allowed': '允许登录', 'email': None, None},...]

#返回指定字段

User.objects.values('uname','password')

[{'uname': '⼩甜甜', 'password':

'59f2443a4317918ce29ad28a14e1bdb7'},...]
  • distinct() 去重
User.objects.values('uname','password').distinct()

5.1.返回单值对象

下面方法,返回模型对象

  • get()只匹配一条数据
user = User.objects.get(pk=1)
user = User.objects.get(uid__lt=20) # 报错,匹配到了多个数据
user = User.objects.get(uid=-1) # 没有匹配上
  • first()、last()
User.objects.all().first()
User.objects.all().last()
  • count()
User.objects.count()
  • exists():判断是否有记录
User.objects.filter(uid__lt=3).exists()
  • 查询集限制
User.objects.all()[0] #等同于:limit 0,1

User.objects.all()[2] #等同于:limit 2,1

User.objects.all()[0:2] #等同于limit 2

User.objects.all()[:2]

5.2.字段查询

操作符说明实例
exact"="操作uname__exact='admin'
iexact不区分大小写"="uname__iexact='admin'
contains模糊查询,相当于%value%uname__contains='admin'
icontains不区分大小写%value%uname__icontains='admin'
startswith以...开头uanme__startswith='a'
istartswith不区分大小写uname__istartswith='a'
endwith以...结尾uname__endwith='m'
iendwith不区分大小写uname__iendwith='m'
isnull判断是否为空uname__isnull=True
in包含uid__in=[1,2,3]
range范围(between and )uid__range=[1,3]
year、month、day、week_day、hour、minute、second日期查询date__year=2008

5.3.统计查询

  • from django.db.models import Max,Min,Sum,Avg,Count
#统计记录总数: select count(*) from user

User.objects.aggregate(Count('uid')) #{'uid__count': 4}

User.objects.aggregate(Max('uid')) #{'uid__max': 5}

User.objects.aggregate(Min('uid'))

5.4.Q对象和F对象

  • Q对象可以对关键字参数进⾏封装,从⽽更好的应⽤多个查询,可以组合&

(and)、|(or)、~(not)操作符。

#原⽣sql:select * from user where uid = 2 or uid = 3

User.objects.filter(Q(uid=2)|Q(uid=3))

User.objects.filter(Q(uid__gte=2) & Q(uid__lte=3))

User.objects.filter(~Q(uid__gte=2))
  • F对象:⽤于⽐较表中两个字段
#等价sqlselect * from user where uid < type

User.objects.filter(uid__lte = F('type'))

5.5.原始sql

users = User.objects.raw("select * from user")

users = User.objects.raw("select * from user where

username='{}'".format('单强'))

print("select * from user where username='{}'".format('单强'))

users = User.objects.raw("select * from user where

username='{}'".format('单强'))

users = User.objects.raw("select * from user where username=%s",

["sddfsdf' or '1"])

print(list(users))

print(type)

6.模型对应关系

6.1.一对一

class Student(models.Model):
    sno = models.CharField(max_length=6, primary_key=True)
    sname = models.CharField(max_length=100, null=False)
    ssex = models.CharField(max_length=2, default='男', null=True)
    sage = models.IntegerField(null=True)
    sclass = models.CharField(max_length=10, null=True)

    def __str__(self):
        return "no:{},name:{}".format(self.sno, self.sname)

    class Meta:
        db_table = 'student'


class Archives(models.Model):
    idcard = models.CharField(max_length=18, unique=True)
    address = models.CharField(max_length=200, null=True)
    # on_delete=models.CASCADE 级联删除,删除学⽣会连同档案⼀块删除
    student = models.OneToOneField(Student, on_delete=models.CASCADE)

    def __str__(self):
        return "{},{}".format(self.idcard, self.address)

    class Meta:
        db_table = 'archives'
  • 操作
### 创建 ###
student = Student()
student.sno = '180502'
student.sname = '杨康'
student.sage = 22
student.save()


stu = Student.objects.get(pk='180502')
arc = Archives()
arc.idcard = '130098384893838953'
arc.student = stu #学⽣对象必须已经保存到数据库,否则错误
arc.save()

### 查询 ###
# 获取学⽣信息
student = Student.objects.first()
print(student)
# 通过学⽣对象获取档案信息
archive = student.archives
print(archive)

archive = Archives.objects.first()
#通过档案获取关联学⽣信息
student = archive.student

### 跨关系查询 ### 
#根据档案查学⽣
# student = Student.objects.get(archives__pk=1)
student =Student.objects.get(archives__idcard='13009488384383838')

#根据学⽣查档案
archive = Archives.objects.get(student__sno='180501')
  • on_delete
    • CASECADE:默认删除联级对象
    • PROTECT:当从表有记录,删除主表会报错,从表没有记录,是可以删除的
    • SET_NULL:外键本身设置为空
    • SET_DEFAULT:设置默认值
    • DO_NOTHING:什么都不做

6.2.一对多

class Publisher(models.Model):
    pname = models.CharField(max_length=100, null=True)

    def __str__(self):
        return self.pname

    class Meta:
        db_table = 'publisher'


class Book(models.Model):
    bname = models.CharField(max_length=200, null=True)
    # 多对⼀模型通过ForeignKey表示多对⼀
    # 如果publisher定义在book之后,第⼀个参数应该⽤字符串'Publisher'
    publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE,
                                  null=True,
                                  db_column='pid',  # 表中字段名
                                  related_name='books')

    def __str__(self):
        return self.bname

    class Meta:
        db_table = 'book'
### 创建 ###
pub = Publisher.objects.first()
pub.books.create(bname='红岩')
book = Book.objects.get(pk=1)
pub.books.add(book) #book必须已经保存到数据库
books = Book.objects.filter(pk__lt=5)
pub.books.bulk_create(list(books))

### 删除和更新 ###
pub = Publisher.objects.first()
pub.books.all().delete() #删除出版社出版的所有图书
pub.books.all().update(bname='ddd')

### 查询 ###
pub = Publisher.objects.first()
print(pub)
# pub = Publisher()
book = pub.book_set.all()
print(book)

# 根据图书获取出版社
pub = Publisher.objects.get(book__bname='花样年华927937')
print(pub)
# 根据出版社获取图书
books = Book.objects.filter(publisher__pname='科技出版社5829')
print(books)

6.3.多对多

class Buyer(models.Model):
    bname = models.CharField(max_length=30)
    level = models.IntegerField(default=1)


class Goods(models.Model):
    gname = models.CharField(max_length=100)
    price = models.FloatField()
    buyer = models.ManyToManyField(Buyer)  # 这种写法⾃动⽣成第三张表,但我们⽆法直接控制

    def __str__(self):
        return self.gname + " " + str(self.price)
### 创建 ###
buyer1 = Buyer(bname="df")
buyer1.save()
buyer2 = Buyer(bname="df2")
buyer2.save()
good1 = Goods(gname="good1", price=13.5)
good1.save()
good2 = Goods(gname="good2", price=13.4)
good2.save()
buyer1.goods_set.add(good1)
buyer1.goods_set.add(good2)
good1.buyer.add(buyer1)
good1.buyer.add(buyer2)

### 删除 ###
buyer = Buyer.objects.get(pk=13)
goods = Goods.objects.filter(pk__lt=10)
buyer.goods_set.clear() #删除所有商品
buyer.goods_set.remove(Goods.objects.get(pk=2))

### 查询 ###
buyer = Buyer.objects.get(pk=13)
res = buyer.goods_set.all()
print(res)

goods = Goods.objects.last()
buyer = goods.buyer.all()
print(buyer)
return HttpResponse("由商品查询买家")

7.模型继承

  • 默认模型就是允许继承的,但是默认的继承处理⽅式不是很合理
    • 默认在⽗类中定义的字段会存在⽗类的表中,⼦类的数据通⽤部分会存在⽗表中,⼦类特有数据会在⼦表中,⼦类通过外键进⾏级联

    • 默认⽅式⽐较垃圾,效率⽐较低

  • 开发中,需要将⽗类抽象化,在元信息中使⽤abstract=True
    • 抽象化的⽗类不会再数据库⽣成表了
    • ⼦类会将⽗类中的通⽤数据,复制到⼦表中
class BaseModel(models.Model):
    create_at = models.DateTimeField(auto_now_add=True)
    update_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        abstract = True

class TestModel(BaseModel):
    pass