django提升

(1)打包应用程序:可重用性

  • 打包 Python 程序需要工具:setuptools 。打包时候建议使用django-appname
  • 1 在你的 Django 项目目录外创建一个名为 django-polls 的文件夹,用于盛放 polls
  • 2 将 polls 目录移入 django-polls 目录。
  • 3 创建一个名为 django-polls/README.rst 的文件,包含以下内容:
=====
Polls
===== Polls is a simple Django app to conduct Web-based polls. For each
question, visitors can choose between a fixed number of answers. Detailed documentation is in the "docs" directory. Quick start
----------- 1. Add "polls" to your INSTALLED_APPS setting like this:: INSTALLED_APPS = [
...
'polls',
] 2. Include the polls URLconf in your project urls.py like this:: path('polls/', include('polls.urls')), 3. Run `python manage.py migrate` to create the polls models. 4. Start the development server and visit http://127.0.0.1:8000/admin/
to create a poll (you'll need the Admin app enabled). 5. Visit http://127.0.0.1:8000/polls/ to participate in the poll.
  • 4 创建一个 django-polls/LICENSE 文件。选择一个非本教程使用的授权协议,但是要足以说明发布代码没有授权证书是 不可能的 。Django 和很多兼容 Django 的应用是以 BSD 授权协议发布的;不过,你可以自己选择一个授权协议。只要确定你选择的协议能够限制未来会使用你的代码的人。
  • 下一步我们将创建 setup.py 用于说明如何构建和安装应用的细节。关于此文件的完整介绍超出了此教程的范围,但是 setuptools docs 有详细的介绍。创建文件 django-polls/setup.py 包含以下内容:
import os
from setuptools import find_packages, setup with open(os.path.join(os.path.dirname(__file__), 'README.rst')) as readme:
README = readme.read() # allow setup.py to be run from any path
os.chdir(os.path.normpath(os.path.join(os.path.abspath(__file__), os.pardir))) setup(
name='django-polls',
version='0.1',
packages=find_packages(),
include_package_data=True,
license='BSD License', # example license
description='A simple Django app to conduct Web-based polls.',
long_description=README,
url='https://www.example.com/',
author='Your Name',
author_email='yourname@example.com',
classifiers=[
'Environment :: Web Environment',
'Framework :: Django',
'Framework :: Django :: X.Y', # replace "X.Y" as appropriate
'Intended Audience :: Developers',
'License :: OSI Approved :: BSD License', # example license
'Operating System :: OS Independent',
'Programming Language :: Python',
'Programming Language :: Python :: 3.5',
'Programming Language :: Python :: 3.6',
'Topic :: Internet :: WWW/HTTP',
'Topic :: Internet :: WWW/HTTP :: Dynamic Content',
],
)
  • 6 默认包中只包含 Python 模块和包。为了包含额外文件,我们需要创建一个名为 MANIFEST.in 的文件。上一步中关于 setuptools 的文档详细介绍了这个文件。为了包含模板、README.rst 和我们的 LICENSE 文件,创建文件 django-polls/MANIFEST.in 包含以下内容:
include LICENSE
include README.rst
recursive-include polls/static *
recursive-include polls/templates *
  • 7 在应用中包含详细文档是可选的,但我们推荐你这样做。创建一个空目录 django-polls/docs 用于未来编写文档。额外添加一行至 django-polls/MANIFEST.in
recursive-include docs *
  • 8 试着构建你自己的应用包通过 ptyhon setup.py sdist (在 django-polls``目录内)。这将创建一个名为 ``dist 的目录并构建你自己的应用包, django-polls-0.1.tar.gz
C:\Users\Administrator\Desktop\django-polls> python setup.py sdist

(2)使用自己的包名

由于我们把 polls 目录移出了项目,所以它无法工作了。我们现在要通过安装我们的新 django-polls 应用来修复这个问题。

C:\Users\Administrator\Desktop\django-polls\dist>pip install --user django-polls-0.1.tar.gz

(3)发布应用,可以邮件,github等等方式上传

(4)模型

(5)查询

>>> from blog.models import Blog
>>> b = Blog(name='Beatles Blog', tagline='All the latest Beatles news.')
>>> b.save() >>> from blog.models import Author
>>> joe = Author.objects.create(name="Joe")
>>> entry.authors.add(joe) >>> all_entries = Entry.objects.all() Entry.objects.filter(pub_date__year=2006)
Entry.objects.all().filter(pub_date__year=2006) >>> q1 = Entry.objects.filter(headline__startswith="What")
>>> q2 = q1.exclude(pub_date__gte=datetime.date.today())
>>> q3 = q1.filter(pub_date__gte=datetime.date.today()) >>> one_entry = Entry.objects.get(pk=1) >>> Entry.objects.all()[5:10] # OFFSET 5 LIMIT 5 >>> Entry.objects.order_by('headline')[0] SELECT * FROM blog_entry WHERE pub_date <= '2006-01-01'; Entry.objects.get(headline__exact="Cat bites dog") >>> Blog.objects.get(name__iexact="beatles blog") Entry.objects.get(headline__contains='Lennon') SELECT ... WHERE headline LIKE '%Lennon%'; Blog.objects.filter(entry__authors__isnull=False, entry__authors__name__isnull=True) Blog.objects.filter(entry__headline__contains='Lennon', entry__pub_date__year=2008) >>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3)) >>> print([e.headline for e in Entry.objects.all()]) SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06') >>> e.delete() >>> Entry.objects.filter(pub_date__year=2005).delete() e = Entry.objects.get(id=3)
e.authors.all() # Returns all Author objects for this Entry.
e.authors.count()
e.authors.filter(name__contains='John') a = Author.objects.get(id=5)
a.entry_set.all() # Returns all Entry objects for this Author. e = Entry.objects.get(id=2)
e.entrydetail # returns the related EntryDetail object
e.entrydetail = ed

(5)聚合

from django.db import models

class Author(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField() class Publisher(models.Model):
name = models.CharField(max_length=300) class Book(models.Model):
name = models.CharField(max_length=300)
pages = models.IntegerField()
price = models.DecimalField(max_digits=10, decimal_places=2)
rating = models.FloatField()
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher, on_delete=models.CASCADE)
pubdate = models.DateField() class Store(models.Model):
name = models.CharField(max_length=300)
books = models.ManyToManyField(Book)
# Total number of books.
>>> Book.objects.count() >>> Book.objects.filter(publisher__name='BaloneyPress').count() # Average price across all books.
>>> from django.db.models import Avg, Max, Min
>>> Book.objects.aggregate(Avg('price'), Max('price'), Min('price')) # Each publisher, each with a count of books as a "num_books" attribute.
>>> pubs = Publisher.objects.annotate(num_books=Count('book')) # The top 5 publishers, in order by number of books.
>>> pubs = Publisher.objects.annotate(num_books=Count('book')).order_by('-num_books')[:5]
>>> pubs[0].num_books >>> Book.objects.filter(name__startswith="Django").annotate(num_authors=Count('authors')) >>> Book.objects.annotate(num_authors=Count('authors')).filter(num_authors__gt=1) >>> Book.objects.annotate(num_authors=Count('authors')).order_by('num_authors')

(6)搜索

>>> Entry.objects.filter(body_text__search='cheese')

>>> Entry.objects.annotate(
... search=SearchVector('blog__tagline', 'body_text'),
... ).filter(search='cheese')

(7)Manager

from django.db import models

class PollManager(models.Manager):
def with_counts(self):
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("""
SELECT p.id, p.question, p.poll_date, COUNT(*)
FROM polls_opinionpoll p, polls_response r
WHERE p.id = r.poll_id
GROUP BY p.id, p.question, p.poll_date
ORDER BY p.poll_date DESC""")
result_list = []
for row in cursor.fetchall():
p = self.model(id=row[0], question=row[1], poll_date=row[2])
p.num_responses = row[3]
result_list.append(p)
return result_list class OpinionPoll(models.Model):
question = models.CharField(max_length=200)
poll_date = models.DateField()
objects = PollManager() class Response(models.Model):
poll = models.ForeignKey(OpinionPoll, on_delete=models.CASCADE)
person_name = models.CharField(max_length=50)
response = models.TextField()
class ExtraManager(models.Model):
extra_manager = OtherManager() class Meta:
abstract = True class ChildC(AbstractBase, ExtraManager):
# ...
# Default manager is CustomManager, but OtherManager is
# also available via the "extra_manager" attribute.
pass

(8)raw SQL queries

class Person(models.Model):
first_name = models.CharField(...)
last_name = models.CharField(...)
birth_date = models.DateField(...)
>>> for p in Person.objects.raw('SELECT * FROM myapp_person'):
... print(p) >>> Person.objects.raw('SELECT last_name, birth_date, first_name, id FROM myapp_person') >>> name_map = {'first': 'first_name', 'last': 'last_name', 'bd': 'birth_date', 'pk': 'id'}
>>> Person.objects.raw('SELECT * FROM some_other_table', translations=name_map) >>> first_person = Person.objects.raw('SELECT * FROM myapp_person LIMIT 1')[0] >>> people = Person.objects.raw('SELECT *, age(birth_date) AS age FROM myapp_person')
>>> for p in people:
... print("%s is %s." % (p.first_name, p.age)) >>> lname = 'Doe'
>>> Person.objects.raw('SELECT * FROM myapp_person WHERE last_name = %s', [lname]) from django.db import connection def my_custom_sql(self):
with connection.cursor() as cursor:
cursor.execute("UPDATE bar SET foo = 1 WHERE baz = %s", [self.baz])
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
row = cursor.fetchone()
return row cursor.execute("SELECT foo FROM bar WHERE baz = '30%%' AND id = %s", [self.id]) >>> cursor.fetchall() with connection.cursor() as c:
c.execute(...) with connection.cursor() as cursor:
cursor.callproc('test_procedure', [1, 'test'])

(9) 数据事务

a.save() # Succeeds, but may be undone by transaction rollback
try:
b.save() # Could throw exception
except IntegrityError:
transaction.rollback()
c.save() # Succeeds, but a.save() may have been undone

(10)多数据库

DATABASES = {
'default': {
'NAME': 'app_data',
'ENGINE': 'django.db.backends.postgresql',
'USER': 'postgres_user',
'PASSWORD': 's3krit'
},
'users': {
'NAME': 'user_data',
'ENGINE': 'django.db.backends.mysql',
'USER': 'mysql_user',
'PASSWORD': 'priv4te'
}
}
$ ./manage.py migrate --database=users
$ ./manage.py migrate --database=users
$ ./manage.py migrate --database=customers
from django.contrib import admin

# Specialize the multi-db admin objects for use with specific models.
class BookInline(MultiDBTabularInline):
model = Book class PublisherAdmin(MultiDBModelAdmin):
inlines = [BookInline] admin.site.register(Author, MultiDBModelAdmin)
admin.site.register(Publisher, PublisherAdmin) othersite = admin.AdminSite('othersite')
othersite.register(Publisher, MultiDBModelAdmin)
from django.db import connections
with connections['my_db_alias'].cursor() as cursor:
...

(11) URL调度器

from django.urls import path
from . import views urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
path('articles/<int:year>/<int:month>/', views.month_archive),
path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]
from django.urls import path, re_path
from . import views urlpatterns = [
path('articles/2003/', views.special_case_2003),
re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
]
from django.urls import re_path

