django性能分析

发布在 Django

一般情况我们使用django-debug-toolbar就能够看到每个步骤的耗时等信息,不过如果需要调试某个接口就不那么直观了,这种情况下我们可以使用下面的中间件来解决问题:

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
72
73
74
75
76
77
78
79
80
81
82
83
84
85
# Orignal version taken from http://www.djangosnippets.org/snippets/186/
# Original author: udfalkso
# Modified by: Shwagroo Team and Gun.io
import sys
import os
import re
import hotshot, hotshot.stats
import tempfile
import StringIO
from django.conf import settings
words_re = re.compile( r'\s+' )
group_prefix_re = [
re.compile( "^.*/django/[^/]+" ),
re.compile( "^(.*)/[^/]+$" ), # extract module path
re.compile( ".*" ), # catch strange entries
]
class ProfileMiddleware(object):
"""
Displays hotshot profiling for any view.
http://yoursite.com/yourview/?prof
Add the "prof" key to query string by appending ?prof (or &prof=)
and you'll see the profiling results in your browser.
It's set up to only be available in django's debug mode, is available for superuser otherwise,
but you really shouldn't add this middleware to any production configuration.
WARNING: It uses hotshot profiler which is not thread safe.
"""
def process_request(self, request):
if (settings.DEBUG or request.user.is_superuser) and 'prof' in request.GET:
self.tmpfile = tempfile.mktemp()
self.prof = hotshot.Profile(self.tmpfile)
def process_view(self, request, callback, callback_args, callback_kwargs):
if (settings.DEBUG or request.user.is_superuser) and 'prof' in request.GET:
return self.prof.runcall(callback, request, *callback_args, **callback_kwargs)
def get_group(self, file):
for g in group_prefix_re:
name = g.findall( file )
if name:
return name[0]
def get_summary(self, results_dict, sum):
list = [ (item[1], item[0]) for item in results_dict.items() ]
list.sort( reverse = True )
list = list[:40]
res = " tottime\n"
for item in list:
res += "%4.1f%% %7.3f %s\n" % ( 100*item[0]/sum if sum else 0, item[0], item[1] )
return res
def summary_for_files(self, stats_str):
stats_str = stats_str.split("\n")[5:]
mystats = {}
mygroups = {}
sum = 0
for s in stats_str:
fields = words_re.split(s);
if len(fields) == 7:
time = float(fields[2])
sum += time
file = fields[6].split(":")[0]
if not file in mystats:
mystats[file] = 0
mystats[file] += time
group = self.get_group(file)
if not group in mygroups:
mygroups[ group ] = 0
mygroups[ group ] += time
return "<pre>" + \
" ---- By file ----\n\n" + self.get_summary(mystats,sum) + "\n" + \
" ---- By group ---\n\n" + self.get_summary(mygroups,sum) + \
"</pre>"
def process_response(self, request, response):
if (settings.DEBUG or request.user.is_superuser) and 'prof' in request.GET:
self.prof.close()
out = StringIO.StringIO()
old_stdout = sys.stdout
sys.stdout = out
stats = hotshot.stats.load(self.tmpfile)
stats.sort_stats('time', 'calls')
stats.print_stats()
sys.stdout = old_stdout
stats_str = out.getvalue()
if response and response.content and stats_str:
response.content = "<pre>" + stats_str + "</pre>"
response.content = "\n".join(response.content.split("\n")[:40])
response.content += self.summary_for_files(stats_str)
os.unlink(self.tmpfile)
return response

