摘要
1.安装
pip install Django
python -m django --version
2.创建新项目
django-admin startproject mysite
# mysite就是项目名称
3.创建新的应用
python manage.py startapp polls
# polls是应用名称
settings.py中加入新应用配置
1 2 3 4 5 6 7 8 9 INSTALLED_APPS = [ 'polls.apps.PollsConfig' , 'django.contrib.admin' , 'django.contrib.auth' , 'django.contrib.contenttypes' , 'django.contrib.sessions' , 'django.contrib.messages' , 'django.contrib.staticfiles' , ]
4.创建和更新数据库:
python manage.py makemigrations
# 全部应用都会创建迁移文件
python manage.py makemigrations polls
# 只创建指定的应用
python manage.py migrate
# 执行迁移文件到数据库
查看迁移文件生成的sql:
sqlmigrate命令接收迁移文件的名字并返回它们的SQL语句:#只是打印出要执行的sql语句
python manage.py sqlmigrate polls 0001
# 这里迁移文件的后缀_initial.py不需要。
5.启动服务器
Django的管理后台站点是默认启用的。 让我们启动开发服务器,然后探索它。
如果服务器没有运行,像下面这样启动它:
python manage.py runserver
现在,打开一个浏览器访问你本地域名中的 “/admin/” — 例如http://127.0.0.1:8000/admin/。
启动:
python manage.py runserver 9000
#指定启动端口
python manage.py runserver 0.0.0.0:9000
#指定启动ip+端口
6.测试:
python manage.py test
#运行整个项目的全部tests.py
python manage.py test django2
#运行指定模块的tests.py
python manage.py test django2.tests.Django2Test
#测试指定模块的指定测试类
python manage.py test django2.tests.Django2Test.test_sql
#测试指定模块的指定测试类指定方法
7.检查代码覆盖率:
pip install coverage
coverage run my_program.py arg1 arg2
django检查方法:
coverage run --source='.' manage.py test myapp
之后可以运行
coverage report
:显示结果
coverage html
:生成html 测试会在当前项目下生成htmlcov目录,运行index.html即可查看
8.mysql:
brew install mysql-connector-c
pip install mysqlclient
需要提前创建好数据库
settings.py :
1 2 3 4 5 6 7 8 9 10 DATABASES = { 'default' : { 'ENGINE' : 'django.db.backends.mysql' , 'NAME' : 'django' , 'USER' : 'django' , 'PASSWORD' : 'django' , 'HOST' : '127.0.0.1' , 'PORT' : '3306' , } }
数据库更新:
一般情况下,我们使用如下两个命令更新数据库
python manage.py makemigrations
#生成数据库模型文件
python manage.py migrate
#执行模型文件
或者:
python manage.py migrate --database=users
#指定数据库,默认为default
如果由于默写原因删除了数据库中对应的表,则再次执行上面的命令是不能重新创建成功的,原因是每次django执行模型文件时都会在django_migrations表中新增对应的log记录,删掉对应的log记录即可重新执行成功。
9.多数据源配置
django配置连接多个数据库,自定义表名称:
https://www.cnblogs.com/dreamer-fish/p/5469141.html
使用models文件夹维护model时,一定要在其下的__init__.py中添加对model的引用,
否则python manage.py makemigrations
命令不会创建出对应的迁移文件
比如:
1 2 3 4 from .person import Personfrom .user import Userfrom .identity_card import IdentityCardfrom .car import Car
数据库路由:
settings.py :
1 DATABASE_ROUTERS = ['django2.router.django2_router.Django2Router' , ]
可以将对应的迁移文件的sql导入到指定的db,所以路由器的设置很重要
1 2 3 4 5 def allow_migrate (self, db, app_label, model_name=None , **hints ): if db == 'django2_db' : return app_label == 'django2' elif app_label == 'django2' : return False
设置好数据库路由器后,执行python manage.py migrate --database=django2_db
10.缓存
说明:不推荐使用站点级缓存和页面级缓存,除非是展示信息类的网站,如果是频繁修改的站点,最好手工在代码中维护缓存。
1).memcached
brew install memcached
启动:memcached -d -p 11211 -c 1024 -m 64
-d:后台运行
-p:端口
-c:最大连接数
-m:最多分配内存
1.使用memcached:pip install python-memcached
2.settings
1 2 3 4 5 6 7 8 9 CACHES = { 'default' : { 'BACKEND' : 'django.core.cache.backends.memcached.MemcachedCache' , 'LOCATION' : '127.0.0.1:11211' , 'TIMEOUT' : 600 , 'KEY_PREFIX' : 'myapp' , } }
3.代码中
1 2 from django.core.cache import cachescache = caches['default' ]
1 2 3 4 5 6 from django.core.cache import cachecache.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
启动:redis-server /usr/local/etc/redis.conf
2.pip install django-redis
3.settings
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 CACHES = { 'default' : { 'BACKEND' : 'django.core.cache.backends.memcached.MemcachedCache' , 'LOCATION' : '127.0.0.1:11211' , 'TIMEOUT' : 600 , '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 , "SOCKET_TIMEOUT" : 5 , "COMPRESSOR" : "django_redis.compressors.zlib.ZlibCompressor" , "IGNORE_EXCEPTIONS" : True , "CONNECTION_POOL_KWARGS" : {"max_connections" : 100 } } } } DJANGO_REDIS_LOG_IGNORED_EXCEPTIONS = True
4.代码中
1 2 3 4 5 6 from django.core.cache import cachesredis_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.注册模板自定义方法:
1.创建myapp.libraries.utils.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 from django import templateregister = template.Library() color = ((1 , 'red' ), (2 , 'black' ), (3 , 'blue' )) @register.filter def getcolorstr (colorNum ): return color[colorNum - 1 ][1 ] @register.simple_tag def getcolorstr2 (colorNum ): return color[colorNum - 1 ][1 ]
2.settings:在模板配置中加入libraries配置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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' : { 'utils' : 'myapp.libraries.utils' , }, }, }, ]
3.模板页面中使用
1 2 3 {% load utils %} {{ car.carColor|getcolorstr }} {% getcolorstr2 car.carColor %}
12.模板
1.转义:
由于模板系统没有“转义”的概念,为了显示模板标签中使用的一个位,必须使用{% templatetag %}标记。
1 2 3 4 5 6 7 8 9 论据 输出 openblock {% closeblock %} openvariable {{ closevariable }} openbrace { closebrace } opencomment {# closecomment #}
例如:
1 {% templatetag openblock %} url 'entry_list' {% templatetag closeblock %}
或者使用如下方式:被包含的内容不会被模板引擎转义,将直接输出
1 2 3 {% verbatim myblock %} Avoid template rendering via the {% verbatim %}{% endverbatim %} block. {% endverbatim myblock %}
2.for:
1 2 3 4 5 6 7 8 变量 描述 forloop.counter 循环的当前迭代(1索引) forloop.counter0 循环的当前迭代(0索引) forloop.revcounter 循环结束的迭代次数(1索引) forloop.revcounter0 循环结束的迭代次数(0索引) forloop.first 如果这是第一次通过循环,则为真 forloop.last 如果这是最后一次循环,则为真 forloop.parentloop 对于嵌套循环,这是围绕当前循环的循环
13.自定义400、403、404、500页面
1.settings.py中DEBUG = False,否则自定义页面不起作用
2.在任意模块下的views.py中增加如下方法,也可以在主模块中创建一个views.py
方法处理逻辑可以参考:~venv/lib/python3.6/site-packages/django/views/defaults.py中对各个方法的定义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 from django.shortcuts import renderdef 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.在项目根目录下的templates下创建对应的400.html、403.html、404.html、500.html,内容更加需要自定义,也可以参考~venv/lib/python3.6/site-packages/django/views/templates下的对应文件
4.在主模块下urls.py中增加如下配置:
1 2 3 4 handler400 = 'DjangoHelloWorld.views.bad_request' handler403 = 'DjangoHelloWorld.views.permission_denied' handler404 = 'DjangoHelloWorld.views.page_not_found' handler500 = 'DjangoHelloWorld.views.server_error'
14.Django配置session超时
#配置失效时间为半个小时
SESSION_COOKIE_AGE = 60*30
#关闭浏览器清除cookie
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
15.json与xml
1.json
创建一个JSONUtil工具类,用于返回json数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 import jsonfrom django.core.serializers import serialize, deserializefrom django.db import modelsfrom django.db.models.query import QuerySetfrom django.http import JsonResponsedef 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] data = serialize("json" , obj) return data 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} if isinstance (data, str ): data = json.loads(data) return JsonResponse(data, **response_kwargs)
view.py中:
1 2 3 def user_query_json (request ): user_list = User.objects.all () return JSONUtil.render_json(user_list, safe=False )
返回结果,可以看到两边没有引号:
[{“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 ”}}]
1 2 3 4 def user_query_json_get (request, user_id ): user = User.objects.get(pk=user_id) return JSONUtil.render_json(user, dict_key='user' , safe=True )
返回结果:[{“model”: “myapp.user”, “pk”: 1, “fields”: {“name”: “\u97e9\u7fa4\u5cf0”, “birth_day”: “2018-04-07”, “phone”: “None”, “email”: “qunfeng_han@126.com ”}}]
模板中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 <script src ="{% static 'polls/js/jquery-1.11.0.min.js' %}" > </script > #注意这里必须有闭合标签</script > ,否则显示会有问题<div id ="userdiv" > </div > <div id ="userlistdiv" > </div > <script > $.getJSON ("{% url 'myapp:user_query_json_get' 1 %}" , function (ret ) { $.each (ret, function (key, value ) { $("#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 ) { $("#userlistdiv" ).append (value.pk +"#" +value.fields .name +"#" +value.fields .birth_day +"#" +value.fields .phone +"#" +value.fields .email +"<br>" ) }); }) </script >
2.xml
XMLUtil.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 from django.core import serializersfrom django.db import modelsfrom django.db.models.query import QuerySetfrom django.http import HttpResponsedef 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] 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
1 2 3 4 5 6 7 8 9 from utils import XMLUtildef 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)
输出结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 <?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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 $.ajax ({ url :"{% url 'myapp:user_query_xml' %}" , type :"GET" , dataType :'xml' , success :function (xml ){ $(xml).find ("object" ).each (function (i ) { 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添加相应头
一般我们返回视图时都是调用
from django.shortcuts import render的render(request, ‘myapp/user/index.html’, context)
实际上它返回的是一个HttpResponse对象,我们可以这样为其添加返回头
1 2 3 response = render(request, 'myapp/user/index.html' , context) response['Last-Modified' ] = date.strftime('%a, %d %b %Y %H:%M:%S GMT' ) return response
17.多语言
参考: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个文件:
init .py,
tests.py ,
x_user_defined.py,
将:utf8 修改为 utf-8.
3.settings.py
1 2 3 4 5 6 LANGUAGE_CODE = 'zh-hans' USE_I18N = True LOCALE_PATHS = ( os.path.join(BASE_DIR, 'myapp/locale' ), os.path.join(BASE_DIR, 'locale' ), )
注意:这里『locale』文件夹需要手工创建,默认就是项目根路径下的locale目录。
这里需要注意一点,如果应用下面创建了locale并且配置到LOCALE_PATHS中,则后面执行创建命令时,无论是在项目根路径下执行还是在应用下执行,都只会将语言文件创建到应用下的locale中。如果应用下没用locale目录则需要在项目根路径下执行命令,并且创建到项目根路径下的locale目录中。
4.在代码中加入一些多语言对应的内容
代码中
1 2 from django.utils.translation import ugettext as _ output = _('Today is %(month)s %(day)s.' ) % {'month' : m, 'day' : d}
模板页面中可以直接使用下划线的别名形式
1 2 {{ _('Django site admin') }}<br > {{ _('my test local') }}<br >
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 这里注意,如果要使用『trans』标签,必须在页面中加载 i18n {% load i18n %} {% trans "my test local" %}<br > {#将翻译结果保存到变量中#} {% trans "my test local" as mylocal %} {{ mylocal }}<br > {#设置局部显示的语言,下面的内容将显示对应的英文内容,但只在区块内有效#} {% language 'en' %} {% get_current_language as LANGUAGE_CODE %} Current language: {{ LANGUAGE_CODE }} <br > #区块内显示en {{ _('Django site admin') }}<br > {% endlanguage %} {% get_current_language as LANGUAGE_CODE %} Current language: {{ LANGUAGE_CODE }} <br > #区块外显示zh-hans
如果没有找到对应的key值,则会直接显示待翻译的key值字符串;
如果对应的语言包下没有找到key值,而默认语言包下有对应的key值,则会显示默认的语言,如LANGUAGE_CODE = ‘zh-hans’
PS:如果需要翻译的内容包含变量,比如_(‘Today is %(month)s %(day)s.’) ,最好在后台处理好后做为变量传递到模板页面上,目前暂不知道如何在模板中直接处理。
5.创建或更新语言文件
django-admin makemessages -l en
# 英文
django-admin makemessages -l zh_hans
#指定中文语言,注意这里不要写成zh-hans
会在locale目录下生成对应的语言包django.po
django-admin makemessages -a
#全部语言
说明:如果在项目根路径下执行,会将项目中所有应用都扫描一遍并汇总合并到一起,如果在某个应用下执行命令,则只会扫描当前应用,并在其下的locale目录下创建文件,优先级根据settings中配置的LOCALE_PATHS的顺序而定。
6.编译
django-admin compilemessages --locale zh_hans
#指定语言
django-admin compilemessages
# 全部语言
7.语言切换
1)在settings中的中间件配置中加入如下配置:
1 2 3 4 5 6 7 8 9 10 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中加入配置:
1 path('i18n/' , include('django.conf.urls.i18n' )),
变更后的语言会保存在session中,可以通过request.session['_language']
获得
3)在模板页面中需要切换语言的地方加入如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 <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 >
说明:
redirect_to:如果不设置就会返回当前页面,设置的话就会跳转到设置的页面
这里get_available_languages会显示所有支持的语言,不过一般项目不会支持这么多的语言,所以可以在settings中增加配置来明确语言范围:
1 2 3 4 5 LANGUAGES = ( ('en' , ('English' )), ('zh-hans' , ('中文简体' )), ('zh-hant' , ('中文繁體' )), )
4)js中使用多语言
js需要单独处理,比如我们写了一个js文件,路径为project/myapp/static/myapp/js/test.js
1 2 a = gettext ('wwww hhhh' ) alert (a)
模板中引入:
#下面这个是动态js,必须引入,否则gettext方法不起作用
1 2 <script type ="text/javascript" src ="{% url 'javascript-catalog' %}" > </script > <script src ="{% static 'myapp/js/test.js' %}" > </script >
urls加入对javascript-catalog的支持:
`path(‘jsi18n/’, JavaScriptCatalog.as_view(), name=‘javascript-catalog’),``
执行如下命令:
django-admin makemessages -d djangojs -l zh_hans
此时会在应用下的locale中生成djangojs.po文件(如果配置了应用locale,否则会在项目下的locale中创建)
django-admin compilemessages --locale zh_hans
此时会将djangojs.po编译为djangojs.mo
如果直接将带翻译的js代码写在模板页面中,暂时不清楚要通过什么命令实现,不过可以有个折中的办法,就是创建一个js文件,然后将所有需要翻译的内容都加上,然后运行上面两个命令,这样django在运行模板中的js时同样可以完成翻译
模板中:
1 2 3 4 <script> alert (gettext ('hello js' )) alert (gettext ('o my god' )) </script>
js中:只要js代码中出现翻译方法的地方都会被加入翻译,这个js不需要被任何模板引入,也不需要被同步到静态文件夹中,仅仅是为生成翻译文件而存在
1 2 gettext ('hello js' )gettext ('o my god' )
18.日志
1.settings
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 LOGGING = { 'version' : 1 , 'disable_existing_loggers' : False , 'formatters' : { 'verbose' : { 'format' : '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s' }, 'simple' : { 'format' : '%(levelname)s %(message)s' }, 'standard' : { 'format' : '%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s' }, }, 'filters' : { 'require_debug_true' : { '()' : 'django.utils.log.RequireDebugTrue' , }, }, 'handlers' : { 'console' : { 'level' : 'DEBUG' , 'filters' : ['require_debug_true' ], 'class' : 'logging.StreamHandler' , 'formatter' : 'verbose' }, 'file' : { 'level' : 'DEBUG' , 'class' : 'logging.FileHandler' , 'filename' : '/Users/hanqunfeng/python_workspace/log/file.log' , 'formatter' : 'verbose' }, 'rotatingFile' : { 'level' : 'DEBUG' , 'class' : 'logging.handlers.RotatingFileHandler' , 'filename' : '/Users/hanqunfeng/python_workspace/log/rotatingFile.log' , 'maxBytes' : 1024 * 1024 * 5 , 'backupCount' : 5 , 'formatter' : 'standard' , }, 'timedRotatingFile' : { 'level' : 'DEBUG' , 'class' : 'logging.handlers.TimedRotatingFileHandler' , 'filename' : '/Users/hanqunfeng/python_workspace/log/timedRotatingFile.log' , 'when' : 'D' , 'backupCount' : 5 , 'formatter' : 'standard' , }, }, 'loggers' : { 'django' : { 'handlers' : ['console' ], 'propagate' : True , 'level' : os.getenv('DJANGO_LOG_LEVEL' , 'DEBUG' ), }, 'django.request' : { 'handlers' : ['rotatingFile' ], 'level' : 'ERROR' , 'propagate' : False , }, 'myapp.log' : { 'handlers' : ['file' , 'timedRotatingFile' ], 'level' : 'INFO' , }, }, }
代码中使用方式:
1 2 3 4 5 6 7 8 import logginglogger = logging.getLogger('myapp.log' ) logger.info('这是一个日志' )
19.发送邮件
1.settings
1 2 3 4 5 6 7 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' EMAIL_HOST_PASSWORD = 'xxxxxxx' DEFAULT_FROM_EMAIL = 'hanqf <xxx@163.com>'
2.代码里
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 from django.conf import settingsfrom django.core.mail import send_mailsend_mail('Subject here主题' , 'Here is the message.消息' , settings.DEFAULT_FROM_EMAIL, ['aaaaa@126.com' ], fail_silently=False ) from django.core.mail import send_mass_mailmessage1 = ('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 EmailMultiAlternativesmsg = EmailMultiAlternatives('主题' , '内容' , settings.DEFAULT_FROM_EMAIL, ['aaaaa@126.com' ], cc=['aaaaa@163.com' ]) html_content = '<p>这是一封<strong>重要的</strong>邮件.</p>' msg.attach_alternative(html_content, "text/html" ) msg.attach_file('/Users/hanqunfeng/python_workspace/STATIC_ROOT/polls/images/background.jpg' ) msg.send()
20.main方法测试
mian方法测试一定要在如下情况下使用,这样可以保证当前模块被别处引用时不会触发如下测试代码,只有独立运行该模块时才会执行。
1 2 3 4 5 6 7 8 9 10 if __name__ == '__main__' : import django, os os.environ.setdefault("DJANGO_SETTINGS_MODULE" , "DjangoHelloWorld.settings" ) django.setup() from myapp.models.user import User user_list = User.objects.all () xml = to_xml(user_list) print (xml)
21.Signal,信号,有点类似MQ
1.定义信号和接收器
1 2 3 4 5 6 7 8 9 10 11 12 from django.dispatch import Signal, receivermy_singal = Signal(providing_args=["key1" , "key2" ]) @receiver(my_singal ) def my_callback (sender, **kwargs ): print (sender) print (kwargs) for key in kwargs: print (key) print (kwargs[key]) print ("Request finished!" )
2.发送信号,发送信号时接收器就会被执行
1 2 from signals.signals import my_singalmy_singal.send(sender=__name__, key1='qqq' , key2=10 , key3=100 )
22.Django管理后台简介
首先,我们需要创建一个能够登录管理后台站点的用户。
运行如下命令:
1 python manage.py createsuperuser
键入你想要使用的用户名,然后按下回车键:
然后提示你输入想要使用的邮件地址:
1 Email address: admin@example.com
你需要输入两次密码,第二次输入是确认密码
1 2 3 Password: ********** Password (again): ********* Superuser created successfully.
PS:管理员密码忘记了可以通过如下方法修改:
1 2 3 4 5 6 $ python manage.py shell >>> from django.contrib.auth.models import User >>> user = User.objects.get(pk=1) >>> user.set_password('xxxxxxxx' ) >>> user.save() >>> quit()
23.部署正式环境
settings.py :
1 2 3 4 5 6 7 8 9 10 11 12 DEBUG = False ALLOWED_HOSTS = ['127.0.0.1' ] STATIC_URL = 'http://localhost/static/' STATIC_ROOT = "/Users/hanqunfeng/python_workspace/STATIC_ROOT/" MEDIA_URL = 'http://localhost/media/' MEDIA_ROOT = '/Users/hanqunfeng/python_workspace/MEDIA/'
apache配置:
1 2 3 4 5 6 7 8 9 10 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>
使用如下命令可以将本地的静态资源部署到apache服务目录:
1 python manage.py collectstatic
模板页面:
1 2 3 {% load static %} <link rel ="stylesheet" type ="text/css" href ="{% static 'polls/style.css' %}" />
上传文件:
model中:
1 photo = models.ImageField(upload_to="photo" , default="default/django.jpeg" )
之后要注意更新数据库。
需要安装Pillow,否则会报错
1 2 3 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".
如果要在页面中使用settings中的变量,需要在当前应用中创建一个context_processors.py 文件
1 2 3 4 5 from django.conf import settings def settings_constant (request ): return {'MEDIA_URL' : settings.MEDIA_URL, 'DEBUG' : settings.DEBUG}
并在settings文件配置如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 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' , ], }, }, ]
模板页面中:
1 2 3 4 5 6 7 8 9 <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处理代码中:
1 2 3 input_img = request.FILES['photo' ] question.photo = input_img question.save()
部署到apache:
下载mod_wsgi:https://github.com/GrahamDumpleton/mod_wsgi/releases
1 2 3 4 5 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配置文件中加入如下配置
1 LoadModule wsgi_module modules/mod_wsgi.so
普通模式:
1 2 WSGIPythonHome /Users/hanqunfeng/python_workspace/DjangoHelloWorld/venv WSGIPythonPath /Users/hanqunfeng/python_workspace/DjangoHelloWorld
或者采用守护进程模式:
1 2 3 WSGIDaemonProcess example.com python-home=/Users/hanqunfeng/python_workspace/DjangoHelloWorld/venv python-path=/Users/hanqunfeng/python_workspace/DjangoHelloWorld WSGIProcessGroup example.com
配置项目访问路径
1 2 3 4 5 6 7 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>
访问地址:http://127.0.0.1/mysite/polls