摘要
版本:python3.6.4+django2.0.3
Demo: https://github.com/hanqunfeng/DjangoHelloWorld參考資料:
官方資料
Django 1.8.2 文檔
Django 1.11.6 文檔
Django 2.0.2文檔
Django中文教程
1.安裝
pip install Django
python -m django --version
2.創(chuàng)建新項(xiàng)目
django-admin startproject mysite
# mysite就是項(xiàng)目名稱(chēng)
3.創(chuàng)建新的應(yīng)用
python manage.py startapp polls
# polls是應(yīng)用名稱(chēng)
settings.py中加入新應(yīng)用配置
INSTALLED_APPS = [
'polls.apps.PollsConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
4.創(chuàng)建和更新數(shù)據(jù)庫(kù):
python manage.py makemigrations
# 全部應(yīng)用都會(huì)創(chuàng)建遷移文件
python manage.py makemigrations polls
# 只創(chuàng)建指定的應(yīng)用
python manage.py migrate
# 執(zhí)行遷移文件到數(shù)據(jù)庫(kù)
查看遷移文件生成的sql:
sqlmigrate命令接收遷移文件的名字并返回它們的SQL語(yǔ)句:#只是打印出要執(zhí)行的sql語(yǔ)句
python manage.py sqlmigrate polls 0001
# 這里遷移文件的后綴_initial.py不需要监署。
5.啟動(dòng)服務(wù)器
Django的管理后臺(tái)站點(diǎn)是默認(rèn)啟用的抢埋。 讓我們啟動(dòng)開(kāi)發(fā)服務(wù)器,然后探索它。
如果服務(wù)器沒(méi)有運(yùn)行,像下面這樣啟動(dòng)它:
python manage.py runserver
現(xiàn)在,打開(kāi)一個(gè)瀏覽器訪問(wèn)你本地域名中的 “/admin/” — 例如http://127.0.0.1:8000/admin/主穗。
啟動(dòng):
python manage.py runserver 9000
#指定啟動(dòng)端口
python manage.py runserver 0.0.0.0:9000
#指定啟動(dòng)ip+端口
6.測(cè)試:
python manage.py test
#運(yùn)行整個(gè)項(xiàng)目的全部tests.py
python manage.py test django2
#運(yùn)行指定模塊的tests.py
python manage.py test django2.tests.Django2Test
#測(cè)試指定模塊的指定測(cè)試類(lèi)
python manage.py test django2.tests.Django2Test.test_sql
#測(cè)試指定模塊的指定測(cè)試類(lèi)指定方法
7.檢查代碼覆蓋率:
pip install coverage
coverage run my_program.py arg1 arg2
django檢查方法:
coverage run --source='.' manage.py test myapp
之后可以運(yùn)行
coverage report
:顯示結(jié)果
coverage html
:生成html 測(cè)試會(huì)在當(dāng)前項(xiàng)目下生成htmlcov目錄,運(yùn)行index.html即可查看
8.mysql:
brew install mysql-connector-c
pip install mysqlclient
需要提前創(chuàng)建好數(shù)據(jù)庫(kù)
settings.py:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'django',
'USER': 'django',
'PASSWORD': 'django',
'HOST': '127.0.0.1',
'PORT': '3306',
}
}
數(shù)據(jù)庫(kù)更新:
一般情況下毙芜,我們使用如下兩個(gè)命令更新數(shù)據(jù)庫(kù)
python manage.py makemigrations
#生成數(shù)據(jù)庫(kù)模型文件
python manage.py migrate
#執(zhí)行模型文件
或者:
python manage.py migrate --database=users
#指定數(shù)據(jù)庫(kù)忽媒,默認(rèn)為default
如果由于默寫(xiě)原因刪除了數(shù)據(jù)庫(kù)中對(duì)應(yīng)的表,則再次執(zhí)行上面的命令是不能重新創(chuàng)建成功的腋粥,原因是每次django執(zhí)行模型文件時(shí)都會(huì)在django_migrations表中新增對(duì)應(yīng)的log記錄晦雨,刪掉對(duì)應(yīng)的log記錄即可重新執(zhí)行成功。
9.多數(shù)據(jù)源配置
django配置連接多個(gè)數(shù)據(jù)庫(kù)隘冲,自定義表名稱(chēng):
https://www.cnblogs.com/dreamer-fish/p/5469141.html
使用models文件夾維護(hù)model時(shí)闹瞧,一定要在其下的init.py中添加對(duì)model的引用,
否則python manage.py makemigrations
命令不會(huì)創(chuàng)建出對(duì)應(yīng)的遷移文件
比如:
from .person import Person
from .user import User
from .identity_card import IdentityCard
from .car import Car
數(shù)據(jù)庫(kù)路由:
settings.py:
DATABASE_ROUTERS = ['django2.router.django2_router.Django2Router', ]
可以將對(duì)應(yīng)的遷移文件的sql導(dǎo)入到指定的db展辞,所以路由器的設(shè)置很重要
def allow_migrate(self, db, app_label, model_name=None, **hints):
if db == 'django2_db': #如果指定了數(shù)據(jù)庫(kù)
return app_label == 'django2' #并且model被設(shè)置了正確的app_label奥邮,則可以執(zhí)行遷移文件
elif app_label == 'django2':
return False
設(shè)置好數(shù)據(jù)庫(kù)路由器后,執(zhí)行python manage.py migrate --database=django2_db
10.緩存
說(shuō)明:不推薦使用站點(diǎn)級(jí)緩存和頁(yè)面級(jí)緩存罗珍,除非是展示信息類(lèi)的網(wǎng)站洽腺,如果是頻繁修改的站點(diǎn),最好手工在代碼中維護(hù)緩存覆旱。
1).memcached
brew install memcached
啟動(dòng):memcached -d -p 11211 -c 1024 -m 64
-d:后臺(tái)運(yùn)行
-p:端口
-c:最大連接數(shù)
-m:最多分配內(nèi)存
1.使用memcached:pip install python-memcached
2.settings
# 緩存設(shè)置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'TIMEOUT': 600, # 單位秒蘸朋,默認(rèn)300s, 60s * 10 = 10min
'KEY_PREFIX': 'myapp', # 緩存鍵的字符串前綴
}
}
3.代碼中
from django.core.cache import caches
cache = caches['default']
#如果希望使用默認(rèn)的default,也可以
from django.core.cache import cache
cache.set('user_list', user_list)
user_list = cache.get('user_list')
user_list = cache.delete('user_list')
2).redis
參考資料:http://django-redis-chs.readthedocs.io/zh_CN/latest/
1.brew install redis
啟動(dòng):redis-server /usr/local/etc/redis.conf
2.pip install django-redis
3.settings
# 緩存設(shè)置
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache',
'LOCATION': '127.0.0.1:11211',
'TIMEOUT': 600, # 單位秒扣唱,默認(rèn)300s, 60s * 10 = 10min
'KEY_PREFIX': 'myapp', # 緩存鍵的字符串前綴
},
"redis": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/1",
'TIMEOUT': 600,
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"SOCKET_CONNECT_TIMEOUT": 5, # in seconds socket 建立連接超時(shí)設(shè)置
"SOCKET_TIMEOUT": 5, # in seconds 連接建立后的讀寫(xiě)操作超時(shí)設(shè)置
"COMPRESSOR": "django_redis.compressors.zlib.ZlibCompressor", # 壓縮支持
"IGNORE_EXCEPTIONS": True, # 如果redis服務(wù)關(guān)閉藕坯,不會(huì)引起異常,memcached默認(rèn)支持
"CONNECTION_POOL_KWARGS": {"max_connections": 100} # 連接池
}
}
}
# redis記錄異常日志
DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
4.代碼中
from django.core.cache import caches
redis_cache = caches['redis']
redis_cache.set('user_list', user_list)
user_list = redis_cache.get('user_list')
user_list = redis_cache.delete('user_list')
11.注冊(cè)模板自定義方法:
1.創(chuàng)建myapp.libraries.utils.py
from django import template
register = template.Library()
color = ((1, 'red'), (2, 'black'), (3, 'blue'))
# @register.filter使用方法噪沙,最多兩個(gè)參數(shù)
# {{ car.carColor|getcolorstr }}
# {{ car.carColor|getcolorstr:param2 }} 前面的表示第一個(gè)參數(shù)
@register.filter
def getcolorstr(colorNum):
return color[colorNum - 1][1]
# @register.simple_tag使用方法炼彪,不限制參數(shù)個(gè)數(shù)
# {% getcolorstr2 car.carColor %}
# {% getcolorstr2 param1 param2 param3 %}
@register.simple_tag
def getcolorstr2(colorNum):
return color[colorNum - 1][1]
2.settings:在模板配置中加入libraries配置
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
'libraries': { # Adding this section should work around the issue.
'utils': 'myapp.libraries.utils',
},
},
},
]
3.模板頁(yè)面中使用
{% load utils %}
{{ car.carColor|getcolorstr }}
{% getcolorstr2 car.carColor %}
12.模板
1.轉(zhuǎn)義:
由于模板系統(tǒng)沒(méi)有“轉(zhuǎn)義”的概念,為了顯示模板標(biāo)簽中使用的一個(gè)位曲聂,必須使用{% templatetag %}標(biāo)記霹购。
論據(jù) 輸出
openblock {%
closeblock %}
openvariable {{
closevariable }}
openbrace {
closebrace }
opencomment {#
closecomment #}
例如:
{% templatetag openblock %} url 'entry_list' {% templatetag closeblock %}
或者使用如下方式:被包含的內(nèi)容不會(huì)被模板引擎轉(zhuǎn)意,將直接輸出
{% verbatim myblock %}
Avoid template rendering via the {% verbatim %}{% endverbatim %} block.
{% endverbatim myblock %}
2.for:
變量 描述
forloop.counter 循環(huán)的當(dāng)前迭代(1索引)
forloop.counter0 循環(huán)的當(dāng)前迭代(0索引)
forloop.revcounter 循環(huán)結(jié)束的迭代次數(shù)(1索引)
forloop.revcounter0 循環(huán)結(jié)束的迭代次數(shù)(0索引)
forloop.first 如果這是第一次通過(guò)循環(huán)朋腋,則為真
forloop.last 如果這是最后一次循環(huán)齐疙,則為真
forloop.parentloop 對(duì)于嵌套循環(huán),這是圍繞當(dāng)前循環(huán)的循環(huán)
13.自定義400旭咽、403贞奋、404、500頁(yè)面
1.settings.py中DEBUG = False穷绵,否則自定義頁(yè)面不起作用
2.在任意模塊下的views.py中增加如下方法轿塔,也可以在主模塊中創(chuàng)建一個(gè)views.py
方法處理邏輯可以參考:~venv/lib/python3.6/site-packages/django/views/defaults.py中對(duì)各個(gè)方法的定義
from django.shortcuts import render
def bad_request(request, exception, template_name='400.html'):
return render(request, template_name)
def permission_denied(request, exception, template_name='403.html'):
return render(request, template_name)
def page_not_found(request, exception, template_name='404.html'):
context = {'exception': exception}
return render(request, template_name, context=context)
def server_error(request, template_name='500.html'):
return render(request, template_name)
3.在項(xiàng)目根目錄下的templates下創(chuàng)建對(duì)應(yīng)的400.html、403.html、404.html勾缭、500.html揍障,內(nèi)容更加需要自定義,也可以參考~venv/lib/python3.6/site-packages/django/views/templates下的對(duì)應(yīng)文件
4.在主模塊下urls.py中增加如下配置:
handler400 = 'DjangoHelloWorld.views.bad_request' #模塊名稱(chēng).views.方法名稱(chēng)
handler403 = 'DjangoHelloWorld.views.permission_denied'
handler404 = 'DjangoHelloWorld.views.page_not_found'
handler500 = 'DjangoHelloWorld.views.server_error'
14.Django配置session超時(shí)
配置失效時(shí)間為半個(gè)小時(shí)
SESSION_COOKIE_AGE = 60*30
關(guān)閉瀏覽器清除cookie
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
15.json與xml
1.json
創(chuàng)建一個(gè)JSONUtil工具類(lèi)俩由,用于返回json數(shù)據(jù)
import json
from django.core.serializers import serialize, deserialize
from django.db import models
from django.db.models.query import QuerySet
from django.http import JsonResponse
# 反序列化
def json_to_list(json):
if json[0] == '[':
deserializedObjectList = deserialize('json', json)
else:
deserializedObjectList = deserialize('json', '[' + json + ']')
list = []
for deserializedObject in deserializedObjectList:
list.append(deserializedObject.object)
return list
# 序列化
def to_json(obj):
if isinstance(obj, models.Model):
obj = [obj] # 因?yàn)閟erialize只支持可迭代對(duì)象毒嫡,比如querySet對(duì)象
data = serialize("json", obj)
return data
# 該方法沒(méi)有做嚴(yán)格的驗(yàn)證,只支持dict,models.Model,models.QuerySet幻梯,可以根據(jù)需要自行擴(kuò)展
def render_json(data, dict_key='data', **response_kwargs):
if isinstance(data, dict):
return JsonResponse(data)
data = to_json(data)
if 'safe' in response_kwargs and response_kwargs['safe'] is False:
pass
else:
data = {dict_key: data} # 默認(rèn)必須傳遞字典數(shù)據(jù)
if isinstance(data, str): # 由于非字典類(lèi)型的數(shù)據(jù)會(huì)被當(dāng)做字符串處理兜畸,即返回結(jié)果兩邊都有引號(hào),所以此處將其轉(zhuǎn)換為對(duì)象碘梢,否則ajax調(diào)用時(shí)不方便處理
data = json.loads(data)
return JsonResponse(data, **response_kwargs)
view.py中:
def user_query_json(request):
user_list = User.objects.all()
return JSONUtil.render_json(user_list, safe=False) # safe=False可以傳遞對(duì)象咬摇,否則必須傳遞一個(gè)dict,ajax請(qǐng)求時(shí)這樣要設(shè)置safe=False煞躬,這樣頁(yè)面可以直接獲取到對(duì)象
返回結(jié)果肛鹏,可以看到兩邊沒(méi)有引號(hào):
[{"model": "myapp.user", "pk": 4, "fields": {"name": "\u54c8\u54c8", "birth_day": "2018-04-09", "phone": "None", "email": "None"}}, {"model": "myapp.user", "pk": 9, "fields": {"name": "\u5929\u738b\u5c71", "birth_day": "2018-09-10", "phone": "123", "email": "123@123.com"}}]
def user_query_json_get(request, user_id):
user = User.objects.get(pk=user_id)
# user = User.objects.filter(pk=user_id)
return JSONUtil.render_json(user, dict_key='user', safe=True)
返回結(jié)果:[{"model": "myapp.user", "pk": 1, "fields": {"name": "\u97e9\u7fa4\u5cf0", "birth_day": "2018-04-07", "phone": "None", "email": "qunfeng_han@126.com"}}]
模板中:
<script src="{% static 'polls/js/jquery-1.11.0.min.js' %}"></script> #注意這里必須有閉合標(biāo)簽</script>,否則顯示會(huì)有問(wèn)題
<div id="userdiv"></div>
<div id="userlistdiv"></div>
<script>
$.getJSON("{% url 'myapp:user_query_json_get' 1 %}", function(ret) {
$.each(ret, function (key, value) {
// key 為字典的 key汰翠,value 為對(duì)應(yīng)的值
$("#userdiv").append(value.pk+"#"+value.fields.name+"#"+value.fields.birth_day+"#"+value.fields.phone+"#"+value.fields.email+"<br>")
});
});
$.getJSON("{% url 'myapp:user_query_json' %}", function(ret) {
$.each(ret, function (key, value) {
// key 為字典的 key龄坪,value 為對(duì)應(yīng)的值
$("#userlistdiv").append(value.pk+"#"+value.fields.name+"#"+value.fields.birth_day+"#"+value.fields.phone+"#"+value.fields.email+"<br>")
});
})
</script>
2.xml
XMLUtil.py
# -*- coding=utf-8 -*-
from django.core import serializers
from django.db import models
from django.db.models.query import QuerySet
from django.http import HttpResponse
def render_xml(data):
data = to_xml(data)
response = HttpResponse(data)
response['Content-Type'] = 'application/xml'
return response
# 序列化
def to_xml(data):
if isinstance(data, models.Model):
data = [data] # 因?yàn)閟erialize只支持可迭代對(duì)象昭雌,比如querySet對(duì)象
elif isinstance(data, QuerySet):
data = data
else:
pass
data = serializers.serialize("xml", data)
return data
# 反序列化
def xml_to_list(xml):
deserializedObjectList = serializers.deserialize("xml", xml)
list = []
for deserializedObject in deserializedObjectList:
list.append(deserializedObject.object)
return list
views.py
from utils import XMLUtil
def user_query_xml(request):
user_list = User.objects.all()
return XMLUtil.render_xml(user_list)
def user_query_xml_get(request, user_id):
user = User.objects.get(pk=user_id)
return XMLUtil.render_xml(user)
輸出結(jié)果
<?xml version="1.0" encoding="utf-8"?>
<django-objects version="1.0">
<object model="myapp.user" pk="4">
<field name="name" type="CharField">哈哈</field>
<field name="birth_day" type="DateField">2018-04-09</field>
<field name="phone" type="CharField">13800138000</field>
<field name="email" type="CharField">138@qq.com</field>
</object>
<object model="myapp.user" pk="2">
<field name="name" type="CharField">張三</field>
<field name="birth_day" type="DateField">
<None></None>
</field>
<field name="phone" type="CharField">
<None></None>
</field>
<field name="email" type="CharField">zhansan@163.com</field>
</object>
</django-objects>
js:
$.ajax({
url:"{% url 'myapp:user_query_xml' %}",
type:"GET",
dataType:'xml',
success:function(xml){
$(xml).find("object").each(function(i) {
//獲取id
var id=$(this).attr("pk");
var content = "";
$(this).find("field").each(function(j){
content += $(this).attr('name') + "==" + $(this).text() + "#"
})
$("#userdivxml").append(id+ "#" + content +"<br>")
});
},
error:function(){ alert("加載失敗"); }
})
16.response添加相應(yīng)頭
一般我們返回視圖時(shí)都是調(diào)用
from django.shortcuts import render的render(request, 'myapp/user/index.html', context)
實(shí)際上它返回的是一個(gè)HttpResponse對(duì)象复唤,我們可以這樣為其添加返回頭
response = render(request, 'myapp/user/index.html', context)
response['Last-Modified'] = date.strftime('%a, %d %b %Y %H:%M:%S GMT')
return response
17.多語(yǔ)言
參考:https://code.ziqiangxuetang.com/django/django-internationalization.html
1.brew install gettext
2.pip的bug,需要手工處理
/venv/lib/python3.6/site-packages/pip-9.0.1-py3.6.egg/pip/_vendor/webencodings/
修改3個(gè)文件:
init.py烛卧,
tests.py佛纫,
x_user_defined.py,
將:utf8 修改為 utf-8.
3.settings.py
LANGUAGE_CODE = 'zh-hans' # 英文是en总放,這里是中文呈宇,注意這里必須配置為zh-hans,而下面創(chuàng)建和編譯語(yǔ)言文件是要使用zh_hans
USE_I18N = True
LOCALE_PATHS = (
os.path.join(BASE_DIR, 'myapp/locale'), # 應(yīng)用下的路徑
os.path.join(BASE_DIR, 'locale'),
)
注意:這里『locale』文件夾需要手工創(chuàng)建局雄,默認(rèn)就是項(xiàng)目根路徑下的locale目錄甥啄。
這里需要注意一點(diǎn),如果應(yīng)用下面創(chuàng)建了locale并且配置到LOCALE_PATHS中炬搭,則后面執(zhí)行創(chuàng)建命令時(shí)蜈漓,無(wú)論是在項(xiàng)目根路徑下執(zhí)行還是在應(yīng)用下執(zhí)行,都只會(huì)將語(yǔ)言文件創(chuàng)建到應(yīng)用下的locale中宫盔。如果應(yīng)用下沒(méi)用locale目錄則需要在項(xiàng)目根路徑下執(zhí)行命令融虽,并且創(chuàng)建到項(xiàng)目根路徑下的locale目錄中。
4.在代碼中加入一些多語(yǔ)言對(duì)應(yīng)的內(nèi)容
代碼中
from django.utils.translation import ugettext as _
output = _('Today is %(month)s %(day)s.') % {'month': m, 'day': d}
模板頁(yè)面中可以直接使用下劃線的別名形式
{{ _('Django site admin') }}<br>
{{ _('my test local') }}<br>
這里注意灼芭,如果要使用『trans』標(biāo)簽有额,必須在頁(yè)面中加載{% load i18n %}
{% load i18n %}
{% trans "my test local" %}<br>
{#將翻譯結(jié)果保存到變量中#}
{% trans "my test local" as mylocal %}
{{ mylocal }}<br>
{#設(shè)置局部顯示的語(yǔ)言,下面的內(nèi)容將顯示對(duì)應(yīng)的英文內(nèi)容,但只在區(qū)塊內(nèi)有效#}
{% language 'en' %}
{% get_current_language as LANGUAGE_CODE %}
Current language: {{ LANGUAGE_CODE }} <br> #區(qū)塊內(nèi)顯示en
{{ _('Django site admin') }}<br>
{% endlanguage %}
{% get_current_language as LANGUAGE_CODE %}
Current language: {{ LANGUAGE_CODE }} <br> #區(qū)塊外顯示zh-hans
如果沒(méi)有找到對(duì)應(yīng)的key值巍佑,則會(huì)直接顯示待翻譯的key值字符串茴迁;
如果對(duì)應(yīng)的語(yǔ)言包下沒(méi)有找到key值,而默認(rèn)語(yǔ)言包下有對(duì)應(yīng)的key值萤衰,則會(huì)顯示默認(rèn)的語(yǔ)言笋熬,如LANGUAGE_CODE = 'zh-hans'
PS:如果需要翻譯的內(nèi)容包含變量,比如_('Today is %(month)s %(day)s.') 腻菇,最好在后臺(tái)處理好后做為變量傳遞到模板頁(yè)面上胳螟,目前暫不知道如何在模板中直接處理。
5.創(chuàng)建或更新語(yǔ)言文件
django-admin makemessages -l en
# 英文
django-admin makemessages -l zh_hans
#指定中文語(yǔ)言筹吐,注意這里不要寫(xiě)成zh-hans
會(huì)在locale目錄下生成對(duì)應(yīng)的語(yǔ)言包django.po
django-admin makemessages -a
#全部語(yǔ)言
說(shuō)明:如果在項(xiàng)目根路徑下執(zhí)行糖耸,會(huì)將項(xiàng)目中所有應(yīng)用都掃描一遍并匯總合并到一起,如果在某個(gè)應(yīng)用下執(zhí)行命令丘薛,則只會(huì)掃描當(dāng)前應(yīng)用嘉竟,并在其下的locale目錄下創(chuàng)建文件,優(yōu)先級(jí)根據(jù)settings中配置的LOCALE_PATHS的順序而定洋侨。
6.編譯
django-admin compilemessages --locale zh_hans
#指定語(yǔ)言
django-admin compilemessages
# 全部語(yǔ)言
- django.po---->diango.mo
7.語(yǔ)言切換
1)在settings中的中間件配置中加入如下配置:
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
2)url中加入配置:
path('i18n/', include('django.conf.urls.i18n')), #對(duì)應(yīng)下面的{% url 'set_language' %}
變更后的語(yǔ)言會(huì)保存在session中舍扰,可以通過(guò)request.session['_language']
獲得
3)在模板頁(yè)面中需要切換語(yǔ)言的地方加入如下代碼:
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input type="submit" value="Go" />
</form>
說(shuō)明:
redirect_to:如果不設(shè)置就會(huì)返回當(dāng)前頁(yè)面,設(shè)置的話就會(huì)跳轉(zhuǎn)到設(shè)置的頁(yè)面
這里get_available_languages會(huì)顯示所有支持的語(yǔ)言希坚,不過(guò)一般項(xiàng)目不會(huì)支持這么多的語(yǔ)言边苹,所以可以在settings中增加配置來(lái)明確語(yǔ)言范圍:
LANGUAGES = (
('en', ('English')),
('zh-hans', ('中文簡(jiǎn)體')),
('zh-hant', ('中文繁體')),
)
4)js中使用多語(yǔ)言
js需要單獨(dú)處理,比如我們寫(xiě)了一個(gè)js文件裁僧,路徑為project/myapp/static/myapp/js/test.js
a = gettext('wwww hhhh')
alert(a)
模板中引入:
下面這個(gè)是動(dòng)態(tài)js个束,必須引入,否則gettext方法不起作用
<script type="text/javascript" src="{% url 'javascript-catalog' %}"></script>
<script src="{% static 'myapp/js/test.js' %}"></script>
urls加入對(duì)javascript-catalog的支持:
`path('jsi18n/', JavaScriptCatalog.as_view(), name='javascript-catalog'),``
執(zhí)行如下命令:
django-admin makemessages -d djangojs -l zh_hans
此時(shí)會(huì)在應(yīng)用下的locale中生成djangojs.po文件(如果配置了應(yīng)用locale聊疲,否則會(huì)在項(xiàng)目下的locale中創(chuàng)建)
django-admin compilemessages --locale zh_hans
此時(shí)會(huì)將djangojs.po編譯為djangojs.mo
如果直接將帶翻譯的js代碼寫(xiě)在模板頁(yè)面中茬底,暫時(shí)不清楚要通過(guò)什么命令實(shí)現(xiàn),不過(guò)可以有個(gè)折中的辦法获洲,就是創(chuàng)建一個(gè)js文件阱表,然后將所有需要翻譯的內(nèi)容都加上,然后運(yùn)行上面兩個(gè)命令贡珊,這樣django在運(yùn)行模板中的js時(shí)同樣可以完成翻譯
模板中:
<script>
alert(gettext('hello js'))
alert(gettext('o my god'))
</script>
js中:只要js代碼中出現(xiàn)翻譯方法的地方都會(huì)被加入翻譯最爬,這個(gè)js不需要被任何模板引入,也不需要被同步到靜態(tài)文件夾中飞崖,僅僅是為生成翻譯文件而存在
gettext('hello js')
gettext('o my god')
18.日志
1.settings
LOGGING = {
'version': 1,
'disable_existing_loggers': False, # 是否禁用logger烂叔,建議設(shè)置為False
'formatters': { # 日志格式,提供給handler使用固歪,非必須蒜鸡,如果不設(shè)置格式胯努,默認(rèn)只會(huì)打印消息體
'verbose': { # 格式名稱(chēng)
# INFO 2018-04-25 15:43:27,586 views 8756 123145350217728 這是一個(gè)日志
'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
},
'simple': {
# INFO 這是一個(gè)日志
'format': '%(levelname)s %(message)s'
},
'standard': {
# 2018-04-25 16:40:00,195 [Thread-7:123145575223296] [myapp.log:282] [views:user_query_json_get] [INFO]- 這是一個(gè)日志
'format': '%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'
},
},
'filters': { # 過(guò)濾器,提供給handler使用逢防,非必須
'require_debug_true': { # 要求DEBUG=True時(shí)才打印日志
'()': 'django.utils.log.RequireDebugTrue',
},
},
'handlers': { # 處理器叶沛,設(shè)置日志記錄方式,必須
'console': { # 處理器名稱(chēng)
'level': 'DEBUG', # 設(shè)置級(jí)別
'filters': ['require_debug_true'], # 設(shè)置過(guò)濾器忘朝,多個(gè)用逗號(hào)分割
'class': 'logging.StreamHandler', # 處理器灰署,這里是控制臺(tái)打印
'formatter': 'verbose' # 設(shè)置日志格式
},
'file': {
'level': 'DEBUG',
'class': 'logging.FileHandler', # 記錄到文件
'filename': '/Users/hanqunfeng/python_workspace/log/file.log',
'formatter': 'verbose'
},
'rotatingFile': {
'level': 'DEBUG',
'class': 'logging.handlers.RotatingFileHandler', # 按文件大小切割日志
# 'filename': 'log/all.log', # 日志輸出文件 默認(rèn)在當(dāng)前項(xiàng)目根路徑下
'filename': '/Users/hanqunfeng/python_workspace/log/rotatingFile.log', # 日志輸出文件
'maxBytes': 1024 * 1024 * 5, # 每個(gè)文件大小
'backupCount': 5, # 保留日志份數(shù),只保留最后5份局嘁,如果都保留溉箕,設(shè)置為0,默認(rèn)就是0
'formatter': 'standard', # 使用哪種formatters日志格式
},
'timedRotatingFile': {
'level': 'DEBUG',
'class': 'logging.handlers.TimedRotatingFileHandler', # 按時(shí)間切割日志
'filename': '/Users/hanqunfeng/python_workspace/log/timedRotatingFile.log', # 日志輸出文件
'when': 'D', # 按天分割
'backupCount': 5, # 保留日志份數(shù)悦昵,只保留最后5份肴茄,如果都保留,設(shè)置為0但指,默認(rèn)就是0
'formatter': 'standard', # 使用哪種formatters日志格式
},
},
'loggers': {#日志記錄器
'django': {#日志名稱(chēng)路徑前綴寡痰,即logging.getLogger(__name__)獲取logger對(duì)象時(shí),_name__得到的前綴與之匹配即可棋凳,比如__name__得到的是django.server
'handlers': ['console'],
'propagate': True,
'level': os.getenv('DJANGO_LOG_LEVEL', 'DEBUG'), # 只有設(shè)置DEBUG = True時(shí)拦坠,該配置才會(huì)打印sql信息
},
'django.request': {
'handlers': ['rotatingFile'],
'level': 'ERROR',
'propagate': False, # 設(shè)置為False,表示不像其父級(jí)別傳遞日志內(nèi)容
},
'myapp.log': { # 也可以這樣創(chuàng)建logger對(duì)象剩岳,logging.getLogger('myapp.log')
'handlers': ['file', 'timedRotatingFile'],
'level': 'INFO', # 這里的日志級(jí)別不能低于處理器中設(shè)置的日志級(jí)別
},
},
}
代碼中使用方式:
# 導(dǎo)入logging庫(kù)
import logging
# 獲取logger的一個(gè)實(shí)例
# logger = logging.getLogger(__name__)
logger = logging.getLogger('myapp.log')
# 方法中:
logger.info('這是一個(gè)日志')
19.發(fā)送郵件
1.settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_USE_SSL = True
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 465
EMAIL_HOST_USER = 'xxx@163.com' # 帳號(hào)
EMAIL_HOST_PASSWORD = 'xxxxxxx' # 密碼
DEFAULT_FROM_EMAIL = 'hanqf <xxx@163.com>'
2.代碼里
from django.conf import settings
# 發(fā)送郵件
from django.core.mail import send_mail
send_mail('Subject here主題', 'Here is the message.消息', settings.DEFAULT_FROM_EMAIL,
['aaaaa@126.com'], fail_silently=False)
# 一次可以發(fā)送多組郵件
from django.core.mail import send_mass_mail
message1 = ('Subject here', 'Here is the message', settings.DEFAULT_FROM_EMAIL,
['aaaaa@126.com', 'aaaaa@163.com'])
message2 = ('Another Subject', 'Here is another message', settings.DEFAULT_FROM_EMAIL, ['aaaaa@126.com'])
send_mass_mail((message1, message2), fail_silently=False)
# 可以這是抄送附件等
from django.core.mail import EmailMultiAlternatives
msg = EmailMultiAlternatives('主題', '內(nèi)容', settings.DEFAULT_FROM_EMAIL, ['aaaaa@126.com'],
cc=['aaaaa@163.com'])
# msg.content_subtype = "html" # 設(shè)置郵件格式贞滨,html可以發(fā)送內(nèi)容為html,不推薦這么使用卢肃,可以使用下面的方式
html_content = '<p>這是一封<strong>重要的</strong>郵件.</p>'
msg.attach_alternative(html_content, "text/html") # 如果接收方的郵件支持html疲迂,則顯示該信息,否則顯示原「內(nèi)容」
# 添加附件(可選)
msg.attach_file('/Users/hanqunfeng/python_workspace/STATIC_ROOT/polls/images/background.jpg')
# 發(fā)送
msg.send()
20.main方法測(cè)試
mian方法測(cè)試一定要在如下情況下使用莫湘,這樣可以保證當(dāng)前模塊被別處引用時(shí)不會(huì)觸發(fā)如下測(cè)試代碼,只有獨(dú)立運(yùn)行該模塊時(shí)才會(huì)執(zhí)行郑气。
if __name__ == '__main__':
# 加載環(huán)境配置
import django, os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "DjangoHelloWorld.settings")
django.setup()
# 以下是測(cè)試內(nèi)容
from myapp.models.user import User
user_list = User.objects.all()
xml = to_xml(user_list)
print(xml)
21.Signal幅垮,信號(hào),有點(diǎn)類(lèi)似MQ
1.定義信號(hào)和接收器
from django.dispatch import Signal, receiver
# my_singal = Signal()
my_singal = Signal(providing_args=["key1", "key2"]) # 定義信號(hào)接收的參數(shù)尾组,不指定參數(shù)也可以
@receiver(my_singal)
def my_callback(sender, **kwargs): # 接收器回調(diào)函數(shù)
print(sender)
print(kwargs)
for key in kwargs:
print(key)
print(kwargs[key])
print("Request finished!")
2.發(fā)送信號(hào)忙芒,發(fā)送信號(hào)時(shí)接收器就會(huì)被執(zhí)行
from signals.signals import my_singal
my_singal.send(sender=__name__, key1='qqq', key2=10, key3=100) # 實(shí)際上可以多發(fā)送一些參數(shù)
22.Django管理后臺(tái)簡(jiǎn)介
首先,我們需要?jiǎng)?chuàng)建一個(gè)能夠登錄管理后臺(tái)站點(diǎn)的用戶讳侨。
運(yùn)行如下命令:
python manage.py createsuperuser
鍵入你想要使用的用戶名呵萨,然后按下回車(chē)鍵:
Username: admin
然后提示你輸入想要使用的郵件地址:
Email address: admin@example.com
你需要輸入兩次密碼,第二次輸入是確認(rèn)密碼
Password: **********
Password (again): *********
Superuser created successfully.
PS:管理員密碼忘記了可以通過(guò)如下方法修改:
$ python manage.py shell
>>> from django.contrib.auth.models import User
>>> user = User.objects.get(pk=1) # 可以通過(guò)查詢獲得用戶對(duì)象
>>> user.set_password('xxxxxxxx')
>>> user.save()
>>> quit()
23.部署正式環(huán)境
settings.py:
DEBUG = False # 此時(shí)很多問(wèn)題就會(huì)出現(xiàn)跨跨,需要增加很多額外的配置才能正常工作潮峦,這也是為了包含生產(chǎn)環(huán)境吧
ALLOWED_HOSTS = ['127.0.0.1']
# ALLOWED_HOSTS = ['*', ] # 允許所有機(jī)器訪問(wèn)
STATIC_URL = 'http://localhost/static/' # apache部署的靜態(tài)文件服務(wù)器訪問(wèn)地址
STATIC_ROOT = "/Users/hanqunfeng/python_workspace/STATIC_ROOT/" #apache 服務(wù)目錄
# 上傳文件路徑
MEDIA_URL = 'http://localhost/media/'
MEDIA_ROOT = '/Users/hanqunfeng/python_workspace/MEDIA/'
apache配置:
Alias /media/ /Users/hanqunfeng/python_workspace/MEDIA/
Alias /static/ /Users/hanqunfeng/python_workspace/STATIC_ROOT/
<Directory /Users/hanqunfeng/python_workspace/STATIC_ROOT>
Require all granted
</Directory>
<Directory /Users/hanqunfeng/python_workspace/MEDIA/>
Require all granted
</Directory>
使用如下命令可以將本地的靜態(tài)資源部署到apache服務(wù)目錄:
python manage.py collectstatic
模板頁(yè)面:
{% load static %}
<link rel="stylesheet" type="text/css" href="{% static 'polls/style.css' %}" />
上傳文件:
model中:
photo = models.ImageField(upload_to="photo", default="default/django.jpeg") # 路徑相對(duì)于MEDIA_ROOT的配置
之后要注意更新數(shù)據(jù)庫(kù)囱皿。
需要安裝Pillow,否則會(huì)報(bào)錯(cuò)
ERRORS:
polls.Question.photo: (fields.E210) Cannot use ImageField because Pillow is not installed.
HINT: Get Pillow at https://pypi.python.org/pypi/Pillow or run command "pip install Pillow".
pip install Pillow
如果要在頁(yè)面中使用settings中的變量忱嘹,需要在當(dāng)前應(yīng)用中創(chuàng)建一個(gè)context_processors.py 文件
from django.conf import settings # import the settings file
def settings_constant(request):
# return the value you want as a dictionnary. you may add multiple values in there.
return {'MEDIA_URL': settings.MEDIA_URL, 'DEBUG': settings.DEBUG}
并在settings文件配置如下
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')]
,
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
'polls.context_processors.settings_constant', #應(yīng)用名稱(chēng).文件名稱(chēng).方法名稱(chēng)
],
},
},
]
模板頁(yè)面中:
<form enctype="multipart/form-data">
<img src="{{MEDIA_URL}}abc/a.png">
<input type="file" name="photo" id="id_photo" />
</form>
也可以使用下面的形式獲得上傳文件的url嘱腥,
即使用上傳文件字段的url屬性:{{ question.photo.url }}
<a href="{{MEDIA_URL}}{{ question.photo }}">{{ question.photo }}</a> ##
<a href="{{ question.photo.url }}">{{ question.photo }}</a>
views處理代碼中:
input_img = request.FILES['photo']
question.photo = input_img
question.save()
部署到apache:
下載mod_wsgi:https://github.com/GrahamDumpleton/mod_wsgi/releases
tar xvfz mod_wsgi-X.Y.tar.gz
./configure --with-apxs=/Applications/XAMPP/bin/apxs --with-python=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
make
make install
然后在apache配置文件中加入如下配置
LoadModule wsgi_module modules/mod_wsgi.so
普通模式:
WSGIPythonHome /Users/hanqunfeng/python_workspace/DjangoHelloWorld/venv
WSGIPythonPath /Users/hanqunfeng/python_workspace/DjangoHelloWorld
或者采用守護(hù)進(jìn)程模式:
WSGIDaemonProcess example.com python-home=/Users/hanqunfeng/python_workspace/DjangoHelloWorld/venv python-path=/Users/hanqunfeng/python_workspace/DjangoHelloWorld
WSGIProcessGroup example.com
配置項(xiàng)目訪問(wèn)路徑
WSGIScriptAlias /mysite /Users/hanqunfeng/python_workspace/DjangoHelloWorld/DjangoHelloWorld/wsgi.py
<Directory /Users/hanqunfeng/python_workspace/DjangoHelloWorld/DjangoHelloWorld>
<Files wsgi.py>
Require all granted
</Files>
</Directory>
訪問(wèn)地址:http://127.0.0.1/mysite/polls