把这个文件保存为middleware.py,然后在settings.py中的MIDDLEWARE_CLASSES添加刚才写好的中间件
'yourproject.yourapp.middleware.ProfileMiddleware',
添加完成后,在原本要访问的url后添加’?prof’就可以看到性能分析结果了:

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
<pre>         202188 function calls (182154 primitive calls) in 2.948 seconds
Ordered by: internal time, call count
ncalls tottime percall cumtime percall filename:lineno(function)
302 2.444 0.008 2.454 0.008 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/MySQLdb/cursors.py:277(_do_query)
2 0.086 0.043 0.104 0.052 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/MySQLdb/connections.py:62(__init__)
2 0.017 0.009 0.017 0.009 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/MySQLdb/connections.py:287(set_character_set)
2 0.016 0.008 0.016 0.008 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/backends/mysql/base.py:299(_set_autocommit)
302 0.008 0.000 2.488 0.008 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/backends/utils.py:76(execute)
19410 0.008 0.000 0.008 0.000 /usr/lib64/python2.7/copy.py:267(_keep_alive)
10237 0.008 0.000 0.008 0.000 /usr/lib64/python2.7/json/encoder.py:33(encode_basestring)
600 0.008 0.000 0.012 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/sql/query.py:246(clone)
6 0.007 0.001 0.007 0.001 /usr/lib64/python2.7/urlparse.py:336(unquote)
500 0.007 0.000 2.712 0.005 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/query.py:229(iterator)
1152 0.005 0.000 0.029 0.000 /usr/lib64/python2.7/copy.py:253(_deepcopy_dict)
1 0.005 0.005 0.014 0.014 /usr/lib64/python2.7/json/encoder.py:212(iterencode)
302 0.005 0.000 0.010 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/MySQLdb/cursors.py:117(_do_get_result)
300 0.005 0.000 0.121 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/sql/compiler.py:351(as_sql)
300 0.004 0.000 0.033 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/sql/query.py:1114(build_filter)
302 0.004 0.000 0.004 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/MySQLdb/cursors.py:313(_get_result)
1 0.003 0.003 0.017 0.017 /usr/lib64/python2.7/json/encoder.py:186(encode)
1300 0.003 0.000 0.004 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/backends/mysql/operations.py:176(get_db_converters)
600 0.003 0.000 0.006 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/sql/query.py:1334(names_to_path)
300 0.003 0.000 0.004 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/sql/query.py:110(__init__)
302 0.003 0.000 0.003 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/MySQLdb/cursors.py:82(_warning_check)
200 0.003 0.000 0.004 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/base.py:388(__init__)
302 0.003 0.000 2.469 0.008 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/MySQLdb/cursors.py:139(execute)
300 0.003 0.000 0.022 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/sql/compiler.py:155(get_select)
300 0.003 0.000 0.007 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/sql/compiler.py:472(get_default_columns)
908 0.003 0.000 0.003 0.000 /home/xsy/.virtualenvs/calc/lib64/python2.7/encodings/utf_8.py:15(decode)
3500 0.003 0.000 0.005 0.000 /home/xsy/.virtualenvs/calc/lib/python2.7/site-packages/django/db/models/sql/compiler.py:325(quote_name_unless_alias)
<pre> ---- By file ----

简单解释下主要的信息,ncalls是函数调用的次数,percall指调用一次所需时间,cumtime是运行时占用的总时间。比如percall时间很短而cumtime时间很长,则代表循环次数过多了,试着从算法角度进行优化;如果从输出中看到大量时间消耗和“sql”有关的,则试着从数据库相关代码优化;如果看见大量时间消耗和”template”有关,则尝试从模板渲染处着手优化。

评论和分享

django-userena使用记录

发布在 Django

django-userena扩展了django原生的用户系统,提供了注册、登录、修改密码、邮件验证等一系列常用功能。直接使用pip安装即可:pip install django-userena

会自动安装其所需的依赖包,不过个人建议为了更好的定制模板或相关功能,把这个包放到项目目录下当作一个app更方便一些。安装完成后修改settings.py,首先来创建一个app用于扩展用户系统
python manage.py startapp accounts
然后修改Models.py来扩展原生用户字段,我这里以添加用户等级为例:

1
2
3
4
5
6
7
8
9
10
11
# coding=utf-8
from django.db import models
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from userena.models import UserenaBaseProfile
class CustomerProfile(UserenaBaseProfile):
user = models.OneToOneField(User,
unique=True,
verbose_name=_('user'),
related_name='customer_profile')
level = models.IntegerField(_(u"用户等级"), default=0)