urlpatterns = [
re_path(r'^blog/(page-(\d+)/)?$', blog_articles), # bad
re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments), # good
]
from django.urls import include, path

urlpatterns = [
# ... snip ...
path('community/', include('aggregator.urls')),
path('contact/', include('contact.urls')),
# ... snip ...
]
# In settings/urls/main.py
from django.urls import include, path urlpatterns = [
path('<username>/blog/', include('foo.urls.blog')),
] # In foo/urls/blog.py
from django.urls import path
from . import views urlpatterns = [
path('', views.blog.index),
path('archive/', views.blog.archive),
]

示例

from django.urls import path
from . import views urlpatterns = [
#...
path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
#...
]
<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>
from django.http import HttpResponseRedirect
from django.urls import reverse def redirect_to_year(request):
# ...
year = 2006
# ...
return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

(12)文件上传

forms.py

from django import forms

class UploadFileForm(forms.Form):
title = forms.CharField(max_length=50)
file = forms.FileField()

views.py

from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import ModelFormWithFileField def upload_file(request):
if request.method == 'POST':
form = ModelFormWithFileField(request.POST, request.FILES)
if form.is_valid():
# file is saved
form.save()
return HttpResponseRedirect('/success/url/')
else:
form = ModelFormWithFileField()
return render(request, 'upload.html', {'form': form})
def handle_uploaded_file(f):
with open('some/file/name.txt', 'wb+') as destination:
for chunk in f.chunks():
destination.write(chunk)

