Django模型是与数据库相关的,与数据库相关的代码一般写在models.py中,Django支持sqlite3,MySQL,PostgreSQL等数据库,只需要在settings.py中配置即可,不用更改models.py中的代码,丰富的API极大的方便了使用。
1、新建项目和应用
django-admin.py startproject learn_models # 新建一个项目
cd learn_models/ # 进入到该项目的文件夹
ls # 查看该文件下内容
# learn_models manage.py
python manage.py startapp people # 新建一个people应用(app)
ls # 查看该文件下内容
# learn_models manage.py people
补充:新建app也可以用python manage.py startapp people,需要指出的是,django-admin.py是安装Django后多出的一条命令,并不是运行的当前目录下的django-admin.py(当前目录下去也没有),但创建项目会生成一个manage.py文件
那么project和app有什么关系呢?
一个项目一般会有多个应用,一个应用也可以用在多个项目中。
2、添加应用
建工我们新建的应用(people)添加到settings.py中的INSTALLED_APPS中,也就是告诉Django有这么一个应用。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'people',
]
# 备注: 这一步是干什么呢? 新建的 app 如果不加到 INSTALL_APPS 中的话,django 就不能自动找到app中的模板
文件(app-name/templates/下的文件)和静态文件(app-name/static/中的文件) , 后面你会学习到它们分别用来
干什么.
3、修改models.py
我们打开people/models.py文件,修改其中的代码如下:
from django.db import models
# Create your models here.
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
# 我们新建了一个Person类,继承自models.Model,一个人有姓名和年龄
4、创建数据表
我们来同步以下数据库(我们是用默认的数据库SQLite3,无需配置)
python manage.py makemigrations
# 显示内容如下
# Migrations for 'people':
# people/migrations/0001_initial.py
# - Create model Person
python manage.py migrate
# 显示内容如下:
# Operations to perform:
# Apply all migrations: admin, auth, contenttypes, people, sessions
# Running migrations:
# Applying contenttypes.0001_initial... OK
# Applying auth.0001_initial... OK
# Applying admin.0001_initial... OK
# Applying admin.0002_logentry_remove_auto_add... OK
# Applying contenttypes.0002_remove_content_type_name... OK
# Applying auth.0002_alter_permission_name_max_length... OK
# Applying auth.0003_alter_user_email_max_length... OK
# Applying auth.0004_alter_user_username_opts... OK
# Applying auth.0005_alter_user_last_login_null... OK
# Applying auth.0006_require_contenttypes_0002... OK
# Applying auth.0007_alter_validators_add_error_messages... OK
# Applying auth.0008_alter_user_username_max_length... OK
# Applying people.0001_initial... OK
# Applying sessions.0001_initial... OK
# 我们会看到,Django生成了一系列的表,也生成了我们新建的people_person这个表,那么如何使用这个表呢?
5、使用Django提供的QuerySet API
Django提供了丰富的API,下面演示如何使用它。
python manage.py shell # 在其中可以执行 Model 类的方法,向数据库中插入/更新数据等一系列操作。
# Python 3.4.3 (default, Aug 25 2017, 11:42:22)
# Type 'copyright', 'credits' or 'license' for more information
# IPython 6.2.0 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from people.models import Person # 引入models中的Person这个类
In [2]: Person.objects.create(name='liu', age='12') # 新建一个用户liu,那么如何从数据库中查询到他呢?
Out[2]: <Person: Person object>
n [3]: Person.objects.get(name='liu')
Out[3]: <Person: Person object>
In [4]:
# 我们用了一个.objects.get()方法查询出复合体爱建的对象,但是大家注意,查询姐结果中显示<Person: Person object>,这里并没有显示出与liu的相关信息,如果用户多了就无法知道查询出来的到底是谁,查询结果是否正确,我们重新修改以下people/models.py
name和age等字段中不能有__(双下划线,因为在Django QuerySet API中有特殊含义,用于关系,包含,不区分大小写,以什么开头或结尾,日期的大于小于,正则等)
也不鞥有python中的关键字,name是合法的,student_name也是合法的,但是student__name不合法,try,class,continue也不合法,因为他们是python的关键字(import keyword;print(keyword.kwlist)可以打出所有的关键字)
from django.db import models
# Create your models here.
class Person(models.Model):
name = models.CharField(max_length=30)
age = models.IntegerField()
# 重写name字段
def __str__(self):
return 'Person object (%s %s)' % (self.name, self.age)
quit()或exit()退出python shell,重复上面的操作,我们就可以看到:
In [1]: from people.models import Person
In [2]: Person.objects.get(name='liu')
Out[2]: <Person: Person object (liu 12)>
In [3]: Person.objects.get(age='12')
Out[3]: <Person: Person object (liu 12)>
In [4]:
新建一个对象的方法有以下几种:
1. Person.object.create(name=name, age=age)
2. p = Person(name='liu', age=12)
p.save()
3. p = Person(name='liu')
p.age = 12
p.save()
4. Person,object.get_or_create(name='liu', age=12)
# 这种方法式防止重复很好的方法,但是速度要相对慢一些,返回一个元组,第一个为Person对象,第二个为True或False,新建时返回的是True,已经存在时返回False。
In [11]: Person.objects.get_or_create(name='li', age=11)
Out[11]: (<Person: Person object (li 11)>, True)
In [12]: Person.objects.get_or_create(name='li', age=11)
Out[12]: (<Person: Person object (li 11)>, False)
获取对象有以下方法:
1. Person.objects.all()
2. Person.objects.all()[:10]切片擦操作,获取10个人,不支持副索引,切片可以节约内存。
3. Person.objects.get(name=name)
# get是用来获取一个对象的,如果需要满足条件的一些人,就要用到filter
4. Person.objects.filter(name='abc') # 等于
Person.objects.filter(name__exact="abc") #名称严格等于“abc”得人
5. Person.objects.filter(name__iexact="abc") # 名称为“abc”但是不区分大小写,可以找到ABC,Abc,aBC等等这些都符合条件
6. Person.objects.filter(name__icontains="abc") # 名称中包含“abc”,且“abc”不区分大小写
7. Person.objects.filter(name__contains="abc") # 名字中包含“abc”的人
8. Person.objects.filter(name__regex="^abc") # 正则表达式查询
9. Person.objects.filter(name__iregex="^abc") # 正则表达式不区分大小写
# filter是找出满足条件的,当然也有排除符合某条件的
10. Person.objects.exclude(name__contains="abc") # 排除包含“abc”的Person对象
11. Person.objects.filter(name__contains="abc").exclude(age=12) # 找出名称含有abc,但是排除年龄是12岁的
django ORM model filter 条件过滤,及多表连接查询、反向查询,某字段的distinct
1、多表链接查询:条件选取QuerySet的时候
filter表示=,exclude表示!=,querySet.distinct() 去重复
查询语句 | 语义 |
---|---|
__exact | 精确等于 like'aaa' |
__iexact | 精确等于 忽略大小写 ilike 'aaa' |
__contains | 包含 like '%aaa%' |
__icontains | 包含 忽略大小写 ilike '%aaa%',但是对于sqlite来说,contains的作用效果等同于icontains。 |
__gt | 大于 |
__gte | 大于等于 |
__lt | 小于 |
__lte | 小于等于 |
__in | 存在于一个list范围内 |
__startswith | 以...开头 |
__istartswith | 以...开头 忽略大小写 |
__endswith | 以...结尾 |
__iendswith | 以...结尾,忽略大小写 |
__range | 在...范围内 |
__year | 日期字段的年份 |
__month | 日期字段的月份 |
__day | 日期字段的日 |
__isnull=True/False |
例子:
In [2]: Person.objects.filter(age__gt=1) # 年龄大于1岁的
Out[2]: <QuerySet [<Person: Person object (liu 12)>, <Person: Person object (liul 122)>, <Person: Person object (lius 11)>, <Person: Person object (li 11)>]>
q1.filter(pub_date__gte=datetime.date.today())表示为时间>=now,
补充:
“在django models中取得一个字段的distinct值”。就是select distinct xxx from table_name ...这样的功能。使用values会生成ValuesQuerySet(形如N个dict组成的list),猜测大数据无额外性能影响,毕竟queryset系列都是使用时才查询操作的。
xxxx.objects.values("field_name").distinct()
或者
xxxx.objects.distinct().values("field_name")
关于缓存:
# queryset是有缓存的
a = A.objects.all()
print [i for i in a]
#第一次执行打印会查询数据库,然后结果会被保存在queryset内置的cache中,再执行print的时候就会取自缓存。
# 很多时候会遇到仅需判断queryset是否为空的情况,可以:
if queryset:
pass
if queryset.count>0:
pass
if queryset.exists():
pass.
# 三种方式性能依次提升。
# 当queryset非常巨大时,cache会成为问题。此时可以:
queryset.iterator()
# 迭代器的用处就不多说了,根据具体需求情况使用。
网友评论