接下来修改settings.py,首先把

1
2
3
4
5
"django.contrib.sites",
"accounts",
'userena',
'guardian',
'easy_thumbnails'

添加到INSTALLED_APPS中,然后把'django.contrib.sites.middleware.CurrentSiteMiddleware',
添加到MIDDLEWARE_CLASSES中,在django1.7.7中如果不添加和site有关的东西时,userena注册用户会抛出”Site matching query does not exist“异常。最后添加下面的配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
AUTHENTICATION_BACKENDS = (
'userena.backends.UserenaAuthenticationBackend',
'guardian.backends.ObjectPermissionBackend',
'django.contrib.auth.backends.ModelBackend',
)
EMAIL_HOST = 'xxxx'
EMAIL_HOST_USER = 'xxxx@xxxx'
EMAIL_HOST_PASSWORD = 'xxxx'
EMAIL_PORT = 25
DEFAULT_FROM_EMAIL = 'xxxx@xxxx'
ANONYMOUS_USER_ID = -1
AUTH_PROFILE_MODULE = 'accounts.CustomerProfile'
USERENA_SIGNIN_REDIRECT_URL = '/accounts/%(username)s/'
LOGIN_URL = '/accounts/signin/'
LOGOUT_URL = '/accounts/signout/'

xxxx根据实际情况修改,和发送验证邮件有关。这些都添加完毕后,执行
./manage.py migrate
创建数据库,接下来执行
./manage.py check_permissions
否则报错”Permission matching query does not exist“。最后记得添加url

1
url(r'^accounts/', include('userena.urls')),

都完成后,运行程序,访问http://127.0.0.1:8000/accounts/signup/就可以看见注册页面了。

所有html文件以及email模板都在userena/templates/userena路径下,进行相应定制即可。

评论和分享

最近有个需求就是当执行save时需要把数据写入2个数据库,查看文档后发现直接重写save方法比较简单。

首先建立2个测试数据库testa和testb,然后在settings中配置数据库:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'testa',
'USER': 'root',
'PASSWORD': 'asdasd',
'HOST': '192.168.0.17',
},
'testdb': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'testb',
'USER': 'root',
'PASSWORD': 'asdasd',
'HOST': '192.168.0.18',
},
}

接下来定义model:

1
2
3
4
5
6
7
8
9
10
11
from django.db import models
# Create your models here.
class ABCD(models.Model):
name = models.CharField(max_length=200, unique=False)
def __unicode__(self):
return "%s" % (self.name)
def save(self, *args, **kwargs):
print "save testa"
super(ABCD, self).save(*args, **kwargs)
print "save testb"
super(ABCD, self).save(using="testdb", *args, **kwargs)

注意最后一行的using指定了写入哪个库中,接下来执行syncdb命令创建表,这里只会在default中创建,所以我们手动在testdb中创建表。

然后进入shell中测试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
% python manage.py shell
Python 2.7.8 (default, Nov 10 2014, 08:19:18)
Type "copyright", "credits" or "license" for more information.
IPython 2.3.0 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object', use 'object??' for extra details.
In [1]: from abcd.models import ABCD
In [2]: c = ABCD(name="testc")
In [3]: c.save()
save testa
save testb

再看数据库中,插入都成功了。这里可能产生的问题就是大量并发请求时造成主键的不一致,但对于写操作不频繁的情况下也是一种可以接受的选择。

评论和分享

回来半个月,终于抽出时间写点东西了。最近这天气真是让人不开心阿~不过昨天居然见到了彩虹,突然想起来在飞机上看见的彩虹是直立在太阳两边而不是桥形的,各有各的美感。

至于在win下如何安装python、setuptools、pip等网上很多这里不再重复,可是那些大小姐们向我反映说她们不会“运行cmd,输入python manage.py runserver”。正所谓收人钱财替人消灾,干脆写个批处理让她们双击运行算了,内容如下:

1
2
3
@echo off
python %cd%\manage.py runserver
pause

真是被微软“惯坏了”的孩子们阿….

评论和分享

django自带的评论模块

发布在 Django

某个设计本来采用了一个比较不错的在线评论模块,不过答辩的时候丫居然不给网!!想偷个懒还是挺难啊….

那就用自带的评论模块吧,django版本是1.5.3。

首先把'django.contrib.comments'添加到INSTALLED_APPS中,然后添加url:

1
2
3
4
5
urlpatterns = patterns('',
......
url(r'^comments/', include('django.contrib.comments.urls')),
......
)

在需要显示评论的HTML中:

1
2
3
{% load comments %}
{% render_comment_list for post %} <!--显示所有属于这个文章的评论-->
{% render_comment_form for post %} <!--显示自带的添加评论的form-->

不过自带的添加评论实在太丑了,我们可以自己改造一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{% get_comment_form for post as form %}
<form action='{%comment_form_target%}' method='post'>
{% csrf_token %}
{{form.object_pk}}
{{form.content_type}}
{{form.timestamp}}
{{form.security_hash}}
<p><label for="id_name">姓名(必填):</label><input name="name" id="id_name"></p>
<p><label for="id_email">邮箱(必填):</label><input name="email" id="id_email"></p>
<p><label for="id_url">网站(可选):</label><input name="url" id="id_url"></p>
<p><label for="id_comment">评论(必填):</label></p>
<p><textarea id="id_comment" rows="10" cols="40" name="comment"></textarea></p>
<p style="display:none;"><label for="id_honeypot">垃圾评论。</label>
<input type="text" name="honeypot" id="id_honeypot"></p>
<p><input name="post" value="发表" type="submit" /></p>
<input type='hidden' name='next' value="/blog/post/{{post.id}}"/> <!--这个是提交后的重定向,使用软编码总报错...-->
</form>

然后再进行CSS或者JS一类的特效美化就OK了。

评论和分享

自己封装了一个logging在django中使用,结果发现输出的时候总是重复输出,比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
DEBUG---- 2014/03/31 10:38:13:
!!
DEBUG---- 2014/03/31 10:38:13:
!!
DEBUG---- 2014/03/31 10:38:13:
!!
DEBUG---- 2014/03/31 10:38:13:
!!
DEBUG---- 2014/03/31 10:38:13:
140091903388560
DEBUG---- 2014/03/31 10:38:13:
140091903388560
DEBUG---- 2014/03/31 10:38:13:
140091903388560
DEBUG---- 2014/03/31 10:38:13:
140091903388560

可以看出,id都是一样的。而且我查了一下,正好4个地方引入了mylog。mylog的完整代码见以前日志,这里给出导致错误的原因:
self.logger = logging.getLogger(__name__)

简单测试:

1
2
3
4
5
6
mlog = MyLog()
print id(mlog)
print id(mlog.logger)
xmlog = MyLog()
print id(xmlog)
print id(xmlog.logger)

结果如下:

1
2
3
4
123456666
123456789
123457777
123456789

可以看出虽然类id不同,不过核心的logger却是一个。因为我们执行runserver后,__name__就确定为mylog了,所以不管我们引用的时候如何写,__name__不变则都指向了同一个logger。更简单的例子如下:

1
2
3
4
5
6
In [1]: x = 1
In [2]: y = 1
In [3]: id(x)
Out[3]: 11279464
In [4]: id(y)
Out[4]: 11279464

更细节的原因可以看《python源码分析》。

改起来就让__name__不一样就解决了。比如:

self.logger = logging.getLogger(str(uuid.uuid4()))

评论和分享

第一种HttpResponse,最基本的返回方式,可以直接返回字符:

1
2
3
from django.http import HttpResponse
def index(request):
return HttpResponse(“a test”)

或者结合contextloder返回网页:

1
2
3
4
5
6
7
from django.template import Context, loader  
from polls.models import Poll
def index(request):
latest_poll_list = Poll.objects.order_by('-pub_date')[:5]
template = loader.get_template('polls/index.html')
context = Context({ 'latest_poll_list': latest_poll_list, })
return HttpResponse(template.render(context))

阅读全文

django数据库分库

发布在 Django

有些时候我们需要项目中的app访问不同的数据库,这时就要进行分库操作。

首先建立一个db_router.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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#coding=utf-8
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql', # Add 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'xxxx', # Or path to database file if using sqlite3.
'USER': 'root', # Not used with sqlite3.
'PASSWORD': '123456', # Not used with sqlite3.
'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
'PORT': '3306', # Set to empty string for default. Not used with sqlite3.
'OPTIONS': {
'init_command': 'SET storage_engine=MyISAM',
},
},
'analysis_db':{
'ENGINE': 'django.db.backends.mysql',
'NAME': 'analysis_qq', #分析相关的操作用这个库
'HOST': '',
'USER': 'root',
'PASSWORD': '123456',
'PORT':'3306',
'OPTIONS':{
'init_command': 'SET storage_engine=MyISAM',
},
},
}
class MasterSlaveRouter(object):
def db_for_read(self, model, **hints):
if model._meta.app_label == 'analysisqq':
return 'analysis_db'
else:
return 'default'
def db_for_write(self, model, **hints):
if model._meta.app_label == 'analysisqq':
return 'analysis_db'
else:
return 'default'
def allow_relation(self, obj1, obj2, **hints):
db_list = ('default','analysis_db',)
if obj1._state.db in db_list and obj2._state.db in db_list:
return True
return None
def allow_syncdb(self, db, model):
if db == 'analysis_db':
print " in analysis db"
return True
elif db == 'default':
return False
else:
return None
DATABASE_ROUTERS = ['db_router.MasterSlaveRouter']

然后在settings.py中删除和数据库相关的代码,添加from db_router import *,这样之后指定的app就会使用特定的库了。

注意,这里分库是针对于读写操作,以及default已经存在后的syncdb,如果说你想执行syncdb同时就在不同数据库建表,这样操作是无效的。知道怎么做的请告知!

评论和分享

django文件上传功能

发布在 Django

今天需要一个文件上传功能,所以代码如下

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
def ci_test(request):
try:
if request.POST.has_key("send"):
xml_string=""
final_xml = ""
file_obj = request.FILES.get('file', None)
for keys in request.POST:
if request.POST[keys]:
print keys,request.POST[keys]
xml_string = "<%s>%s</%s>n%s" % (keys,request.POST[keys],keys,xml_string)
final_xml = "<root>n%s</root>" % xml_string
dirname = os.path.dirname(os.path.abspath(__file__))
parent = os.path.split(dirname)[0]
if request.POST["source"] == "text" and file_obj:
if file_obj.name.endswith(".txt"):
#print parent
filepath = "%s/core/emaillist.txt" % parent
#print filepath
open(filepath,'w').write(file_obj.read()) #注意这里
else:
raise forms.ValidationError("上传文件类型错误!")
path = "%s/core/config/%s.xml" % (parent,request.POST['txtDate'])
open(path,'w').write(final_xml.encode('utf-8'))
else:
smtp = request.POST['smtp']
username = request.POST['username']
passwd = request.POST['passwd']
title = request.POST['title'] #邮件标题
content = request.POST['content'] #邮件内容
attach = request.POST['useattach'] #是否是附件发送
ctype = request.POST['c_type'] #邮件格式
testsend = request.POST['testsend']#测试邮箱
subtem = u"%s: %s" % (u"测试",title)
conn = creat_conn(smtp, username, passwd)
tem = testsend.split(';')
if ctype.upper() == "HTML":
final_body = creat_htmlbody(content)
#测试发送,不用记录日志直接传列表
final_testmail(subtem,final_body,username,tem,conn,attach)
print "test send to %s sucess!" % tem
else:
final_testmail(subtem,content,username,tem,conn,"test")
print "test send to %s sucess!" % tem
return render(request,'test.html',{"msg":"请求已经提交,关闭本页面即可"})
except forms.ValidationError:
print "in my error"
return render(request,'test.html',{{"msg":"文件类型错误,请重新操作!"}})
except Exception:
return render(request,'test.html',{{"msg":"发生错误,请重新操作!"}})