使用 UploadedFile.chunks() 而不是 read() 是为了确保即使是大文件又不会将我们系统的内存占满。

(13)快捷键函数

  • render(request, template_name, context=None, content_type=None, status=None, using=None)
from django.shortcuts import render

def my_view(request):
# View code here...
return render(request, 'myapp/index.html', {
'foo': 'bar',
}, content_type='application/xhtml+xml')
  • redirect(to, args, permanent=False, kwargs)
from django.shortcuts import redirect

def my_view(request):
...
obj = MyModel.objects.get(...)
return redirect(obj)

(14)中间件

中间件是 Django 请求/响应处理的钩子框架。它是一个轻量级的、低级的“插件”系统,用于全局改变 Django 的输入或输出。

中间件工厂是一个可调用的程序,它接受 get_response 可调用并返回中间件。中间件是可调用的,它接受请求并返回响应,就像视图一样。

def simple_middleware(get_response):
# One-time configuration and initialization. def middleware(request):
# Code to be executed for each request before
# the view (and later middleware) are called. response = get_response(request) # Code to be executed for each request/response after
# the view is called. return response return middleware

或者它可以写成一个类,它的实例是可调用的,如下:

class SimpleMiddleware:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization. def __call__(self, request):
# Code to be executed for each request before
# the view (and later middleware) are called. response = self.get_response(request) # Code to be executed for each request/response after
# the view is called. return response

中间件工厂必须接受 get_response 参数。还可以初始化中间件的一些全局状态。记住两个注意事项:

  • Django仅用 get_response 参数初始化您的中间件,因此不能定义 __init__(),因为需要其他参数。
  • 与每次请求调用 __call__() 方法不同,当 Web 服务器启动时,__init__() 只被称为一次

激活中间件

