自学Django之路---Day3.Model、字段、查询

一些有用的小东西:

  1. 有时在改数据库或render一个页面时会没有自动提示,参考:
    • https://blog.csdn.net/cf313995/article/details/83117421
  2. return的快捷键,在返回时用 .re 回车即可
数据库中数据类型(大类)
  • 字符串
  • 数字
  • 时间
字段
字段意义
null若为true,将空值(None)存在数据库中,默认false
blank若为true,则允许该字段空白(""),默认false
db_column如果不指定就是属性名
db_index若为true,则会在表中为此字段创建索引
default默认值
primary key该字段会成为模型的主键
unique这个字段在表中要有唯一值(用户名、邮箱等)
Meta在Models定义的类中再定义Meta子类可以指定表名等信息
验证
class Person(models.Model):
    name = models.CharField(max_length=16, db_column='Name', unique='True')
    age = models.IntegerField(default=18, db_column='Age')
    sex = models.BooleanField(default=False, db_column='Sex')

    class Meta:
        db_table = 'People'

结果如下:
改数据库名字

objects

过滤器

可迭代
前两天用到了objects中的get、all,今天介绍下面几个方法:

  • filter, 过滤符合条件的数据
  • exclude, 返回不符合条件的数据
  • order_by, 排序
  • values, 将数据转换成字典,返回一个列表

单个数据

名称意义
get返回一个满足条件的对象,没有或找到多个都会触发异常,因此使用时要用try
first返回查询集中第一个对象,和下面的last有时会获取到相同的对象(bug),解决办法是先手动order_by
last返回查询集中最后一个对象
内置函数意义
count返回当前查询集中的对象个数,由于get毛病很多,因此查询信息(例如某个用户信息)时,虽然你知道结果唯一/不存在,但还是用count好一些,具体用法:先filter一下,然后对结果取count看看值是否为0
exists若查询集中有数据则返回true,上面count的用法使用exists也可以

切片
可以在查询后面直接写[x:y],表示取结果从下标2到下标4的数据,但要注意这和python中的切片不同

persons = Person.objects.all().order_by('age')[2:5]

all、filter、exclude等方法不会真正去查询数据库,只有当在迭代结果集或者获取单个对象属性的时候才会查数据库

可以在一起使用:filter.filter.exclude.x

一个例子(filter)

利用刚刚创建的Models来生成数据并查询数据:

def add_persons(request):
    for i in range(0, 15):
        person = Person()
        flag = random.randrange(100)
        person.name = 'caesar%d' % i
        person.age = flag % 30
        person.sex = flag % 2
        person.save()

    return HttpResponse('add success!')


def get_persons(request):
    persons = Person.objects.filter(age__gt=18).filter(age__lt=25)
    context = {
        "persons": persons
    }

    return render(request, 'person_list.html', context=context)

html:
<h3>Person_List</h3>
<ul>
    {% for person in persons %}
        <li>姓名:{{ person.name }} ,年龄: {{ person.age }} ,性别: {{ person.sex }}</li>
    {% endfor %}
</ul>

结果:
姓名:caesar8 ,年龄: 23 ,性别: True
姓名:caesar10 ,年龄: 19 ,性别: True
姓名:caesar11 ,年龄: 24 ,性别: False
姓名:caesar12 ,年龄: 20 ,性别: False
姓名:caesar13 ,年龄: 24 ,性别: False

注: filter(age__gt=18)是指找出age大于18的,
filter(age__lt=25)是找出age小于25的。

一个例子(order_by)

如果用all来查询,那么结果是从头到尾呈现的:

姓名:caesar0 ,年龄: 6 ,性别: False
姓名:caesar1 ,年龄: 7 ,性别: True
姓名:caesar2 ,年龄: 13 ,性别: True
姓名:caesar3 ,年龄: 13 ,性别: True
姓名:caesar4 ,年龄: 27 ,性别: True
姓名:caesar5 ,年龄: 26 ,性别: False
姓名:caesar6 ,年龄: 2 ,性别: False
姓名:caesar7 ,年龄: 5 ,性别: True
姓名:caesar8 ,年龄: 23 ,性别: True
姓名:caesar9 ,年龄: 18 ,性别: False
姓名:caesar10 ,年龄: 19 ,性别: True
姓名:caesar11 ,年龄: 24 ,性别: False
姓名:caesar12 ,年龄: 20 ,性别: False
姓名:caesar13 ,年龄: 24 ,性别: False
姓名:caesar14 ,年龄: 7 ,性别: True
姓名:peter ,年龄: 23 ,性别: True
姓名:Bob ,年龄: 18 ,性别: True

加了order_by之后:

persons = Person.objects.all().order_by('-id')
结果:
姓名:Bob ,年龄: 18 ,性别: True
姓名:peter ,年龄: 23 ,性别: True
姓名:caesar14 ,年龄: 7 ,性别: True
姓名:caesar13 ,年龄: 24 ,性别: False
姓名:caesar12 ,年龄: 20 ,性别: False
姓名:caesar11 ,年龄: 24 ,性别: False
姓名:caesar10 ,年龄: 19 ,性别: True
姓名:caesar9 ,年龄: 18 ,性别: False
姓名:caesar8 ,年龄: 23 ,性别: True
姓名:caesar7 ,年龄: 5 ,性别: True
姓名:caesar6 ,年龄: 2 ,性别: False
姓名:caesar5 ,年龄: 26 ,性别: False
姓名:caesar4 ,年龄: 27 ,性别: True
姓名:caesar3 ,年龄: 13 ,性别: True
姓名:caesar2 ,年龄: 13 ,性别: True
姓名:caesar1 ,年龄: 7 ,性别: True
姓名:caesar0 ,年龄: 6 ,性别: False

默认是按照id排序,如果想换成年龄,里面参数传’age’即可,若想降序,则’-age’。

一个例子(values)

对上面的代码稍作更改:

persons = Person.objects.all().order_by('age')
p_values = persons.values()
print(p_values)
结果:
<QuerySet [
{'id': 7, 'name': 'caesar6', 'age': 2, 'sex': False}, 
{'id': 8, 'name': 'caesar7', 'age': 5, 'sex': True},
...,]>

可以看到这个形式类似json,方便以后做转换

查询条件

格式:

  • 属性__运算符=值

例如前面提到的:

  • age__gt=17 : 年龄>17
  • age__lt=25 : 年龄<25

以及:

  • in : 在某一集合中
  • contains : like
  • startswith/endswith : 以…开始/结束
  • exact :

对时间的查询:

  • date = Date.objects.filter(time__year=2020) 查询年份
  • date = Date.objects.filter(time__month=10) 查询月份
    但要注意查月份由于时区的问题会导致无法输出结果,解决办法是:
    • 关闭Django中自定义的时区(settings->USE_TZ = True设为False即可)
    • 在数据库中创建对应的时区表(不太好)
models.py
class Date(models.Model):
    time = models.DateTimeField(auto_now_add=True)
    num = models.CharField(max_length=16, unique=True)

views.py
def get_date(request):
    date = Date.objects.filter(time__month=6)
    for i in date:
        print(i.num)

创建对象

之前是用a = A()的形式创建对象,还可以用下面的方式:

  • person = Person.objects.create(name=‘peter’, age=‘23’, sex=‘1’)

  • 定义一个类方法,让这个方法返回对象:

    @classmethod
    def create(cls, name, age=18, sex=1):
        return cls(name=name, age=age, sex=sex)
    

    然后在views中:

    person = Person.create('Bob')
    

当然也可以用类直接创建对象:Person(name=x, age=y, sex=z),但这样需要将参数全都写上(版本的问题?不太清楚),因此用类方法的形式可以设置默认参数,并且可以对传过来的参数进行处理。

级联查询

现有学生和班级两个表,学生的外键是班级的主键,想查询某个学生所在的班级:

grades = Grade.objects.filter(student__s_name='xxx')

聚合函数

在sql中,Max、Avg、Sum等函数可由如下形式实现:

# 注意导包
from django.db.models import Max, Min, Sum, Avg, Count
students.object.aggregate(Max('age'))

F对象

用于比较表中的两个字段

nameboygirl
A105
B1230
C3020

现在想看看男比女少的公司都有哪些,代码如下:

companies = Company.objects.filter(boy__lt=F('girl'))
for company in companies:
    print(company.num)

结果:
B

如果想看看男生比女生多超过8个人的公司:

companies = Company.objects.filter(girl__lt=F('boy')-8)

Q对象

可以支持逻辑运算
如果想获取男生多于1且女生多于5的公司,可以这么写:

res = Company.objects.filter(boy__gt=1).filter(girl__gt=5)

使用Q对象之后:

companies = Company.objects.filter(Q(boy__gt=1) & Q(girl__gt=1))

可以重写Django方法

有如下model:

class Animal(models.Model):
    a_name = models.CharField(max_length=16)
    is_delete = models.BooleanField(default=False)

数据是:
cat,0
cow,1
dog,0

现在想找is_delete为False的数据,可以这么写:

animals = Animal.objects.filter(is_delete=False)

这个objects是Manager类型的一个对象,是隐性的(显示的调用它会报错;a_m=models.Manager()会报错),如果没有指定管理器,Django会自动创建模型管理器;但是如果自定义了模型管理器,那么objects就不会存在,也就是不会为我们生成模型管理器。
所以我们能不能实现这样一个东西,即调用all方法返回的就是is_delete=False的东西?

通过查看all()方法源码,发现其实调用的是get_queryset,因此重写这个方法即可:
class AnimalManager(models.Manager):
    def get_queryset(self):
        return super(AnimalManager, self).get_queryset().filter(is_delete=False)


class Animal(models.Model):
    a_name = models.CharField(max_length=16)
    is_delete = models.BooleanField(default=False)

    a_m = AnimalManager()

views:
 animals = Animal.a_m.all()
    for animal in animals:
        print(animal.a_name)

    return HttpResponse('查询动物成功!')

可以看到,Animal.a_m.all()这句就能把is_delete=False的数据给找出来而不必再每次都写filter。
当然,也可以把a_m改成objects这样在views中根本没改变代码就实现了功能,如果想恢复all本来的功能只需要把a_m = AnimalManager()注释掉即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值