此处需要注意模版文件中form的写法:

1
2
3
<form action="ci_test" method="post" onsubmit="return validate_form(this);" enctype="multipart/form-data">
<input type="file" name="file"/>
</form>

不过此处有个奇怪的问题,根据流程来看,如果上传的不是.txt文件则引发异常,也确实输出了”in my error”这句话,不过随后就引发了下面的异常,不知道render为什么错误。

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
TypeError at /mailinfo/ci_test
unhashable type: 'dict'
Request Method: POST
Request URL: http://127.0.0.1:8000/mailinfo/ci_test
Django Version: 1.5.3
Exception Type: TypeError
Exception Value:
unhashable type: 'dict'
Exception Location: /home/xingsongyan/workspace/send/mailinfo/views.py in ci_test, line 66
Python Executable: /usr/bin/python2.7
Python Version: 2.7.5
Python Path:
['/home/xingsongyan/workspace/send',
'/usr/lib/python2.7/site-packages/pip-1.4.1-py2.7.egg',
'/home/xingsongyan/workspace/send',
'/usr/share/eclipse/dropins/pydev/eclipse/plugins/org.python.pydev_2.8.2.2013090511/pysrc',
'/usr/lib64/python27.zip',
'/usr/lib64/python2.7',
'/usr/lib64/python2.7/plat-linux2',
'/usr/lib64/python2.7/lib-tk',
'/usr/lib64/python2.7/lib-old',
'/usr/lib64/python2.7/lib-dynload',
'/usr/lib64/python2.7/site-packages',
'/usr/lib64/python2.7/site-packages/gtk-2.0',
'/usr/lib64/python2.7/site-packages/wx-2.8-gtk2-unicode',
'/usr/lib/python2.7/site-packages',
'/usr/lib/python2.7/site-packages/setuptools-0.6c11-py2.7.egg-info',
'/usr/lib64/python2.7/site-packages/PIL']
Server time: Wed, 4 Dec 2013 16:05:25 +0800

评论和分享

django中静态文件的使用

发布在 Django

记得我刚刚开始接触django的时候,对于静态文件的引用始终一头雾水,按照网上说明的添加代码就是不好使。
今天再回头看看,突然发现以前自己还真是笨阿!补一篇记录算是弥补以前的缺憾了~
django版本1.5.3
目录结构:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
projectname
----projectname
--------templates
------------base.html
------------appname
----------------a.html
--------media
------------mp3
------------flv
--------static
------------img
----------------s.jpg
------------css
------------js
--------settings.py
--------urls.py
----manage.py

方式一

setting.py中添加、修改以下代码

1
2
3
4
5
6
7
import os
SITE_ROOT = os.path.dirname(__file__)
STATIC_ROOT=''
STATIC_URL = '/static/'
STATICFILES_DIRS = (
SITE_ROOT+STATIC_URL, #注意逗号!
)

urls.py修改如下

1
2
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
urlpatterns += staticfiles_urlpatterns()

<img name="a" src="/static/img/s.jpg"/>进行引用。

方式二

避开static相关,用media。

settings.py:

1
2
MEDIA_ROOT = os.path.join(os.path.dirname(__file__),'media/').replace('\','/')
MEDIA_URL = '/site_media/'

urls.py:

from django.conf import settings
    url(r'^site_media/(.*)$','django.views.static.serve',
                          {'document_root':settings.MEDIA_ROOT}),

<img name="a" src="/site_media/img/a.png"/>这里的set_media和上面urls.py中的名要对应。

目录结构自行修改。

个人推荐第一种方式。

评论和分享

作者的图片

Roy

君以国士待我,我必以国士报君。


野生程序猿


China