若要激活中间件组件,请将其添加到 Django 设置中的 MIDDLEWARE 列表中。在 MIDDLEWARE 中,每个中间件组件由字符串表示:指向中间件工厂的类或函数名的完整 Python 路径。例如,这里创建的默认值是 django-admin startproject

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

MIDDLEWARE 的顺序很重要,因为中间件会依赖其他中间件。例如:类 AuthenticationMiddleware 在会话中存储经过身份验证的用户;因此,它必须在 SessionMiddleware 后面运行 。中间件。Session中间件。请参阅 Middleware ordering ,用于一些关于 Django 中间件类排序的常见提示。

(15) 会话

def post_comment(request, new_comment):
if request.session.get('has_commented', False):
return HttpResponse("You've already commented.")
c = comments.Comment(comment=new_comment)
c.save()
request.session['has_commented'] = True
return HttpResponse('Thanks for your comment!')

This simplistic view logs in a "member" of the site:

def login(request):
m = Member.objects.get(username=request.POST['username'])
if m.password == request.POST['password']:
request.session['member_id'] = m.id
return HttpResponse("You're logged in.")
else:
return HttpResponse("Your username and password didn't match.")

...And this one logs a member out, according to login() above:

def logout(request):
try:
del request.session['member_id']
except KeyError:
pass
return HttpResponse("You're logged out.")

(16)表单

16.1 Get与POST

处理表单时只会用到 GETPOST 两种HTTP方法。Django的登录表单使用 POST 方法传输数据,在这个方法中浏览器会封装表单数据,为了传输会进行编码,然后发送到服务端并接收它的响应。相比之下,GET 方法将提交的数据捆绑到一个字符串中,并用它来组成一个URL。该URL包含了数据要发送的地址以及一些键值对应的数据。如果您在Django文档中进行一次搜索,就会看到这点,它会生成一个形似 https://docs.djangoproject.com/search/?q=forms&release=1 的URL。

GETPOST 通常用于不同的目的。

任何可能用于更改系统状态的请求应该使用 POST —— 比如一个更改数据库的请求。GET 应该只被用于不会影响系统状态的请求。

GET 方法也不适合密码表单,因为密码会出现在URL中,于是也会出现在浏览器的历史记录以及服务器的日志中,而且都是以纯文本的形式。它也不适合处理大量的数据或者二进制数据,比如一张图片。在WEB应用的管理表单中使用 GET 请求具有安全隐患:攻击者很容易通过模拟请求来访问系统的敏感数据。 POST 方法通过与其他像Django的 CSRF protection 这样的保护措施配合使用,能对访问提供更多的控制。另一方面, GET 方法适用于诸如网页搜索表单这样的内容,因为这类呈现为一个 GET请求的URL很容易被存为书签、分享或重新提交。

<form action="/your-name/" method="post">
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
<input type="submit" value="OK">
</form>

forms.py

from django import forms

class NameForm(forms.Form):
your_name = forms.CharField(label='Your name', max_length=100)

views.py

from django.http import HttpResponseRedirect
from django.shortcuts import render from .forms import NameForm def get_name(request):
# if this is a POST request we need to process the form data
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = NameForm(request.POST)
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
# ...
# redirect to a new URL:
return HttpResponseRedirect('/thanks/') # if a GET (or any other method) we'll create a blank form
else:
form = NameForm() return render(request, 'name.html', {'form': form})

视图将再次创建一个表单实例并使用请求中的数据填充它: form = NameForm(request.POST) 这叫“绑定数据到表单” (现在它是一张 绑定的 表单)。调用表单的 is_valid() 方法;如果不为 True ,我们带着表单返回到模板。这次表单不再为空( 未绑定 ),所以HTML表单将用之前提交的数据进行填充,放到可以根据需要进行编辑和修正的位置。如果 is_valid()True ,我们就能在其 cleaned_data 属性中找到所有通过验证的表单数据。我们可以在发送一个HTTP重定向告诉浏览器下一步去向之前用这些数据更新数据库或者做其他处理。

name.html

<form action="/your-name/" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>

16.2 详解Django Form类

forms.py

from django import forms

class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField(widget=forms.Textarea)
sender = forms.EmailField()
cc_myself = forms.BooleanField(required=False)

views.py

from django.core.mail import send_mail

if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
sender = form.cleaned_data['sender']
cc_myself = form.cleaned_data['cc_myself'] recipients = ['info@example.com']
if cc_myself:
recipients.append(sender) send_mail(subject, message, sender, recipients)
return HttpResponseRedirect('/thanks/')
<p><label for="id_subject">Subject:</label>
<input id="id_subject" type="text" name="subject" maxlength="100" required></p>
<p><label for="id_message">Message:</label>
<textarea name="message" id="id_message" required></textarea></p>
<p><label for="id_sender">Sender:</label>
<input type="email" name="sender" id="id_sender" required></p>
<p><label for="id_cc_myself">Cc myself:</label>
<input type="checkbox" name="cc_myself" id="id_cc_myself"></p>

