Django2學(xué)習(xí)筆記

摘要

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市拘悦,隨后出現(xiàn)的幾起案子齿兔,更是在濱河造成了極大的恐慌,老刑警劉巖础米,帶你破解...
    沈念sama閱讀 212,185評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件分苇,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡屁桑,警方通過(guò)查閱死者的電腦和手機(jī)组砚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,445評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)掏颊,“玉大人糟红,你說(shuō)我怎么就攤上這事∥谝叮” “怎么了盆偿?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,684評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)准浴。 經(jīng)常有香客問(wèn)我事扭,道長(zhǎng),這世上最難降的妖魔是什么乐横? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,564評(píng)論 1 284
  • 正文 為了忘掉前任求橄,我火速辦了婚禮,結(jié)果婚禮上葡公,老公的妹妹穿的比我還像新娘罐农。我一直安慰自己,他們只是感情好催什,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,681評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布涵亏。 她就那樣靜靜地躺著,像睡著了一般蒲凶。 火紅的嫁衣襯著肌膚如雪气筋。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,874評(píng)論 1 290
  • 那天旋圆,我揣著相機(jī)與錄音宠默,去河邊找鬼。 笑死灵巧,一個(gè)胖子當(dāng)著我的面吹牛搀矫,可吹牛的內(nèi)容都是我干的抹沪。 我是一名探鬼主播,決...
    沈念sama閱讀 39,025評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼艾君,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼采够!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起冰垄,我...
    開(kāi)封第一講書(shū)人閱讀 37,761評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤蹬癌,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后虹茶,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體逝薪,經(jīng)...
    沈念sama閱讀 44,217評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,545評(píng)論 2 327
  • 正文 我和宋清朗相戀三年蝴罪,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了董济。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,694評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡要门,死狀恐怖虏肾,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情欢搜,我是刑警寧澤封豪,帶...
    沈念sama閱讀 34,351評(píng)論 4 332
  • 正文 年R本政府宣布,位于F島的核電站炒瘟,受9級(jí)特大地震影響吹埠,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜疮装,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,988評(píng)論 3 315
  • 文/蒙蒙 一缘琅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧廓推,春花似錦刷袍、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,778評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至滚局,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間顽频,已是汗流浹背藤肢。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,007評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留糯景,地道東北人嘁圈。 一個(gè)月前我還...
    沈念sama閱讀 46,427評(píng)論 2 360
  • 正文 我出身青樓省骂,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親最住。 傳聞我的和親對(duì)象是個(gè)殘疾皇子钞澳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,580評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容