Django templates and models
-
models
-
templates
-
models and databases
models
如何理解models
A model is the single, definitive source of information about your data.
It contains the essential fields and behaviors of the data you’re storing.
Generally, each model maps to a single database table.
The basics:
- Each model is a Python class that subclasses
django.db.models.Model
. - Each attribute of the model represents a database field.
- With all of this, Django gives you an automatically-generated database-access API; see Making queries.
quick example
from django.db import models class Person(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)
The above Person
model would create a database table like this:
CREATE TABLE myapp_person ( "id" serial NOT NULL PRIMARY KEY, "first_name" varchar(30) NOT NULL, "last_name" varchar(30) NOT NULL );
注意:表名是 ---应用名字_class名字 ,你可以重写他们
ID字段是自动添加的,并设置为主键,当然你也可以重写他们
要想使写的model在数据库生效,你需要在 INSTALLED_APPS中添加进你的应用,像这样
INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'books.apps.BooksConfig', ]
books 是我的app name, BooksConfig 是apps.py 文件中定义的类名
使用以下两条命令
python manage.py makemigrations
python manage.py migrate
执行第一条命令后你会在migrations文件夹中看到0001_initial.py文件
manage.py migrate 这条命令是迁移到数据库,数据库中会有你创建的表
Fileds(字段)
数据表中的字段被class attributes 所指定。需要注意的是,字段的名字不要和model API 冲突,like clear delete save
example
from django.db import models class Musician(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) instrument = models.CharField(max_length=100) class Album(models.Model): artist = models.ForeignKey(Musician, on_delete=models.CASCADE) name = models.CharField(max_length=100) release_date = models.DateField() num_stars = models.IntegerField()
field options
以下是字段常用的参数
- null 如果是True, django会将空值存储为null在数据库中,默认是False
- default The default value for the field. This can be a value or a callable object. If callable it will be called every time a new object is created.
- choice An iterable (e.g., a list or tuple) of 2-tuples to use as choices for this field. If this is given,the default form widget will be a select box instead of the standard text field and will limit choices to the choices given.
- blank(空白) If
True
, the field is allowed to be blank. Default isFalse
. - primary key 如果是True ,指定这个字段是主键
- unique 如果是True 这个字段数据唯一的,不能重复
关于field name 的约束
django 对于field name 只有两个约束
- 不能是Python的保留字,比如pass for try 等,否则会出现语法错误
- 字段名字不能包含超过1个下划线 (_) 这是由于django 的查询语法的工作模式导致的
class Example(models.Model): foo__bar = models.IntegerField() # 'foo__bar' has two underscores!
making query 查询
一旦你创建了数据模型,django会自动提供数据库抽象API让你创建,更新,删除object
refer to the following models
from django.db import models class Blog(models.Model): name = models.CharField(max_length=100) tagline = models.TextField() def __str__(self): # __unicode__ on Python 2 return self.name class Author(models.Model): name = models.CharField(max_length=200) email = models.EmailField() def __str__(self): # __unicode__ on Python 2 return self.name class Entry(models.Model): blog = models.ForeignKey(Blog) headline = models.CharField(max_length=255) body_text = models.TextField() pub_date = models.DateField() mod_date = models.DateField() authors = models.ManyToManyField(Author) n_comments = models.IntegerField() n_pingbacks = models.IntegerField() rating = models.IntegerField() def __str__(self): # __unicode__ on Python 2 return self.headline
creating object
Django uses an intuitive system:
A model class represents a database table, and an instance of that class represents a particular record in the database table.
模型类代表数据表,这个l类的实例代表这个数据表中一个特定的实例。
>>> from blog.models import Blog >>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.') name是blog类中的属性,即指定的字段 >>> b.save()
这个行为相当于在幕后执行了INSERT SQL 语句
这是一种插入数据的方式,还有另一种插入数据的方式:
>> Blog.object.create(name="libai",tagline="all the latest beatles news")
这种方式不需要save
Saving changes to objects
使用.save()来保存改变的对象
例如
b.name="李白"
b.save()
retrieving object(检索对象)
To retrieve objects from your database, construct a QuerySet
via a Manager
on your model class.
为了检索从数据库的对象,通过model类的manage方法构建一个QuerySet
关于manage方法,如果不设置名字,默认名字是objects
A QuerySet represents a collection of objects from your database. It can have zero, one or many filters.
QuertSet 代表数据库中对象的集合,他有0个,1个或者多个过滤器 从SQL角度来看,QuerySet相当于select语句,filter相当于where having
You get a QuerySet
by using your model’s Manager
. Each model has at least one Manager
, and it’s called objects
by default. Access it directly via the model class, like so:
NOtes:
实例是没有manage方法的
like:
>>> Blog.objects <django.db.models.manager.Manager object at ...> >>> b = Blog(name='Foo', tagline='Bar') >>> b.objects Traceback: ... AttributeError: "Manager isn't accessible via Blog instances."
检索所有的objects
all_entries=Entry.objects.all()
很多f情况下我们需要匹配特定的,这时需要用到过滤器
Retrieving specific objects with filters
两种方法:
filter(**kwargs)
Returns a new QuerySet
containing objects that match the given lookup parameters.
excludet(**kwargs)
Returns a new QuerySet
containing objects that do not match the given lookup parameters.
For example, to get a QuerySet
of blog entries from the year 2006, use filter()
like so:
Entry.objects.filter(pub_date__year=2006)
With the default manager class, it is the same as:
Entry.objects.all().filter(pub_date__year=2006)
Retrieving a single object with get()
filter() will always give you a QuerySet, even if only a single object matches the query - in this case, it will be a QuerySet
containing a single element.
使用get()会返回一个object
你就可以直接使用它
查询表达式
from django.db.models import F, Count, Value from django.db.models.functions import Length, Uppe
F() 表达式
An F()
object represents the value of a model field or annotated column. It makes it possible to refer to
model field values and perform database operations using them without actually having to pull them
out of the database into Python memory.
Instead, Django uses the F()
object to generate an SQL expression that describes the required operation at the database level.
# Tintin filed a news story! reporter = Reporters.objects.get(name='Tintin') reporter.stories_filed += 1 reporter.save()
使用F()
from django.db.models import F reporter = Reporters.objects.get(name='Tintin') reporter.stories_filed = F('stories_filed') + 1 reporter.save()
F() 代表了一个model field或者annatate column上的value, 优点在于不用将数据库数据拿出来放到Python 内存中
F() 常用于update 语句中
reporter = Reporters.objects.filter(name='Tintin') reporter.update(stories_filed=F('stories_filed') + 1)
F()
therefore can offer performance advantages by:
- getting the database, rather than Python, to do work
- reducing the number of queries some operations require
To access the new value saved this way, the object must be reloaded:
如果你想立刻获得更新的值的话,执行 注释:这句理解可能有误
reporter.refresh_from_db()
reporter = Reporters.objects.get(pk=reporter.pk)
# Or, more succinctly:
reporter.refresh_from_db()
Django 静态文件部署
以下是几个概念
- STATIC_ROOT
- STATIC_URL
- STATICFILES_DIR
- STATICFILES_STORAGE
- STATICFILES_FINDERS
STATIC_ROOT
default :none
The absolute path to the directory where collectstatic
will collect static files for deployment
目录的绝对路径,当执行python manage.py collectstatic 命令时,会将收集的静态文件全部放到这个目录下
一般来说这个目录下应该没有文件,是空的目录
例如
STATIC_ROOT="/var/www/example.com/static/"
STATIC_URL
default :none
URL to use when referring to static files located in STATIC_ROOT
Example: "/static/"
or "http://static.example.com/"
如果这个值不是空值,必须要以 / 结尾
STATICFILES_DIRS
default::[] empty list
This setting defines the additional locations the staticfiles app will traverse if the FileSystemFinder
finder is enabled,
这个设置将定义了一个额外的位置, staticfiles app将会遍历这个位置,如果FileSystemFinder
finde能够被使用
for example
STATICFILES_DIRS = [ "/home/special.polls.com/polls/static", "/home/polls.com/polls/static", "/opt/webfiles/common", ]
STATICFILES_FINDERS
default:
[
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
]
The list of finder backends that know how to find static files in various locations.
查找器的一个列表,知道如何从不同的位置找到静态文件
The default will find files stored in the STATICFILES_DIR setting (using django.contrib.staticfiles.finders.FileSystemFinder
) and in a static
subdirectory of each app (usingdjango.contrib.staticfiles.finders.AppDirectoriesFinder
). If multiple files with the same name are present, the first file that is found will be used.
One finder is disabled by default: django.contrib.staticfiles.finders.DefaultStorageFinder
. If added to your STATICFILES_FINDERS
setting,
it will look for static files in the default file storage as defined by the DEFAULT_FILE_STORAGE
setting.
template
template 模板
变量 variables
标签 tag
过滤器 filter
模板是一个简单的text文件,包括变量(获得值)和标签(控制逻辑)
变量 {{ variable }}
自定义模板标签和filters
1 确定你的app在settings.py 的installed_app中
2然后在你的app中应该有一个templatetags包,
3在templatetag目录下,创建一份文件去自定义标签,例如这个文件名叫myappcustomtag.py
4在你的template总加入这个语句
{% load myappcustomtag %}
在myappcustomtag.py 这个module中的前面加入这几句
from django import template register = template.Library()
目的是让你的模块成为一个有效的标签库
5开始写你自定义的filter或者tag
定义一个函数
给函数加上一个装饰器,
@register.filter
像下面这样
@register.filter
def cut(value, arg): return value.replace(arg, '')
@register.simple_tag
代码如下:
@register.simple_tag
def current_time(format_string):
return datetime.datetime.now().strftime(format_string)
模板继承
你需要一个模板,作为母版,例如base.html
在子模板中加入以下语句
{% extends %}
需要注意两点
{% extends " base.html" %} 必须是这个模板中的第一个标签,否则将不会起效果
{% block %} 标签越多越好
如果你想获得母版中block中的值,使用{% block.super%}
在同一个模板中block的名字不能相同
models and database
查询数据库中的记录
get() filter() all()
更新
使用queryset的方法update()
第二种方法 获取instance object ,直接赋值,然后 调用save()方法
删除
delete()
关于query expression
介绍两个
F() Q()
导入
from django.db.models import F,Q
可以用在update, create, filter, order by, annotation, or aggregate.
支持算术,加减乘除
F() EXPRESSION
An F()
object represents the value of a model field or annotated column
F()代表了model字段的值或者注释列 它直接操作数据库,通过注入SQL语句,而不是吧数据从数据库拉到Python的内存中
使用F()有以下几个优势
- getting the database, rather than Python, to do work
- reducing the number of queries some operations require
直接用数据库而不是Python, 减少了查询操作需求的数量
另外还可以avoild race condition 在使用Python mulitiple thread 要注意这点
F()
objects assigned to model fields persist after saving the model instance and will be applied on each save()
. For example:
reporter = Reporters.objects.get(name='Tintin') reporter.stories_filed = F('stories_filed') + 1 reporter.save() reporter.name = 'Tintin Jr.' reporter.save()
stories_filed
will be updated twice in this case. If it’s initially 1
, the final value will be 3
.
bk=Book.objects.get(id=2) # t=Book.objects.filter(auth__name='李白').values('title','price') # print(t)# bk.price=F('price')/2 print("-------------------------------") bk.save() bk.title='唐诗三百首' bk.save() return HttpResponse("ok")
关于queryset API reference
queryset 对象是可迭代的,
支持切片[1:3]
支持pickle
len()
b=len(Book.objects.all())
list() 将queryset转化为列表
b=list(Book.objects.all())
切片后也是query对象,但是这个对象不再支持更远的修改,排序等操作,因为它已经不能很好的转化为SQL,没有了明确的定义
bk=Book.objects.get(id=2) # t=Book.objects.filter(auth__name='李白').values('title','price') b=Book.objects.all()[0:3] print(b) print(b.order_by('price'))
比如执行以上的代码,会出现以下错误
Methods that return new QuerySet
s
filter
(**kwargs)
exclude
(**kwargs)
annotate
(*args, **kwargs)
order_by(*field)
reverse()
values
(*fields, **expressions)
aggregate
(*args, **kwargs)
exists()
update
(**kwargs)
delete()
annotate 的参数可以是一个值,字段,查询表达式,聚合表达式,
除了聚合表达式可以是匿名参数,其他任何参数必须是关键字参数
annaotate 都指定一个关键字参数作为alias 别名
from django.db.models import Count,Avg ,Sum,Max b = Book.objects.values('auth__name').annotate(maxprice=Max('price')) print(b[0]['maxprice'])
如果里面是聚合表达式,会默认将聚合和models field combine as alias
使用reverse() 必须是已经排序了,要么调用了order_by 或者定义了ordering,otherwise ,no effect
values
(*fields, **expressions)
Returns a QuerySet
that returns dictionaries, rather than model instances, when used as an iterable.
返回一个requeryset ,里面包含的是字典,而不是model instance
values 有一个可选的位置参数,*field 如果制定了字段,则字典只包含指定的字段
aggregate
(*args, **kwargs)
返回一个字典,
aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的 标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定 一个名称,可以向聚合子句提供它: >>> Book.objects.aggregate(average_price=Avg('price')) {'average_price': 34.35}
exists()
Returns True
if the QuerySet
contains any results, and False
if not.