(17)用户认证

Django 自带一个用户验证系统。它负责处理用户账号、组、权限和基于cookie的用户会话。文档的这部分解释了默认的实现如何开箱即用,以及如何扩展和自定义以满足你的项目需求。

(18)验证系统

创建用户

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword') # At this point, user is a User object that has already been saved
# to the database. You can continue to change its attributes
# if you want to change other fields.
>>> user.last_name = 'Lennon'
>>> user.save()

创建超级用户

$ python manage.py createsuperuser --username=joe --email=joe@example.com

更改密码

>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username='john')
>>> u.set_password('new password')
>>> u.save()

验证用户

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
# A backend authenticated the credentials
else:
# No backend authenticated the credentials

登出

from django.contrib.auth import logout

def logout_view(request):
logout(request)
# Redirect to a success page.

限制对未登录用户的访问:装饰器

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
...

(19)Django缓存框架

动态网站存在一个基本权衡是——它们是动态的。每次用户请求一个页面,web 服务器需要提供各种各样的计算——从数据库查询到模板渲染再到业务逻辑——最后建立页面呈现给用户。从处理开销的角度来看,这比标准读取文件系统服务安排的开销要高得多。下面是一些伪代码解释了动态网站生成页面的时候,缓存是怎么工作的:

given a URL, try finding that page in the cache
if the page is in the cache:
return the cached page
else:
generate the page
save the generated page in the cache (for next time)
return the generated page

19.1 Memcached内存缓存

Memcached 是一个完全基于内存的缓存服务器,是 Django 原生支持的最快、最高效的缓存类型,最初被开发出来用于处理 LiveJournal.com 的高负载,随后由 Danga Interactive 开源。Facebook 和 Wikipedia 等网站使用它来减少数据库访问并显著提高网站性能。

Memcached 以一个守护进程的形式运行,并且被分配了指定数量的 RAM。它所做的就是提供一个快速接口用于在缓存中添加,检索和删除数据。所有数据都直接存储在内存中,因此不会产生数据库或文件系统使用的开销。

在安装 Memcached 本身后,你还需要安装一个 Memcached 绑定。有许多可用的 Python Memcached 绑定,最常见的两个是 python-memcached 和pylibmc

在 Django 中使用 Memcached :

  • 将 BACKEND 设置为 django.core.cache.backends.memcached.MemcachedCache 或者 django.core.cache.backends.memcached.PyLibMCCache (取决于你所选择的 memcached 绑定)
  • 将 LOCATION设置为 ip:port 值,其中 ip 是 Memcached 守护进程的 IP 地址,port 是运行 Memcached 的端口;或者设置为一个 unix:path 值,其中 path 是 Memcached Unix 套接字文件的路径。

在这个示例中,Memcached 使用 python-memcached 绑定,在 localhost (127.0.0.1) 端口 11211 上运行:

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
}
}

在这个示例中, Memcached 可通过本地 Unix 套接字文件 /tmp/memcached.sock 使用 python-memcached 绑定得到:

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': 'unix:/tmp/memcached.sock',
}
}

当使用 pylibmc 绑定时,不要包含 unix:/ 前缀:

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '/tmp/memcached.sock',
}
}

Memcached 的一个出色功能是它能够在多个服务器上共享缓存。这意味着您可以在多台计算机上运行 Memcached 守护程序,程序会视这组计算机为单个缓存,而无需在每台机器上复制缓存值。要使用此功能,需要在 LOCATION 中包含所有服务器的地址,可以是分号或者逗号分隔的字符串,也可以是一个列表。

在这个示例中,缓存通过端口 11211 的 IP 地址 172.19.26.240 、 172.19.26.242 运行的 Memcached 实例共享:

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11211',
]
}
}

在以下示例中,缓存通过在 IP 地址 172.19.26.240(端口号 11211),172.19.26.242(端口号 11212)和 172.19.26.244(端口号 11213)上运行的 Memcached 实例共享:

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': [
'172.19.26.240:11211',
'172.19.26.242:11212',
'172.19.26.244:11213',
]
}
}

关于 Memcached 的最后一点是,基于内存的缓存有一个缺点:因为缓存的数据存储在内存中,如果服务器崩溃,那么数据将会丢失。显然,内存不适用于持久数据存储,因此不要依赖基于内存的缓存作为你唯一的数据存储。毫无疑问,没有任何 Django 缓存后端应该被用于持久存储——它们都是适用于缓存的解决方案,而不是存储——我们在这里指出这一点是因为基于内存的缓存是格外临时的。

19.2 数据库缓存

Django 可以在数据库中存储缓存数据。如果你有一个快速、索引正常的数据库服务器,这种缓存效果最好。

用数据库表作为你的缓存后端:

  • BACKEND 设置为 django.core.cache.backends.db.DatabaseCache
  • LOCATION 设置为 数据库表的表名。这个表名可以是没有使用过的任何符合要求的名称。

