一、项目
1、创建项目
django-admin startproject mysite
2、创建应用
python manage.py startapp blog
3、启动项目
python manage.py runserver 8080
4、目录结构
二、路由
1、路由配置
# vim urls.py
import blog.view
...
url(r'^welcome', blog.view.welcome),
...
2、路由处理
vim blog.view.py
def welcome(request):
.....
return render(request, 'welcome.html')
# welcome.html是templates下的视图文件
3、变量传递
vim view.py
def welcome(request):
.....
return render(request, 'welcome.html',{'abc':times})
vim welcome.html
...
<a> {{ abc }} </a>
...
4、路由正则匹配
(1) 开头结尾
'^admin/$'
- ^ : 以admin开头
- $ : 以admin/结尾
(2)数字匹配
'^admin/[0-9]{4}/$'
- [0-9]{4} :0~9 4个数字,如2019
(3)无名参数
'^admin/([0-9]{4})/([0-9]{2})/$'
- ()括号内当无名参数顺序传递给view函数
- 视图函数需要接收两个变量
(4)有名参数
'^admin/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$'
- 将匹配到的参数以year和month传回,接收需要参数名
5、默认参数
url(r'index',view.index,{'name':'ruike'})
- 将name='ruike'有名形参传递回视图函数
6、路由别名
vim urls.py
url(r'^index', view.index, name='index2')
别名传递到视图vim template.index.html
<form action={% url "index2" %} methon="post">
7、路由分发
vim project/urls.py
# 将blog的路由分发到blog.urls
from django.urls import path, include
url(r'^blog/', include('blog.urls')),
vim blog/urls.py
from django.urls import path
import views
urlpatterns = [
path('new/$', views.new),
]
最终路由/blog/new
三、视图模版文件
1、变量符 {{ }}
(1)变量传递
vim view.py
def welcome(request):
.....
return render(request, 'welcome.html',{'abc':times})
vim welcome.html
...
<a> {{ abc }} </a>
...
2、程序 {% %}
(1) for函数
vim welcome.html
{% for i in url_list %}
<tr>
<td> i.name </td>
<td> i.email </td>
<td> i.sex </td>
</tr>
{% endfor %}
3、模版之继承
(1)、盒子放置
vim base.html
...
{% block block_name1 %}
{% endblock %}
...
{% block block_name2 %}
{% endblock %}
...
(2)、盒子引用
vim hello.html
# 必须放在页面文件第一个位置
{% extends 'base.html' %}
{% blocl block_name1 %}
......
{% endblock %}
{% blocl block_name2 %}
......
{% endblock %}
四、Model
1、模型创建
生成同步数据库的脚本:python manage.py makemigrations
同步数据库: python manage.py migrate
注意:在开发过程中,数据库同步误操作之后,难免会遇到后面不能同步成功的情况,解决这个问题的一个简单粗暴方法是把migrations目录下的脚本(除__init__.py之外)全部删掉,再把数据库删掉之后创建一个新的数据库,数据库同步操作再重新做一遍。
(1)字段类型:
- AutoField
根据可用ID自动递增。您通常不需要直接使用它; 如果您没有另外指定,主键字段将自动添加到您的模型中。 - BigAutoField
一个64位整数,很像一个AutoField不同之处在于它是保证从适合数字1到9223372036854775807。 - BinaryField
classBinaryField(max_length = None,** options)
用于存储原始二进制数据的字段。它可以分配bytes, bytearray或memoryview。
默认情况下,BinaryField设置editable为False,在这种情况下,它不能包含在a中ModelForm。 - BooleanField
真/假字段 - CharField
字符串字段,用于小到大的字符串 - DateField
日期 - DateTimeField
日期和时间 - TimeField
时间 - DecimalField
一个固定精度的十进制数,由Python Decimal实例表示。它使用验证输入 DecimalValidator。
有两个必需的参数:
DecimalField.max_digits¶
数字中允许的最大位数。请注意,此数字必须大于或等于decimal_places。
DecimalField.decimal_places¶
与数字一起存储的小数位数。 - DurationField
用于存储时间段的字段 - 用Python建模 timedelta。在PostgreSQL上使用时,使用interval的数据类型是Oracle,数据类型是。否则使用一微秒。INTERVAL DAY(9) TO SECOND(6)bigint - EmailField
检查该值是使用一个有效的电子邮件地址 - FileField
classFileField(upload_to = None,max_length = 100,** options) - IntegerField
整数,无需定义长度 - PositiveIntegerField
正整数 - TextField
大文本 - GenericIPAddressField
classGenericIPAddressField(protocol ='both',unpack_ipv4 = False,** options)
IPv4或IPv6地址,采用字符串格式 - URLField
- UUIDField
(2)字段选项:
- null
null=True 则数据库字段允许为空。默认为false - blank
blank=True,则表单验证将允许输入空值。默认为false - choices
一个可迭代的,用作该字段的选择。每个元组中的第一个元素是要在模型上设置的实际值,第二个元素是人类可读的名称。例如:
from django.db import models
class Student(models.Model):
YN_IN_SCHOOL_CHOICES = [
(0, '是'),
(1, '否'),
]
#...
status = models.CharField(
max_length=2,
choices=YN_IN_SCHOOL_CHOICES,
default=1,
)
第二个元素是人类可读的名称采用get_FOO_display()来读,比如:get_status_display() ==> "是"
- db_column
用于此字段的数据库列的名称。如果没有给出,Django将使用该字段的名称。
如果您的数据库列名是SQL保留字,或者包含Python变量名中不允许的字符 - 特别是连字符 - 那就没问题。Django在幕后引用了列名和表名。
- db_index
如果True,将为此字段创建数据库索引 - db_tablespace
如果此字段已编制索引,则用于此字段索引的数据库表空间的名称。默认值为项目的 DEFAULT_INDEX_TABLESPACE设置(如果已设置)或 db_tablespace模型的设置(如果有)。如果后端不支持索引的表空间,则忽略此选项。 - default
字段的默认值。这可以是值或可调用对象。如果可调用,则每次创建新对象时都会调用它。 - editable
如果False,该字段将不会显示在管理员或任何其他字段中 ModelForm。在模型验证期间也会跳过它们。默认是True。 - error_messages
该error_messages参数允许您覆盖该字段将引发的默认消息。传入一个字典,其中的键与您要覆盖的错误消息相匹配。
错误消息键包括null,blank,invalid,invalid_choice, unique,和unique_for_date。在下面的“ 字段类型”部分中为每个字段指定了其他错误消息密钥。 - help_text
使用表单小部件显示的额外“帮助”文本。即使您的字段未在表单上使用,它也对文档很有用。
请注意,此值不会在自动生成的表单中进行HTML转义 - primary_key
如果True,此字段是模型的主键。
如果没有primary_key=True为模型中的任何字段指定,Django将自动添加一个AutoField来保存主键,因此primary_key=True除非要覆盖默认的主键行为,否则不需要设置任何字段。有关更多信息,请参阅 自动主键字段。
primary_key=True暗示null=False和 unique=True。对象上只允许一个主键。
主键字段是只读的。如果更改现有对象上的主键值,然后保存它,则将创建一个与旧对象并排的新对象 - unique
如果True,该字段在整个表格中必须是唯一的。 - unique_for_date
将其设置为a的名称DateField或DateTimeField要求此字段对于日期字段的值是唯一的。
举例来说,如果你有一个字段title有 unique_for_date="pub_date",那么Django的不允许的两个记录具有相同的入口title和pub_date。 - unique_for_month
- unique_for_year
(3)字段关系
- ForeignKey
classForeignKey(to,on_delete,** options) - ManyToManyField
classManyToManyField(to,** options) - OneToOneField
classOneToOneField(to,on_delete,parent_link = False,** options)
2、ORM模型--单表
(1).增删改查
1).增create
- 方法一
from models import Book
Book.objects.create(
title = "罗宾逊漂流记",
price = 1,
color = "green",
publicsher_id = 4,
)
- 方法二
from models import Book
dicts = {
"title" = "罗宾逊漂流记",
"price" = 1,
"color" = "green",
"publicsher_id" = 4,
}
Book.objects.create(**dicts)
2).删delete
Book.objects.filter(id=1).delete()
3).改update
- 方法一:先取出后改(全部更改)
# 拿到对象
books = Book.objects.get(id = 2)
books.name = "天空之城"
books.save
- 方法二:效率高(只改name)
# 拿到集合
Books.objects.filter(id = 2).update(name = '天空')
4).查
- 查询API
序号 | 命令 | 说明 |
---|---|---|
1 | fiter(**kwargs) | 包含所有符合的集合对象 |
2 | all() | 包含所有的集合对象 |
3 | get(**kwargs) | 返回一个条件匹配的对象,没有或多个都会报错 |
- 对查询结果再进行处理
序号 | 命令 | 说明 |
---|---|---|
1 | exclude(**kwargs) | 筛选不匹配的条件(反选) |
2 | order_by(*key) | 排序,如order_by('-id')对ID反排序 |
3 | reverse() | 对结果进行反向排序 |
4 | distinct() | 对结果去重 |
5 | first() | 返回第一条记录 |
6 | last() | 返回最后一条记录 |
7 | values(*key) | 返回对不是对象,而是一个可迭代字典 |
8 | values_list(*key) | 返回对不是对象,而是一个元组序列 |
9 | count | 返回查询到的对象数量 |
10 | exists() | 如果结果包含数据,返回True,否则返回False |
(2) 神奇的双下划线之单表查询
命令 | 涵义 |
---|---|
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 |
# 获取id大于1 且 小于10的值
models.Tb1.objects.filter(id__lt=10, id__gt=1)
# 获取id等于11、22、33的数据
models.Tb1.objects.filter(id__in=[11, 22, 33])
# in
models.Tb1.objects.exclude(id__in=[11, 22, 33])
# 模糊查询
models.Tb1.objects.filter(name__contains="ven")
# 模糊查询,大小写不敏感
models.Tb1.objects.filter(name__icontains="ven")
# 范围bettwen
models.Tb1.objects.filter(id__range=[1, 2])
# 开始于 结束与
startswith,istartswith, endswith, iendswith,
3、多表操作
(1)一对多
一个班级,对应多个学生:班级是1,学生是多
ForeignKey在多里
1)表的创建
class ClassAndGrade(models.Model):
grade = models.CharField(max_length=10)
classname = models.CharField(max_length=10)
class Studen(models.Model):
name = models.CharField(max_length=10)
age = = models.IntegerField()
# 一对多,在数据库键名为 classandgrade_id
classandgrade = ForeignKey('ClassAndGrade')
2)create
有两张方法:
- 通过classandgrade_id插入
Sutden.objects.create(
name = '张三',
age = 12,
# _id方法直接赋值
classandgrade_id = 1,
)
- 通过班级的对象去插入
classes = ClassAndGrade.object.filter(id=1)
Sutden.objects.create(
name = '张三',
age = 12,
# 根据对象绑定关系
classandgrade = classes[0],
)
3)查-正向查找
需求:查询学生的班级名称
# 取到学生的对象
studen = Sutden.objects.filter(name='张三')
# 取到班级的对象
classes = studen.classandgrade
# 取到班级名称
classname = classes.classname
4)查-反向查找
需求:查询某个班级下的所有学生的名字
# 取到班级
classes = ClassAndGrade.object.filter(classname='一班')
# 取到学生的集合_set
studens = classes.studen_set.all()
# 取到名字的集合
studensname = sutdens.values('name')
或
# __ 查询关联表
studensname = Sutden.objects.filte(classandgrade__classname='一班').values('name')
(2)多对多
一个学生可以加入多个社团,一个社团可以加入过个学生;一本书可以有多个作者,一个作者可以有多本书,这就是多对多的关系
1)使用 ManyToManyField自动创建
使用ManyToManyField关键字可以创建 第三张表Book_Authors关联 book与author的关系。
from django.db import models
class Book(models.Model):
# ...
authors = models.ManyToManyField(Author)
class Author(models.Model):
# ...
pass
但是该方式在第三张表中只能存id和两个外键,如果需要记录额外字段,请用下面半自动的方式
2)多对多关系中的额外字段
如果您可能希望收集的成员资格,有很多详细信息,例如该人加入该组的日期。
对于这些情况,Django允许您指定将用于管理多对多关系的模型。然后,您可以在中间模型上放置额外的字段。中间模型与ManyToManyField使用 through参数关联 以指向将充当中介的模型。对于我们的音乐家示例,代码如下所示:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
def __str__(self):
return self.name
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through='Membership')
def __str__(self):
return self.name
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
设置中介模型时,您需要为多对多关系中涉及的模型明确指定外键。该显式声明定义了两个模型之间的关系。
中间模型有一些限制:
- 您的中间模型必须包含源模型的一个和唯一一个外键(Group在我们的示例中将是这样),或者您必须使用显式指定Django应该用于关系的外键ManyToManyField.through_fields。如果您有多个外键through_fields且未指定,则将引发验证错误。类似的限制适用于目标模型的外键(这Person在我们的示例中)。
- 对于通过中介模型与其自身具有多对多关系的模型,允许使用同一模型的两个外键,但是它们将被视为多对多关系的两个(不同)方面。如果有更多的比两个外键虽然,你还必须指定through_fields如上,或验证错误将得到提升。
既然您已经设置好ManyToManyField使用中介模型(Membership在本例中为),就可以开始创建一些多对多关系了。您可以通过创建中间模型的实例来做到这一点:
3)create
>>> ringo = Person.objects.create(name="Ringo Starr")
>>> paul = Person.objects.create(name="Paul McCartney")
>>> beatles = Group.objects.create(name="The Beatles")
>>> m1 = Membership(person=ringo, group=beatles,
... date_joined=date(1962, 8, 16),
... invite_reason="Needed a new drummer.")
>>> m1.save()
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>]>
>>> ringo.group_set.all()
<QuerySet [<Group: The Beatles>]>
>>> m2 = Membership.objects.create(person=paul, group=beatles,
... date_joined=date(1960, 8, 1),
... invite_reason="Wanted to form a band.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>]>
4)add(),create()或set()
只要为任何必填字段指定,您还可以使用add(),create()或set()创建关系through_defaults:
beatles.members.add(john, through_defaults={'date_joined': date(1960, 8, 1)})
beatles.members.create(name="George Harrison", through_defaults={'date_joined': date(1960, 8, 1)})
beatles.members.set([john, paul, ringo, george], through_defaults={'date_joined': date(1960, 8, 1)})
5)remove()
如果中间模型定义的自定义通过表未在该对上强制执行唯一性,从而允许多个值,则该 调用将删除所有中间模型实例:(model1, model2)remove()
>>> Membership.objects.create(person=ringo, group=beatles,
... date_joined=date(1968, 9, 4),
... invite_reason="You've been gone for a month and we miss you.")
>>> beatles.members.all()
<QuerySet [<Person: Ringo Starr>, <Person: Paul McCartney>, <Person: Ringo Starr>]>
>>> # This deletes both of the intermediate model instances for Ringo Starr
>>> beatles.members.remove(ringo)
>>> beatles.members.all()
<QuerySet [<Person: Paul McCartney>]>
6) clear()
该clear() 方法可用于删除实例的所有多对多关系:
>>> # Beatles have broken up
>>> beatles.members.clear()
>>> # Note that this deletes the intermediate model instances
>>> Membership.objects.all()
<QuerySet []>
建立多对多关系后,就可以发出查询。就像普通的多对多关系一样,您可以使用多对多相关模型的属性进行查询:
# Find all the groups with a member whose name starts with 'Paul'
>>> Group.objects.filter(members__name__startswith='Paul')
<QuerySet [<Group: The Beatles>]>
使用中间模型时,还可以查询其属性:
# Find all the members of the Beatles that joined after 1 Jan 1961
>>> Person.objects.filter(
... group__name='The Beatles',
... membership__date_joined__gt=date(1961,1,1))
<QuerySet [<Person: Ringo Starr]>
如果您需要访问会员的信息,可以直接查询Membership模型:
>>> ringos_membership = Membership.objects.get(group=beatles, person=ringo)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
访问同一信息的另一种方式是通过查询 许多一对多相反的关系从一个 Person对象:
>>> ringos_membership = ringo.membership_set.get(group=beatles)
>>> ringos_membership.date_joined
datetime.date(1962, 8, 16)
>>> ringos_membership.invite_reason
'Needed a new drummer.'
4、聚合查询与分组查询
(1)聚合查询 aggregate
from django.db.models import Avg,Min,Sum,Max
# 统计所有人的平均年龄
Studen.objects.all().aggregate(Avg('age'))
# {'age__avg': 14}
# 如果需要最大最小值,也可以:
Studen.objects.all().aggregate(Max('age'),Min('age'), Avg('age'))
# {'age__max':16, 'age__min': 12 }
# 如果需要定义结果的key,可以
Studen.objects.all().aggregate(ageavg=Avg('age'))
# {'ageavg': 14}
(2) 分组查询 annotate
from django.db.models import Avg,Min,Sum,Max
# 统计不同班级的平均年龄
Studen.objects.values('classandgrade__classname').annotate(Avg('age'))
# [
# {'classandgrade__classname': '一班', 'age__avg': 14},
# {'classandgrade__classname': '二班', 'age__avg': 15}
# ]
5、F查询与Q查询
(1)F查询
专门对某列 ==数值== 取值
- 需求:对所有人年龄+1
- 逻辑:需先取出每个人的年龄再加回去
from django.db.models import F
Studen.objects.all().update(age=F('age')+1)
(2)Q查询
对查询条件多个关键字参数进行封装,从而更好地应用多个查询
1.操作符:
- | 或
- & 与
- ~ 反
2.应用范围:
- filter()
- get()
- exclude()
from django.db.models import Q
# 查询年龄等于13的学生
models.Studen.objects.filter(Q(age=13))
# 查询男生年龄大于12,或女生年龄大于14
models.Studen.objects.filter(
Q(Q(sex='男')&Q(age_gt=12))| Q(Q(sex='女')&Q(age_gt=14))
)
# ~操作符放在前面表示否定,也可允许否定与不否定形式的组合
Q(title__startswith='P') | ~Q(pub_date__year=2005)
# Q and也可以如下写
Book.objects.get(
Q(title__startswith='P'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
# Q对象可以与关键字参数查询一起使用,不过一定要把Q对象放在关键字参数查询的前面。
# 正确:
Book.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
title__startswith='P')
# 错误:
Book.objects.get(
question__startswith='P',
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
评论 (0)