settings.py:
AUTH_USER_MODEL
默认值:django.contrib.auth.models.User
何时需要设置:有时候默认的User模型(其中包含的默认字段)可能并不适合一些项目的身份验证
需求,用户需要自定义用户模型(增加字段)。只有显示设置了AUTH_USER_MODEL后,才能识别自定义的用户模型。
#settings.py
AUTH_USER_MODEL = 'myapp.MyUser'
#models.py
from django.contrib.auth.models import AbstractUser
class MyUser(AbstractUser):
pass
#admin.py
admin.site.register(MyUser, MyUserAdmin)
强烈建议在第一次makemigrations之前就设置好AUTH_USER_MODEL!!!
AUTHENTICATION_BACKENDS
指定要使用的身份验证后端列表
HAYSTACK_CONNECTIONS
利用django-haystack插件设置搜索引擎
HAYSTACK_SEARCH_RESULTS_PER_PAGE
设置分页显示的数据量
HAYSTACK_SIGNAL_PROCESSOR
当数据库改变时,自动更新索引
MEDIA_URL
使用户通过浏览器来访问上传文件。如本机http://127.0.0.1/, MEDIA_URL设置为"/media/",那么通过http://127.0.0.1/media/*** 就可以访问相关的上传图片或者其他资源。
MEDIA_ROOT
存放用户上传文件的目录的绝对路径
。在Django的FileField
和ImageField
这样的Model类中,有upload_to
参数可选。当upload_to设置相关的地址后,如:upload_to=“username”;文件上传后将自动保存到 os.path.join(MEDIA_ROOT, upload_to)。
SECRET_KEY
django-admin startproject
会自动将随机生成的SECRET_KEY添加到每个新项目。如果SECRET_KEY没有设置,Django将拒绝启动。
SECRET_KEY 的作用主要是提供一个值做各种 HASH,在加密过程中作为算法的一个参数(salt 或其他),所以这个值的复杂度也就影响到了数据传输和存储时的复杂度。还用于sessions, messages, PasswordResetView令牌,密码签名。
另外, 考虑到安全性, 这个密钥是不建议存储在你的程序中的. 最好的方法是存储在你的系统环境变量中。
STATIC_URL
同MEDIA_URL类似,用于访问静态资源文件。
STATIC_ROOT
部署项目
中静态资源文件所在目录的绝对路径
- STATIC_ROOT是一个比较特殊的文件夹。这是区别Django的开发模式和部署模式下最大的地方了。
- 通常我们在开发模式下,可以在我们所在的project下建立相应的app, 然后每个app下都建立相应的static文件夹。在开发模式下(Debug=True),Django将为我们自动查找这些静态文件(每个app)并在网页上显示出来。然而,在部署模式下,Django认为这些工作交由web服务器来运行会更有效率。
- 在进行项目部署时,我们需要运行一下
python manage.py collectstatic
这个命令。这个命令将会把每个app里的static目录下的文件copy到STATIC_ROOT这个文件夹下,这时候如果在部署模式下(Debug=False),网页中相关的,如: http://127.0.0.1/static/*** 的访问,将不会访问Django下各个App中的static,而是STATIC_ROOT中所指定的文件夹。
STATICFILES_DIRS
STATICFILES_DIRS告诉django,首先到STATICFILES_DIRS里面寻找静态文件,其次再到各个app的static文件夹里面找
models.py
字段选项
…
null
数据库字段是否可以为空,默认为False
blank
如为True,设置在Admin站点管理中添加数据时可以允许空值
default
设置默认值,可以是函数名
primary_key
如为True,将字段设置为主键,代替原来的自增 id 列
db_column
设置数据库中的字段名称
unique
如为True,将字段设置成唯一属性,默认为False
db_index
如为True,为字段添加数据库索引
verbose_name
在Admin站点管理设置字段的显示名称
related_name
关联对象反向引用描述,用于多表查询,可解决一个数据表有两个外键同时指向另一个数据表而出现重名的问题
auto_now_add
配置auto_now_add=True,永远是创建时的时间
auto_now
配置上auto_now=True,无论添加或修改,都是当前操作的时间
choices
提供可选数据。
每个元组中的第一个元素是要在模型上设置的实际值,第二个元素是人类可读的名称。
通常,最好在模型类中定义选择。虽然您可以在模型类外部定义一个选择列表,然后再引用它,但是在模型类内部定义每个选择的选择和名称,会将所有信息保留在使用它的类中,并有助于引用选择。
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
)
您还可以将可用的选择收集到命名组
中,以用于组织目的:
MEDIA_CHOICES = [
('Audio', (
('vinyl', 'Vinyl'),
('cd', 'CD'),
)
),
('Video', (
('vhs', 'VHS Tape'),
('dvd', 'DVD'),
)
),
('unknown', 'Unknown'),
]
每个元组中的第一个元素是要应用于该组的名称
。第二个元素是2元组的可迭代对象,每个2元组包含一个值和一个选项的易于理解的名称。可以将组合选项
与未组合选项
组合在一个列表中(例如'unknown'
本示例中的 选项)。
对于已choices设置的每个模型字段,Django提供get_FOO_display()
来检索该字段的当前值的可读名称。
枚举类型
from django.utils.translation import gettext_lazy as _
class Student(models.Model):
class YearInSchool(models.TextChoices):
# FRESHMAN = ('FR', 'Freshman')
FRESHMAN = 'FR', _('Freshman')
SOPHOMORE = 'SO', _('Sophomore')
JUNIOR = 'JR', _('Junior')
SENIOR = 'SR', _('Senior')
GRADUATE = 'GR', _('Graduate')
year_in_school = models.CharField(
max_length=2,
# 如此添加选项!
choices=YearInSchool.choices,
default=YearInSchool.FRESHMAN,
)
def is_upperclass(self):
return self.year_in_school in {
self.YearInSchool.JUNIOR,
self.YearInSchool.SENIOR,
}
注意:YearInSchool.FRESHMAN
,YearInSchool['FRESHMAN']
,YearInSchool('FR')
是等价的,都返回对应选项的人类可读名称。
如果没有人类可读的名称,则可以从成员名称中推断出它们(用空格替换下划线并使用标题大小写):
>>> class Vehicle(models.TextChoices):
... CAR = 'C'
... TRUCK = 'T'
... JET_SKI = 'J'
...
>>> Vehicle.JET_SKI.label
'Jet Ski'
由于枚举值需要为整数的情况非常普遍,因此Django提供了一个IntegerChoices
类。例如:
class Card(models.Model):
class Suit(models.IntegerChoices):
DIAMOND = 1
SPADE = 2
HEART = 3
CLUB = 4
suit = models.IntegerField(choices=Suit.choices)
如果您需要枚举值为其它数据类型,则可以子类化Choices所需的具体数据类型,例如 date,用于DateField
class MoonLandings(datetime.date, models.Choices):
APOLLO_11 = 1969, 7, 20, 'Apollo 11 (Eagle)'
APOLLO_12 = 1969, 11, 19, 'Apollo 12 (Intrepid)'
APOLLO_14 = 1971, 2, 5, 'Apollo 14 (Antares)'
APOLLO_15 = 1971, 7, 30, 'Apollo 15 (Falcon)'
APOLLO_16 = 1972, 4, 21, 'Apollo 16 (Orion)'
APOLLO_17 = 1972, 12, 11, 'Apollo 17 (Challenger)'
还可以使用Enum Functional API,并需要警告,标签会自动生成,如上面突出显示的那样:
>>> MedalType = models.TextChoices('MedalType', 'GOLD SILVER BRONZE')
>>> MedalType.choices
[('GOLD', 'Gold'), ('SILVER', 'Silver'), ('BRONZE', 'Bronze')]
>>> Place = models.IntegerChoices('Place', 'FIRST SECOND THIRD')
>>> Place.choices
[(1, 'First'), (2, 'Second'), (3, 'Third')]
Meta选项
针对表
abstract
当abstract = True
时,这个模型将是抽象基类
get_latest_by
一个字段的名称或几个字段名称的列表,通常是 DateField,DateTimeField或IntegerField类型,表示按字段升序或降序的顺序显示最新的一行数据。
例如:
# Latest by priority descending, order_date ascending.
get_latest_by = ['-priority', 'order_date']
verbose_name和verbose_name_plural
verbose_name表示单数形式的显示,verbose_name_plural表示复数形式的显示;中文的单数和复数一般不作区别
QuerySet API
datetimes()
返回datetime.datetime 代表的对象的QuerySet列表
def datetimes(self, field_name, kind, order='ASC', tzinfo=None):
field_name
:某模型的某DateTimeField类型的字段名
kind
:“year”,“month”,“week”,“day”, “hour”,“minute”,或"second"。datetime.datetime 结果列表中的每个对象都被“截断”到给定kind类型之前
order
:默认是升序(ASC),还可以是降序(DESC)
tzinfo
:定义截断之前将日期时间转换为的时区,默认是Django当前时区
>>> Article.objects.datetimes('article_create_time', 'month', order='DESC')
<QuerySet [datetime.datetime(2019, 1, 1, 0, 0), datetime.datetime(2018, 12, 1, 0, 0), ...
distinct()
从查询结果中消除重复的行,一般和values()连用。
>>> Article.objects.values('article_tag').distinct()
<QuerySet [{'article_tag': '关于我 me'}, {'article_tag': '虚拟环境 start'}, ...
get_current()
使用该函数的前提是,模型得是Django.contrib.sites.models.Site
的子类
def get_current(self, request=None):
基于项目设置中的SITE_ID返回当前的Site。如果SITE_ID没有设置,就根据request.get_host()返回带有domain的site,Site对象会在从数据库取得的第一时间被缓存。
可以通过.domain
获得网站域名。
get_FOO_display()
对于已choices
设置的每个字段,该对象将具有一个get_FOO_display()方法,其中FOO是字段的名称
。此方法返回该字段的“人类可读”值
。
save()
def save(self, force_insert=False, force_update=False, using=None, update_fields=None)
update_fields为None时,所有字段都会更新。但有时你只需要更新一个字段,就用update_fields来指定。可以提高效率
。
save(update_fields=['name'])
update()
update(**kwargs)
对指定的字段
执行SQL更新查询,并返回匹配的行数
(如果某些行已经具有新值,则该行数可能不等于更新的行数)。
update()方法可立即应用,唯一限制
是它只能更新模型主表中的列,而不能更新相关模型上的列。您不能这样做,例如:
>>> Entry.objects.update(blog__name='foo') # Won't work!
values()
def values(self, *fields, **expressions)
返回一个ValuesQuerySet —— QuerySet 的一个子类,迭代时返回字典而不是模型实例对象。
values() 接收可选的位置参数*fields
,它指定SELECT 应该限制哪些字段。如果指定字段,每个字典将只包含指定的字段的键/值。如果没有指定字段,每个字典将包含数据库表中所有字段的键和值。
values()还带有可选的关键字参数**expressions
,这些参数将传递
annotate()
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]
>>> Blog.objects.values(lower_name=Lower('name'))
<QuerySet [{'lower_name': 'beatles blog'}]>
如果你有一个字段foo 是一个ForeignKey,默认的values() 调用返回的字典将有一个叫做foo_id 的键,因为这是保存实际的值的那个隐藏的模型属性的名称(foo 属性引用关联的模型)。当你调用values() 并传递字段的名称,传递foo 或foo_id 都可以,得到的结果是相同的(字典的键会与你传递的字段名匹配)。
>>> Entry.objects.values('blog')
[{'blog': 1}, ...]
>>> Entry.objects.values('blog_id')
[{'blog_id': 1}, ...]
当values() 与distinct() 一起使用时,注意排序可能影响最终的结果。详细信息参见distinct() 中的备注。
魔法方法
__unicode__()
和__str__()
python2只能使用__unicode__(),python3中两者没区别。如果不使用,后台都是显示xxx object
urls.py
django1.11使用的是url()
函数
def url(regex, view, kwargs=None, name=None)
regex的格式是r'^$'
,命名正则表达式组的语法是 (?P<name>pattern)
,其中 name 是组名,pattern 是要匹配的模式。
views.py
视图函数
reverse()
def reverse(viewname, urlconf=None, args=None, kwargs=None, current_app=None)
reverse 接收 url 中的 name 作为第一个参数,我们在代码中就可以通过 reverse() 来获取对应的网址(这个网址可以用来跳转,也可以用来计算相关页面的地址),只要对应的 url 的name不改,就不用改代码中的网址。
这个函数避免了我们在视图函数中硬编码 URL,它需要我们给出我们想要跳转的视图的名字和该视图所对应的 URL 模式中需要给该视图提供的参数。
request.GET.get() && request.POST.get()
后者一般用于接受从表单传过来的数据,实际上两种方法还有一种书写形式,拿request.POST.get()举例:
request.POST.get(‘name’)可以写成request.POST[‘name’],都可以获取数据,但是当获取不到数据时,前者会返回None,而后者会抛出KeyError,
大致看一下get方法的源码就明白了:
def get(self, key, default=None):
try:
val = self[key]
except KeyError:
return default
if val == []:
return default
return val
所以通常不使用字典索引的形式获取数据,防止报错。
request.get_full_path() && request.path()
- 都是获取request 请求的url路径
- request.get_full_path() – 获取当前url,(包含参数)
请求一个http://127.0.0.1:8000/200/?type=10
request.get_full_path()返回的是【/200/?type=10】
request.path – 获取当前url,(但不含参数)
request.path返回的是 【/200/】 - 如果想让其正常显示(有中文的情况下),需进行如下编码处理【django 默认编码是unicode 的】
request.get_full_path().encode('utf-8')
request.path.encode('utf-8')
request.META
request.META 是一个Python字典,包含了所有本次HTTP请求的Header信息,比如用户IP地址和用户Agent(通常是浏览器的名称和版本号)。 注意,Header信息的完整列表取决于用户所发送的Header信息和服务器端设置的Header信息。
Template
内置标签
autoescape
{% autoescape on/off %}
{% endautoescape %}
控制标签内的内容是否自动转义,当自动转义是生效的, 所有变量的内容将被自动转义成HTML字面值后输出
csrf_token
提供了易于使用的跨站点请求伪造保护
。在任何使用POST表单的模板中,如果表单用于内部URL,一定要在表单中使用{% csrf_token %}
,对于以外部URL为目标的POST表单,不应这样做,因为这会导致CSRF令牌泄漏,从而导致漏洞。
extends
模板继承必须的标签
load
{% load static %}
加载静态文件
内置过滤器
pluralize
如果值不是1,‘1’或长度为1的对象,则返回复数后缀。默认情况下,此后缀为’s’。
{{ num_messages|pluralize }} \
{{ num_walruses|pluralize:"es" }} \
{{ num_cherries|pluralize:"y,ies" }}
自定义标签和过滤器
已注册的app中创建一个templatetags目录,templatetags里添加一个__init__.py,使它成为一个模块。接下来创建的py文件,可以通过{% load 文件名 %}加载进模板。
文件里必须导入如下配置:
register = template.Library()
如果是自定义过滤器:
@register.filter()
#相关函数
参数:
is_safe:默认为False。设置is_safe=True,若一个“安全”字符串传给您的过滤器,结果仍会是安全的。若传入了不安全的字符串,Django会在需要时自动转义。这个‘安全’指的是是否为SafeString对象,mark_safe()函数总会返回SafeString对象。
need_autoescape:如果在注册过滤器时添加了need_autoescape=True,那么过滤器必须接收一个autoescape参数,这样过滤器会捕捉其引用位置的自动转义是否开启,以决定你在过滤器中的行为.如果模板中autoescape是开启的,说明我们已经认定这部分的数据是存在威胁的,所以需要在过滤器中手动对输入数据进行转义来保证其安全性.
@stringfilter
如果编写只接收一个字符串作为第一个参数的模板过滤器,你需要使用 stringfilter 的装饰器,它会将参数前转为字符串后传递给函数。这样,您就可以将一个整数传递给这个过滤器,从而使用字符串操作的方法。
如果是自定义标签
@register.simple_tag()
#相关函数
参数:
takes_context:模板标签需要访问当前上下文(函数的第一个参数必须是context)
name:重命名标签
将标签结果存入一个模板变量而不是直接将其输出是可能的。这能通过使用 as 参数,后跟变量名实现。这样做能让你在期望的位置输出内容:
{% current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}.</p>
@register.inclusion_tag()
将标签传到指定的模板,标签函数返回一个字典,将作为一个模板上下文被模板碎片使用。如果包含标签可能要求超多参数,可以使用takes_context=True参数。这样可以通过标签在其它模板中重用指定的模板。