在这个例子中,缓存表的名称是 my_cache_table

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.db.DatabaseCache',
'LOCATION': 'my_cache_table',
}
}
  • 创建缓存表

使用数据库缓存之前,必须通过下面的命令创建缓存表:

python manage.py createcachetable

这将在数据库中创建一个表,该表的格式与 Django 数据库缓存系统期望的一致。该表的表名取自 LOCATION

如果你正在使用多数据库缓存, createcachetable 会对每个缓存创建一个表。

如果你正在使用多数据库, createcachetable 将遵循数据库路由的 allow_migrate() 方法。

migrate 一样, createcachetable 不会影响已经存在的表,它只创建缺失的表。

要打印即将运行的 SQL,而不是运行它,请使用 createcachetable --dry-run 选项。

  • 多数据库

如果在多数据库中使用缓存,你也需要设置数据库缓存表的路由指令。因为路由的原因,数据库缓存表在 django_cache 应用程序中显示为 CacheEntry 的模型名。这个模型不会出现在模型缓存中,但模型详情可用于路由目的。

比如,下面的路由可以将所有缓存读取操作指向 cache_replica ,并且所有的写操作指向 cache_primary。缓存表将会只同步到 cache_primary

class CacheRouter:
"""A router to control all database cache operations""" def db_for_read(self, model, **hints):
"All cache read operations go to the replica"
if model._meta.app_label == 'django_cache':
return 'cache_replica'
return None def db_for_write(self, model, **hints):
"All cache write operations go to primary"
if model._meta.app_label == 'django_cache':
return 'cache_primary'
return None def allow_migrate(self, db, app_label, model_name=None, **hints):
"Only install the cache model on primary"
if app_label == 'django_cache':
return db == 'cache_primary'
return None

如果你没有指定路由指向数据库缓存模型,缓存后端将使用 默认 的数据库。当然,如果没使用数据库缓存后端,则无需担心为数据库缓存模型提供路由指令。

19.3 文件系统缓存

基于文件的后端序列化并保存每个缓存值作为单独的文件。要使用此后端,可将 BACKEND 设置为 "django.core.cache.backends.filebased.FileBasedCache" 并将 LOCATION 设置为一个合适的路径。比如,在 /var/tmp/django_cache 存储缓存数据,使用以下配置:

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}

如果使用 Windows 系统,将驱动器号放在路径开头,如下:

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': 'c:/foo/bar',
}
}

目录路径应该是绝对路径——因此,它应该以文件系统根目录开始。无需担心是否需要以斜杠结尾。

确保这个配置指向的目录存在,并且可由运行 Web 服务器的系统用户读写。继续上面的例子,如果服务器被用户 apache 运行,确保目录 /var/tmp/django_cache 存在并且可被用户 apache 读写。

19.4 本地内存缓存

如果在配置文件中没有指定缓存,那么将默认使用本地内存缓存。如果你想要内存缓存的速度优势,但又没有条件使用 Memcached,那么可以考虑本地内存缓存后端。

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
}

LOCATION 被用于标识各个内存存储。如果只有一个 locmem 缓存,你可以忽略 LOCATION 。但是如果你有多个本地内存缓存,那么你至少要为其中一个起个名字,以便将它们区分开。这种缓存使用最近最少使用(LRU)的淘汰策略。

注意,每个进程将有它们自己的私有缓存实例,这意味着不存在跨进程的缓存。这也同样意味着本地内存缓存不是特别节省内存,因此它或许不是生成环境的好选择,不过它在开发环境中表现很好。

19.5 虚拟缓存(用于开发模式)

Django 带有一个实际上不是缓存的 "虚拟" 缓存,它只是实现缓存接口,并不做其他操作。如果你有一个正式网站在不同地方使用了重型缓存,但你不想在开发环境使用缓存,而且不想为这个特殊场景而修改代码的时候,这将非常有用。要激活虚拟缓存,像这样设置 BACKEND

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.dummy.DummyCache',
}
}

19.6 使用自定义的缓存后台

虽然 Django 自带一些缓存后端,但有时你也想使用自定义的缓存后端。当使用第三方缓存后端时,使用 Python 导入路径作为 Cache 设置的后端,像这样:

CACHES = {
'default': {
'BACKEND': 'path.to.backend',
}
}

如果你正在创建自己的后端,你可以使用标准缓存作为参考实现。你在 Django 源代码的 django/core/cache/backends/ 目录找到代码。

注意:除非是令人信服的理由,诸如服务器不支持缓存,否则你应该使用 Django 附带的缓存后端。他们经过了良好的测试并易于使用。

19.7 缓存参数

每个缓存后端可以通过额外的参数来控制缓存行为。这些参数在 CACHES 设置中作为附加键提供。有效参数如下:

  • 缓存:setting:TIMEOUT :用于缓存的默认超时时间(以秒为单位)。这个参数默认为 300 秒(5分钟)。你可以设置 TIMEOUTNone,因此,默认情况下缓存键永不过时。值为 0 会导致键立刻过期(实际上就是不缓存)。

  • OPTIONS :任何选项应该传递到缓存后端。有效选项列表将随着每个后端变化,并且由第三方库缓存支持的后端直接传递它们的选项到底层缓存库。

    实现自有的淘汰策略的缓存后端(比如 locmem, filesystemdatabase 后端)将遵循以下选项:

    • MAX_ENTRIES :删除旧值之前允许缓存的最大条目。默认是 300

    • CULL_FREQUENCY :当达到 MAX_ENTRIES 时被淘汰的部分条目。实际比率为 1 / CULL_FREQUENCY ,当达到 MAX_ENTRIES 时,设置为2就会淘汰一半的条目。这个参数应该是一个整数,默认为3。

      CULL_FREQUENCY 的值为 0 意味着当达到 MAX_ENTRIES 缓存时,整个缓存都会被清空。在一些后端(尤其是 database ),这会使以更多的缓存未命中为代价来更快的进行淘汰。

    Memcached 后端传递 OPTIONS 的内容作为键参数到客户端构造函数,从而允许对客户端行为进行更高级的控制。参见下文:

  • KEY_PREFIX :将自动包含(默认预先添加)到Django 服务器使用的所有缓存键的字符串。

    查看 cache documentation 获取更多信息。

  • VERSION :通过 Django 服务器生成的缓存键的默认版本号。

    查看 cache documentation 获取更多信息。

  • KEY_FUNCTION :一个包含指向函数的路径的字符串,该函数定义将如何前缀、版本和键组成最终的缓存键。

    查看 cache documentation 获取更多信息。

在这个例子中,文件系统后端正被设置成60秒超时时间,并且最大容量是1000条。

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
'TIMEOUT': 60,
'OPTIONS': {
'MAX_ENTRIES': 1000
}
}
}

这个的例子是基于 python-memcached 后端的设置,对象大小限制在 2MB :

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'OPTIONS': {
'server_max_value_length': 1024 * 1024 * 2,
}
}
}

这个例子是基于 pylibmc 后端的设置,改设置支持二进制协议、SASL 验证和 ketama行为模式:

CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',
'LOCATION': '127.0.0.1:11211',
'OPTIONS': {
'binary': True,
'username': 'user',
'password': 'pass',
'behaviors': {
'ketama': True,
}
}
}
}

更多缓存知识访问>> https://docs.djangoproject.com/zh-hans/2.2/topics/cache/

(20)发送邮件

20.1 快速上手,仅需两行代码:

from django.core.mail import send_mail

send_mail(
'Subject here',
'Here is the message.',
'from@example.com',
['to@example.com'],
fail_silently=False,
)

邮件是通过 SMTP 主机和端口发送的,由配置项 EMAIL_HOSTEMAIL_PORT 指定。如果配置了 EMAIL_HOST_USEREMAIL_HOST_PASSWORD ,那么它们将被用来验证 SMTP 服务器。配置项 EMAIL_USE_TLSEMAIL_USE_SSL 控制是否使用安全连接。发送邮件最简单的方式就是使用 django.core.mail.send_mail()

send_mail():send_mail(subject, message, from_email, recipient_list, fail_silently=False, auth_user=None, auth_password=None, connection=None, html_message=None)

  • 参数 subject, message, from_emailrecipient_list 是必须的。

  • recipient_list: 一个字符串列表,每项都是一个邮箱地址。recipient_list中的每个成员都可以在邮件的 "收件人:" 中看到其他的收件人。

  • fail_silently: 为 Falsesend_mail() 发生错误时抛出 smtplib.SMTPException 。可在 smtplib 文档找到一系列可能的异常,它们都是 SMTPException 的子类。

  • auth_user: 可选的用户名,用于验证登陆 SMTP 服务器。 若未提供,Django 会使用 EMAIL_HOST_USER 指定的值。

  • auth_password: 可选的密码,用于验证登陆 SMTP 服务器。若未提供, Django 会使用 EMAIL_HOST_PASSWORD 指定的值。

  • connection: 可选参数,发送邮件使用的后端。若未指定,则使用默认的后端。查询 邮件后端 文档获取更多细节。

  • html_message: 若提供了 html_message,会使邮件成为 multipart/alternative 的实例, message 的内容类型则是 text/plain ,并且 html_message 的内容类型是 text/html

返回值会是成功发送的信息的数量(只能是 01 ,因为同时只能发送一条消息)。

20.2 批量发送邮件

django.core.mail.send_mass_mail() 用于批量发送邮件。

send_mass_mail()

笔记15:Django提升篇的更多相关文章

  1. Android进阶笔记15:ListView篇之图片优化

    1.图片异步加载: (1)处理图片的方式: 如果ListView中自定义的Item中有涉及到大量图片的,一定要对图片进行细心的处理,因为图片占的内存是 ListView 项中最头疼的,处理图片的方法大 ...

  2. Ext.Net学习笔记15:Ext.Net GridPanel 汇总(Summary)用法

    Ext.Net学习笔记15:Ext.Net GridPanel 汇总(Summary)用法 Summary的用法和Group一样简单,分为两步: 启用Summary功能 在Feature标签内,添加如 ...

  3. 斯坦福ML公开课笔记15—隐含语义索引、神秘值分解、独立成分分析

    斯坦福ML公开课笔记15 我们在上一篇笔记中讲到了PCA(主成分分析). PCA是一种直接的降维方法.通过求解特征值与特征向量,并选取特征值较大的一些特征向量来达到降维的效果. 本文继续PCA的话题, ...

  4. Django进阶篇【1】

    注:本篇是Django进阶篇章,适合人群:有Django基础,关于Django基础篇,将在下一章节中补充! 首先我们一起了解下Django整个请求生命周期: Django 请求流程,生命周期: 路由部 ...

  5. 《Kafka权威指南》读书笔记-操作系统调优篇

    <Kafka权威指南>读书笔记-操作系统调优篇 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 大部分Linux发行版默认的内核调优参数配置已经能够满足大多数应用程序的运 ...

  6. Django总结篇

    1.0 简述http协议和常用请求头 http协议: ( 基于TCP/IP通信协议来传递数据(HTML 文件, 图片文件, 查询结果等)) HTTP协议是Hyper Text Transfer Pro ...

  7. 运维开发笔记整理-Django模型语法

    运维开发笔记整理-Django模型语法 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.模型基本概念 1>.什么是模型 模型是你的数据唯一的,权威的信息源.它包含你所存储数 ...

  8. C# 程序性能提升篇-1、装箱和拆箱,枚举的ToString浅析

    前景提要: 编写程序时,也许你不经意间,就不知不觉的使程序代码,发生了装箱和拆箱,从而降低了效率,不要说就发生那么一次两次,如果说是程序中发生了循环.网络程序(不断请求处理的)等这些时候,减少装箱和拆 ...

  9. C# 程序性能提升篇-2、类型(字段类型、class和struct)的错误定义所影响性能浅析

    前景提要: 编写程序时,也许你不经意间,就不知不觉的定义了错误的类型,从而发生了额外的性能消耗,从而降低了效率,不要说就发生那么一次两次,如果说是程序中发生了循环.网络程序(不断请求处理的)等这些时候 ...

随机推荐

  1. 2016年蓝桥杯B组C/C++决赛题目

    2016年第七届蓝桥杯B组C/C++决赛题目 点击查看2016年第七届蓝桥杯B组C/C++决赛题解 1.一步之遥 从昏迷中醒来,小明发现自己被关在X星球的废矿车里. 矿车停在平直的废弃的轨道上. 他的 ...

  2. 【西北师大-2108Java】第二次作业成绩汇总

    2[西北师大-2108Java]第二次作业成绩汇总 以命令行方式或在Eclipse集成开发环境中编辑.编译.运行第3章示例程序3-1-3-5,结合程序运行结果理解程序代码,每个示例程序从语法.算法两个 ...

  3. python3.5.3rc1学习九:正则表达式

    # 正则表达式 ''''' 正则表达式是有一些特殊字符组成,能够帮你找到一些符合一定规则的字符串 先来了解几个符号所代表的意思 \d 匹配所有的数字 \D 匹配所有,但是数字除外 \s 空格 \S 匹 ...

  4. 题解:openjudge 1.11——01

    题目 思路:二分查找 来,上代码 #include<cstdio> #include<iostream> using namespace std; +]; int n,m; i ...

  5. SpringMVC常用注解(三)

    一.@Controller .@RestController 和 @ControllerAdvice 1. @Controller @Controller 用于标记在一个类上,使用它标记的类就是一个S ...

  6. Python 基础排序算法

    冒泡排序(bubble sort) 思路 以升序为例: 从第一个数开始向后两两对比,将大的数一直向后移动,直至最大的数移到最后,再找第二大的数 最好情况:O(n) 一般情况:O(n^2) 最坏情况:O ...

  7. LeetCode 739 每日温度

    1.直接遍历 暴力求解 class Solution { public: vector<int>dailyTemperatures(vector<int>& T) { ...

  8. 启动tomcat内存溢出

    在运行项目的过程中,启动tomcat内存溢出.查阅了一些解决办法,总结出来留个笔记. 1.使用Myeclipse2014+tomcat 7 ,在MyEclipse中将项目部署到Tomcat下,启动to ...

  9. 《Linux内核原理与分析》教学进程

    目录 2019-2020-1 <Linux内核原理与分析>教学进程 考核方案 第一周: 第二周: 第三周: 第四周: 第五周 第六周 第七周: 第八周 第九周 第十周 第十一周: 第十二周 ...

  10. JDBC数据库连接测试工具

    贴代码 import java.io.PrintStream; import java.sql.*; import java.util.Properties; public class ZJdbcPi ...