Django community: RSS
This page, updated regularly, aggregates Community blog posts from the Django community.
-
Creating a custom user model in Django 1.6 - Part 2
Welcome back for the second part of this tutorial about creating a custom user model in Django.Last week, we covered the Model and Manager creation as well as schema migration. For those of you who had previously existing users, this week we'll cover data migration and then we will cover (admin) forms. -
Django 1.6 最佳实践: 服务器和代码安全 (2)
10. 使用django form验证 django form是一个绝佳的验证python dict数据的框架. 大多数时间我们都用它来验证包含POST数据的HTTP request. 但我们也可以更广泛的使用它. 例如我们可以使用它来验证用户上传的csv文件中的数据, 这样就避免了直接将用户输入的数据保存到数据库的危险: import csv import StringIO from django import forms from .model import Purchase, Seller class PurchaseForm(forms.ModelForm): class Meta: model = Purchase def clean_seller(self): seller = self.cleaned_data['seller'] try: Seller.objects.get(name=seller) except Seller.DoesNotExist: msg = "{0} does not exist in purchase #{1}".format(seller, self.cleaned_data[purchase_number]) raise forms.ValidationError(msd) return seller def add_csv_purchases(rows): rows = StringIO.StringIO(rows) records_added = 0 errors = [] for row in csv.DictReader(rows, delimiter=','): form = PurchaseForm(row) if form.is_valid(): form.save() records_added += 1 else: errors.append(form.errors) return records_added, errors 11. 关闭支付信息的Autocomplete 在用户填写支付信息的HTML input项中应当关闭Autocomplete. 这样在兼容该功能的浏览器中, 便不会提示保存这些敏感信息的提示了: from django import forms class SpecialForm(forms.Form): my_secret = forms.CharField(widget=forms.TextInput(attrs={'autocomplete': 'off'})) 12. 谨慎对待用户上传的文件 唯一能保证用户上传的文件被安全的呈现的方式是通过不同的域名呈现这些文件. 这也是为什么安全专家们推荐使用CDN的原因之一, CDN为我们提供了一个储存含有潜在危险的文件的地方. 当我们无法使用CDN时, 我们就需要确保文件保存的目录无法运行该文件.使用django的FileField和ImageField时, 虽然有默认的验证, 但我们最好还是再确认一下用户上传的文件类型与内容是否一致, 我们可以使用python-magic, pillow等来实现这一功能. 13. 不使用ModelForms.Meta.exclude 使用ModelForms时, 使用Meta.fields代替Meta.exclude. 因为这一设置会导致除了我们明确指明的field外, 其他field都能被修改, 为我们留下了安全隐患, 特别是当model中的field有所增加时. 14. 不使用ModelForms.Meta.fields='__all__' 使用ModelForms.Meta.fields='__all__'产生的安全隐患与使用Meta.exclude十分类似. 15. 小心SQL注入 django ORM对SQL有所屏蔽, 但在使用raw SQL时, 则需要我们格外小心. 16. 不要储存信用卡信息 除非你对PCI-DSS安全标准非常了解, 并且有足够的钱, 时间和精力来测试PCI兼容性, 否则不要保存信用卡信息. 我们还推荐使用第三方服务比如支付宝, paypal等方式处理支付功能. 17. 加固django admin 改变默认的django admin地址 使用djangi-admin-honeypot, 自动在/admin/显示一个假的admin登录页面, 并保存登录者的信息. 尽量使用HTTPS 可根据IP地址限制用户访问django admin 小心使用 allow_tag, 当allow_tag=True时, admin中允许显示HTMLtag, 所以要小心 18. 保护好admin docs 如果你开启了admin docs, 最好能像django admin那样保护他们. 19. 检测dajngo站点 定期检查web server的logs和errors, 注意黑客攻击. 20. 定期升级依赖模块 应当定期将依赖模块升级到最新稳定版, 特别是Django自身. 21. 防止clickjacking clickjacking是指黑客制作的网站, 引导用户去点击某一元素, 但用户点击的其实是隐藏在frame或iframe中的其他内容. 比如将购买按钮影藏在"赞"之后, 当用户点击时, 其实是为黑客埋单了. 22. 使用defusedcml 黑客攻击XML库并不是什么新鲜事了, 但不幸的的是Python没有预料到这一点, 并且其他第三方库例如lxml非常容易受到攻击. 幸好, 我们还有defusedxml, 一个专门用于代替python自带的xml库的第三方库. 23. 安全检查列表 可以使用Pony Checkup, 它会自动检查Django站点的安全性. 24. 提供反馈页 允许用户反馈错误也是一个不错的主意, GitHub就有这样一个页面: https://bounty.github.com/submit-a-vulnerability.html 25. 预备措施 你需要准备好一套对策来应对可能出现的问题, 基本的计划如下: 关闭所有东西, … -
Bringing back python memory
Lately I've done work on the memory management of Evennia. Analyzing the memory footprint of a python program is a rather educational thing in general. Python keeps tracks of all objects (from variables to classes and everything in between) via a memory reference. When other objects reference that object it tracks this too.Once nothing references an object, it does not need to be in memory any more - in a more low-level languages this might lead to a memory leak. Python's garbage collector handles this for us though - it goes through all abandoned objects and frees the memory for usage by other things. The garbage collector will however not do its thing as long as some other object (which will not be garbage-collected) still holds a reference to the object. This is what you want - you don't want existing objects to stop working because an object they rely on is suddenly not there.Normally in Django, whenever you retrieve an database model instance, that exists only in memory then and there. If you later retrieve the same object from the database, the model instance you have to work with is most likely a new one. This is okay for … -
Django 1.6 最佳实践: 服务器和代码安全(一)
django自身提供的安全相关的工具, 文档, 核心代码使django一直保持着不错的安全记录. 当然这也需要django的开发人员了解和掌握着这些工具才能做到. 本篇中包含了一些使Django项目更安全的基本信息. 1. 服务器安全 要确保django项目的安全, 首先需要阙波服务器的安全. 服务器的安全涉及的范围太广, 在这里不做深入讨论. 如果你使用的是Ubuntu 12.04, 那可以参考一下这篇文章. 2. 了解Django安全特性 django 1.6自身的安全特性包括: Cross-site scripting (XSS) 保护 Cross-site request forgery (CSRF) 保护 SQL 注入保护 Clickjacking 保护 支持 SSL/HTTPS 和安全 cookies 默认密码储存使用 PBKDF2 算法和 SHA256 hash 自动 HTML escaping 针对 XML bomb 攻击优化的分析器 加强的JSON, YAML, XML 序列化/去序列化工具 大多数Django的安全特性不需要开启即可工作. 但还有一些需要我们加以设置才行. 在我们重点讲一下这些需要设置的安全特性前, 请先阅读django官网的安全专题: https://docs.djangoproject.com/en/1.6/topics/security/. 3. 关闭DEBUG 正式服务器上运行的django项目应当设置DEBUG=False. 这样, 不法分子便无法从debug信息中找到对他们有用的信息. 在设置DEBUG=False后, 一定要正确设置ALLOWED_HOSTS, 避免出现 SuspiciousOperation 错误. 4. 妥善保管Security keys 如果侵入者获得了django的security key, 那么就意味着你将会冒更多的安全风险. API key和其他信息也应当妥善保管, 并不要放入版本管理系统中. 具体的做法可以参见之前的博文, Django 1.6 最佳实践: 如何设置django项目的设置(settings.py)和部署文件(requirements.txt)中的 2. 将关键信息和设置文件分离.. 5. 使用HTTPS 如果有必要, 可以选择使用HTTPS. 但是Static资源还是应该以http传输, 否则用户可能会得到"insecure resources"警告. 如果用户使用http访问, 应该将他们导向https. 我们可以通过设置web server或django middleware完成. 我们偏向于使用web server完成这一设置. 如果想使用middleware的话, 我们推荐 django-sslify 或 django-secure, django-sslify只是将http连接导向https, 而django-secure则能检查项目中的其他安全设置. 当然, 在设置https之前, 你需要从正规的聚到购买SSL证书. 使用安全cookies 你的项目应当能通知浏览器使用安全cookies, 即永远不通过http传输cookies. 在settings.py中: SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True 使用HSTS HSTS全称HTTP Strict Transport Security, 通常是通过web server设置的. 当开启HSTS后, 页面传输时的response会包含一个HTTP头部, 通知HSTS兼容的浏览器网站只接受HTTPS. 然后HSTS兼容的浏览器会重定向HTTP到HTTPS. 如果HTTPS无法连通, 连接则会中断. Strict-Transport_security: max-age=3153600; includeSubDomains 一些设置HSTS的建议: 设置includeSubDomains mode能阻止入侵者利用未加密的次域名的cookies入侵主站. 开始时设置一个小的max-age, 例如3600(一小时). 因为一旦设置好了之后, 你无法重置用户浏览器中的记录. 确定一切都ok之后, 再将max-age设置为3153600(12个月)或63072000(24个月). 6. 使用ALLOWED_HOSTS 在django 1.6中提供了ALLOWED_HOSTS设置, 只允许列出的host和domain传输. 如果没有设置的话, 会出现SuspiciousOperation. 这是django为了避免假HTTP host 头部而设计的. 我们建议不要再ALLOWED_HOSTS中使用通配符. 7. 开启CSRF保护 django自身带有的csrf保护十分好用, 当在开发时没有开启的话, 甚至会给出提示. 我们推荐一直开启该保护, 除非在创建机器访问的API时, 像Django-rest-framework和django-tastypie都提供该功能. 因为每个API请求都必须提供验证信息, 这两个framework不依赖HTTP cookies来验证. 所以在使用这些framework时CSRF保护并不是问题. 在AJAX post数据时也应当使用CSRF保护, 此时你需要设置X-CSRFToken HTTP头部. django官方文档给了我们一段示范代码: https://docs.djangoproject.com/en/1.6/ref/contrib/csrf/#ajax. 也可以参见之前的博文: Django 1.6 最佳实践: 如何在 Django Template 中正确使用 REST API的4. AJAX和CSRF. 8. XSS 攻击 当用户引入有攻击性的JavaScript, 并直接在template中呈现时, 会存在XSS攻击. 万幸的是, django会自动屏蔽<, >, ', "" 和 &. 但我们还是建议: 不使用mark_safe来跳过template默认机制 不要允许用户设置HTML tag attribute (属性) … -
如何让搜索引擎抓取AJAX内容?
原文: http://www.ruanyifeng.com/blog/2013/07/how_to_make_search_engines_find_ajax_content.html 越来越多的网站,开始采用"单页面结构"(Single-page application)。 整个网站只有一张网页,采用Ajax技术,根据用户的输入,加载不同的内容。 这种做法的好处是用户体验好、节省流量,缺点是AJAX内容无法被搜索引擎抓取。举例来说,你有一个网站。 http://example.com 用户通过井号结构的URL,看到不同的内容。 http://example.com#1 http://example.com#2 http://example.com#3 但是,搜索引擎只抓取example.com,不会理会井号,因此也就无法索引内容。 为了解决这个问题,Google提出了"井号+感叹号"的结构。 http://example.com#!1 当Google发现上面这样的URL,就自动抓取另一个网址: http://example.com/?_escaped_fragment_=1 只要你把AJAX内容放在这个网址,Google就会收录。但是问题是,"井号+感叹号"非常难看且烦琐。Twitter曾经采用这种结构,它把 http://twitter.com/ruanyf 改成 http://twitter.com/#!/ruanyf 结果用户抱怨连连,只用了半年就废除了。 那么,有没有什么方法,可以在保持比较直观的URL的同时,还让搜索引擎能够抓取AJAX内容? 我一直以为没有办法做到,直到前两天看到了Discourse创始人之一的Robin Ward的解决方法,不禁拍案叫绝。 Discourse是一个论坛程序,严重依赖Ajax,但是又必须让Google收录内容。它的解决方法就是放弃井号结构,采用 History API。 所谓 History API,指的是不刷新页面的情况下,改变浏览器地址栏显示的URL(准确说,是改变网页的当前状态)。这里有一个例子,你点击上方的按钮,开始播放音乐。然后,再点击下面的链接,看看发生了什么事? 地址栏的URL变了,但是音乐播放没有中断! History API 的详细介绍,超出这篇文章的范围。这里只简单说,它的作用就是在浏览器的History对象中,添加一条记录。 window.history.pushState(state object, title, url); 上面这行命令,可以让地址栏出现新的URL。History对象的pushState方法接受三个参数,新的URL就是第三个参数,前两个参数都可以是null。 window.history.pushState(null, null, newURL); 目前,各大浏览器都支持这个方法:Chrome(26.0+),Firefox(20.0+),IE(10.0+),Safari(5.1+),Opera(12.1+)。 下面就是Robin Ward的方法。 首先,用History API替代井号结构,让每个井号都变成正常路径的URL,这样搜索引擎就会抓取每一个网页。 example.com/1 example.com/2 example.com/3 然后,定义一个JavaScript函数,处理Ajax部分,根据网址抓取内容(假定使用jQuery)。 function anchorClick(link) { var linkSplit = link.split('/').pop(); $.get('api/' + linkSplit, function(data) { $('#content').html(data); }); } 再定义鼠标的click事件。 $('#container').on('click', 'a', function(e) { window.history.pushState(null, null, $(this).attr('href')); anchorClick($(this).attr('href')); e.preventDefault(); }); 还要考虑到用户点击浏览器的"前进 / 后退"按钮。这时会触发History对象的popstate事件。 window.addEventListener('popstate', function(e) { anchorClick(location.pathname); }); 定义完上面三段代码,就能在不刷新页面的情况下,显示正常路径URL和AJAX内容。 最后,设置服务器端。 因为不使用井号结构,每个URL都是一个不同的请求。所以,要求服务器端对所有这些请求,都返回如下结构的网页,防止出现404错误。 <html> <body> <section id='container'></section> <noscript> ... ... </noscript> </body> </html> 仔细看上面这段代码,你会发现有一个noscript标签,这就是奥妙所在。 我们把所有要让搜索引擎收录的内容,都放在noscript标签之中。这样的话,用户依然可以执行AJAX操作,不用刷新页面,但是搜索引擎会收录每个网页的主要内容! -
Using Travis CI for testing Django projects
A couple of weeks months1 ago in my post about using tox with Django projects, I mentioned using Travis CI as well as tox for testing. There’s plenty of documentation out there for Python modules and Django applications, but not so much guidance for testing a complete Django project. I can only speculate that this is because testing projects normally involves more moving parts (e.g., databases) as opposed to applications which are supposed to be self-contained. A good example here is the cookiecutter templates of Daniel Greenfeld – one of the authors of Two Scoops of Django. His djangopackage template contains a .travis.yml file, yet his django[project] template doesn’t. Since many consider these templates best practices, and Two Scoops as a Django “bible”, perhaps I’m wrong to want to use CI on a Django project? Well (naturally) I don’t think I am, so here is how to do it. Travis CI has a whole bunch of services you can use in your tests. The obvious ones are there e.g., PostgreSQL, MySQL, and Memcached. For a more complete system, there’s also Redis, RabbitMQ, and ElasticSearch. Using these you can build a pretty complete set of integration tests using the same components … -
Mail tips to your colleagues
tl;dr summary: mail a colleague if you see something that just might be useful to them. A couple of weeks ago I made a django app way faster. The most important improvement was to use python's build-in datetime.datetime.strptime() to parse dates instead of the iso8601 library. 20 times faster for our use case. Last week, a colleague mailed me a link to https://hack.close.io/posts/ciso8601 with as email subject "you're not the only one that found date parsing to be slow". He just saw the article and mailed it to me. He didn't even read it in detail. To me, it looked quite relevant and I did read it in detail. Wow! A datetime parsing library that promises to be even faster? https://github.com/elasticsales/ciso8601 . Trying it out meant changing 5 lines or so. Wow! Another 6x speed increase compared to strptime()! Good news for our customers. Good news for the django app. All because of a simple quick mail. So... think about your colleagues when you spot something that might be especially useful! It might just be the link that makes their day. -
Django 1.6 最佳实践: 排除瓶颈和加速django项目
本篇中我们介绍一些基本的查找和加速django项目的策略. 1. 先等等 首先我们需要明白, 错误的优化不是什么好事. 如果你的项目只是小到中等规模, 并且加载速度过得去, 那么你完全没有必要进行优化. 如果你项目的用户在持续稳定的增加, 并且达到了一定的数目, 那么请往下看. 2. 加速Query查询 如果一个页面中query数太多, 或一个query得到的数据太大, 都会导致加载速度变慢. 首先你可以看一下Django官网关于数据库优化的文档: https://docs.djangoproject.com/en/1.6/topics/db/optimization/. a. 使用django-debug-toolbar django-debug-toolbar可以找到query的来源, 并且找到: 重复的query 产生大量query的ORM语句 慢query 你对哪些页面载入较慢应该有个大致的了解, 所以你只需要使用django-debug-toolbar打开这些页面, 查看是哪些query拖慢了整体速度. b. 减少query数 一旦找到了哪些页面包含过多的query数后, 我们便可以采取措施减少query数: 在ORM中使用select_related()减少query数: 使用select_related()会自动扩展外键关系, 将外键中的数据提前合并到本次query. 如果使用CBV, django-braces的SelectRelatedMixin达到同样的目地. 但要小心query扩展的过深. 如果同样的query发生多次, 那么将其移到view中, 在使用context将其传到template中. 使用redis等caching, 然后测试. 使用django.utils.functional.cached_property修饰器, 将query结果cache在内存中. c. query提速 获取一个大的query结果同样也会影响速度, 因此我们首先需要: 确保index起到了加速query的作用 理解在部署服务器中index的作用, 分析理解数据库中真正发生了什么 查看ORM生成的raw SQL语句 开启数据库的 slow query logging功能, 并查看慢query发生的频率 使用django-debug-toolbar找到慢query 然后我们便可以: 重写代码, 使query获得更小的片段 重写代码, 使query更好的利用index 使用raw SQL语句代替ORM生成的慢SQL语句 d. ATOMIC_REQUESTS选项 大多数django项目在ATOMIC_REQUESTS=True的状况下运行都没有什么问题. 如果你的瓶颈分析显示数据库transaction导致了延迟, 那么你可以选择将ATOMIC_REQUESTS=False 3. 数据库优化 除了以上提到的query优化外, 你可以更进一步的进行数据库优化, 相信这方面的书或文章已经很多了, 我们不进行深入讨论了. 主要是以下几点: a. 哪些不属于数据库 有两种数据不应该储存在数据库中, 一个是log信息, 另一个则是经常变化的数据. log信息在开发时看似没有什么影响, 但在正式服务器上运行时, 可能会拖慢数据库, 因此我们建议使用Splunk, Loggly这样的第三方服务或使用NoSQL数据库保存这些数据. 经常变换的数据比如django.contrib.sessions, django.contrib.messages等应尽量保存到Memcached, Redis, Riak或其他NoSQL数据库中. b. PostgreSQL 对于postgres, 在正式服务器中一定要保证设置正确. 具体的设置方法可以自行google之. 还可以参考书 "Postgresql 9.0 high performance". c. MySQL MySQL容易安装和运行, 但如何优化需要长时间的经验和理解. 我们推荐书"high performance MySQL". 4. 使用Memcached或Redis进行Query Cache 你可以使用Django自带的caching系统配合Memcached或Redis, 轻松的完成整站cache的配置. 也可以使用Django的Low-level API完成复杂的设置. 重要的是, 你需要确定哪些需要cache, 哪些不需要cache. 你需要考虑, 哪些view/template包含的query最多? 哪些URL被浏览的最多? 被cache的页面何时需要失效处理? 我们也可以使用第三方package: 比如django-cache-machine, johnny-cache等. 5. 最小化HTML, CSS和JavaScript文件 当浏览器呈现网页时, 必须载入HTML, CSS, JavaScript和图片. 所有这些文件都会消耗用户的带宽, 使浏览速度下降. 虽然Django自带了GZipMiddleware和{% spaceless %} template tag, 还有WSGI的 middleware都能帮助我们减小这些文件. 但使用以上方法都会增加Django自身的系统资源占有量, 可能会导致瓶颈. 最好的方式则是将这一操作交给Apache或Nginx这些web server, 比如利用PageSpeed Module. 当然django的第三方package来压缩和最小化CSS和JavaScript文件也是可行的, 常见的插件有django-pipeline, django-compressor, django-htmlmin等. 6. 使用Upstream caching或CDN 使用Varnish等upstream caching也能加快系统的载入速度. 当然我们还可以AWS等云服务部署自己的CDN, 为全球的用户提供快速的图片, 视频, CSS文件和JavaScript的载入. -
Stripe and Starting dj-stripe
Stripe is great, but using a library makes it even better. Dj-stripe is a great django library for working with stripe to get people to subscribe to your service. See how simple it is to start working with dj-stripe.Watch Now... -
Django Extensions 1.3.8
We are happy to release: Django-Extensions Version 1.3.8 This brings the usual tons of fixes and improvements Get it at: https://pypi.python.org/pypi/django-extensions/1.3.8 Changes: Feature: show_urls, add option to specify dense or verbose output format Improvement: better support for django 1.7 migrations Improvement: better support for django's admin docs BugFix: runjob, job_name and app_name was swapped in error message Docs: Update link to chinese docs Python3: unreferenced_files, fix python3 compatibility Python3: pipchecker, fix python3 compatibility -
Release 0.8.0 alpha 2
We just released LFS 0.8.0a2. This is a feature release. Changes Removes double colons from management forms Removes django-tagging from dependencies Information You can find more information and help on following locations: Documentation on PyPI Demo Releases on PyPI Source code on bitbucket.org and github. Google Group lfsproject on Twitter IRC -
File download script
Greetings! If you recall, a while ago we saw how to write a file upload script. File download is also equally important. Let's see how to write a download script now.def download (request): filename = "/foo/bar/%s.%s" % (name, extension) f1 = open (filename, "r") response = HttpResponse (f1, mimetype = "type/extension") response['Content-Disposition'] = "attachment; filename = foo_bar.extension" return responseOk, now let's examine this code:Specify the file nameOpen this file in read modeCreate HttpResponse object with the following parameters: filename, and mimetype.MIME stands for Multipurpose Internet Mail Extension.Here's a list of all MIME types. Find the appropriate one for the extension you want: http://www.sitepoint.com/web-foundations/mime-types-complete-list/The second filename in the last but one line is the name and extension which the downloaded file should have. For example, your file may be .py, but you might want to make it download as .txtFinally, return the HttpResponse object, and et voila! You have your file ready for download.Note: As usual, this download will be triggered when the URL that points to the function download in the particular view is accessed.Cheers! -
Django 1.6 最佳实践: 如何正确撰写说明文档
之前已经提过, 说明文档对于任何项目都很重要. 有了reStructuredText和Sphinx后, 你可能会迫不及待地为你的项目撰写文档. 1. 使用reStructuredText RST文档可能是现在最流行的文档修饰语言了. reStructuredText便采用RST格式为项目撰写文档. Django和Python的文档都是使用reStructuredText撰写的. 以下是如何使用reStructuredText的简单例子: 段落标题 ==== 次标题 ---- **强调 (粗体)** *斜体* 简单连接: http://www.weiguda.com #) 计数列表项1 #) 计数列表项2 * 不计数列表项1 * 不计数列表项2 代码:: def like(): print("I like ice cream.") 2. 使用Sphinx Sphinx是一个从.rst文件生成HTML, LaTeX等格式的文件的工具. 具体用法见http://sphinx-doc.org/. 我们建议定期使用Sphinx更新文档, 以免错误产生. 3. 其他文档 之前我们讲过在项目根目录下放置requirements.txt文档, 用于储存项目依赖的第三方package信息. 还应当包含以下文件: 文件或目录存在理由说明 README.rst 每个Python项目都应当有 最少提供一句介绍项目目的的语句. 并能给出连接到安装说明的链接. docs/ 项目说明文档应放入其中, 这是Python社区的通用做法 docs/deployment.rst 让你节约一天时间来部署 如何部署项目的说明 docs/installation.rst 方便新开发者或使用新环境使用者开始 如何安装项目的说明 docs/architecture.rst 方便开发人员理解项目的构架, 和随着时间项目构架的变化 -
Release 0.8.0 alpha 1
We just released LFS 0.8.0. This is a feature release. Changes Added pluggable criteria Added pluggable addresses Added criteria for customer taxes Factored out PayPal to lfs-paypal. Added support for Celery (for mailing) Using South standard features for migration See README.txt for more changes. Information You can find more information and help on following locations: Documentation on PyPI Demo Releases on PyPI Source code on bitbucket.org and github. Google Group lfsproject on Twitter IRC -
Django 1.6 最佳实践: 如何正确进行 Unit Tests
为什么我们要写Unit test? 因为随着代码量的增加, 开发人员会忘记, 因此需要Unit test帮助我们保证程序的可靠性. 尤其是我们的程序涉及到医疗信息, 关乎生命安全, 或关乎其他人的资金. 1. test文件准备 当我们使用manage.py startapp创建新的Django app时, django会为我们创建test.py. 我们需要做的第一步是删除该文件, 然后建立test_models.py, test_forms.py, test_views.py文件: myapp/ __init__.py admin.py forms.py models.py test_forms.py test_models.py test_views.py views.py 如果项目中出现其他代码文件, 则建立相应的test文件. 这样做的原因是使测试文件扁平化, 方便我们更容易浏览和修改. 注意, 则是文件必须以"test_"开头, 否则django无法发现这些测试文件. 2. 如何写 Unit Tests a. 每个method只测试一项 每个test method应当尽量减少其测试的范围, 不要尝试在一个method中测试多个views, models, forms. 当然, 这里也会出现难题, 因为通常一个view会涉及到models, forms, 其他methods和functions. 此时我们就最简化我们的环境: # 测试 REST Api # test_api.py import json from django.core.urlresolvers import reverse from django.test import TestCase from myapp.models import Article class ArticleTests(TestCase): def setUp(self): Article.objects.get_or_create(title="A title", slug="a-slug") def test_list(self): url = reverse("article_object_api") response = self.client.get(url) self.assertEquals(response.status_code, 200) data = json.loads(response.content) self.assertEquals(len(data), 1) 以上代码中, 我们使用setUp method, 最简化了我们需要的model. 以下是一个更为完整的例子, 测试使用django_rest_framework构建的REST API: # test_api.py import json from django.core.urlresolvers import reverse from django.test import TestCase from django.utils.http import urlencode from myapp.models import Article class ArticleTests(TestCase): def setUp(self): Article.objects.get_or_create(title="title1", slug="slug1") Article.objects.get_or_create(title="title2", slug="slug2") self.create_read_url = reverse("article_rest_api") self.read_update_delete_url = reverse("article_rest_api", kwargs={"slug": "slug1"}) def test_list(self): response = self.client.get(self.create_read_url) # content中, 两个title是否都有? self.assertContains(response, "title1") self.assertContains(response, "title2") def test_detail(self): response = self.client.get(self.read_update_delete_url) data = json.loads(response.content) content = {"id": 1, "title": "title1", "slug": "slug1"} self.assertEquals(data, content) def test_create(self): post = {"title": "title3", "slug": "slug3"} response = self.client.post(self.create_read_url, post) data = json.loads(response.content) self.assertEquals(response.status_code, 201) content = {"id": "3", "title": "title3", "slug": "slug3"} self.assertEquals(data, content) self.assertEquals(Article.objects.count(), 3) def test_delete(self): response = … -
Translated text images for lazy programmers
In a previous post about django translations in this blog, I shared how to achieve a quick system that allowed me to manage translations stored in models and served using a template tag. In this post I will explain how to serve images that contain translated text and, hence, a localized image exists for each language.In my case, images are referenced from <img> HTML tags in templates and from CSS files. First of all we must create a basic structure in our img/ and css/ media folders, creating inside a directory for each language code we will use. For example, if we have two languages -- english and spanish -- we would create img/en/, img/es/, css/en/ and css/es/. In the CSS folders, the same files must be initially copied. If we have, for instance, just one style.css file, it must be both in css/en/style.css and css/es/style.css: css/ en/ style.css es/ style.css For the images, we should create the images that will be translated into each language code folder. All CSS files will reference the non-translated images in the same way, but their own file path to the translated image. I'll give an example. Let's say we have one background image … -
From LIKE to Full-Text Search (part I)
What do you do when you need to filter a long list of records for your users? We love and use Django so, most of the time, it is just as simple as: >>> Entry.objects.filter(title='Man bites dog') Well, actually that's not very useful. If you don't provide a lookup type it is assumed to be exact, which is not that user friendly. That query would miss 'Man Bites Dog' or "Man Bites Dog's Tail" and many more. That's why one of the most used field lookups is icontains which roughly translates to this SQL1: SELECT ... WHERE title ILIKE '%Man bites dog%'; That is much better. It works most of the time and you get to keep your comfy ORM. But what if you are looking for an Entry titled 'Man Bites Dogs Tails'? You would still miss it! And what about looking up the Entry's body too? Enter PostgreSQL's Full Text Search. Rather than using regular expressions to tackle this problem, we can use the full text search facilities that PostgreSQL offers. From the manual's introduction: Textual search operators have existed in databases for years. PostgreSQL has ~, ~*, LIKE, and ILIKE operators for textual data types, but they … -
Creating a custom user model in Django 1.6 - Part 1
Welcome back to our Django tutorial series. Before Django 1.5 customizing the user model was a bit of a hack as it involved creating a user profile with a one-to-one relationship to the user. All that changed in 1.5. In this tutorial we are goin to see how to substitue Django's default user model with our own and allow the use of a user's e-mail instead of it's username during the login process. Since 1.7 is not officially stable yet, this tutorial is meant for Django 1.6 but should also work with 1.7 (except for the South part which will be replaced in 1.7 by Django's own schema migration mechanism) -
如何开发合格的 Python/Django 第三方 Package
何为合格的Python/Django第三方package, 以下是一个为发布新的Python/Django package准备的Checklist. 1. 目的 你的package应当能做一件事情, 并且能把它做得很好. package名字应当具有描述性. package仓库的根目录应当以"django-"开头(如果是Django的package的话), 方便其他用户查找. 如果该package的部分功能需要借助其他Python package完成, 那么应当将其他package加入到依赖信息中. 2. 范围 你的package功能范围应该专注于一个小的任务(就像UNIX的原则一样), 这意味着该package的逻辑紧凑, 用户也更容易修改或取代这一package. 3. 文档 没有文档的package只能说是测试package, Docstring无法代替说明文档. 我们可以借助ReStructuredText和Sphinx这样优秀的工具撰写文档. 这些文档应到放在https://readthedocs.org上, 并使用webhooks来随时更新. package的依赖, 安装说明,都应当纳入文档中. 4. 测试 你的package应当包含测试代码. 测试代码能提高可靠性, 更能方便其他贡献者提交代码. 如果有必要, 应当将如何运行测试纳入文档中. 如果你和你的贡献者们能在提交pull request运行测试, 那必定会带来更高质量的代码. 5. 维护 你的package应当定期维护更新. 每次更新代码库中的代码时, 如果有必要, 不要忘了上传到Python Package Index中. 6. 社区 良好的package一般都会得到社区的贡献者帮助提交的代码和补丁, 所有贡献者的名单应当列在CONTRIBUTORS或AUTHORS文档中. 尽力管理由你领导的package产生的社区. 如果你的代码被fork了, 应当尽力给与关注, 试着将部分内容merge到你的package中. 如果该fork与原来的package功能上已有分化, 则应提醒该fork开发人员重新命名该fork. 7. 模块化 你的package应当能简单的被应用到任何Django项目中(针对Django package), 并且不会代替其他核心部件(templates, ORM等). 尽量减少对其他package的影响. 8. PyPI 对于 major 和 minor release, 应该将其放置到PyPI, 方便其他开发人员下载获得源代码. 对各release使用适当的版本号. 9. 依赖 package中所依赖的其他package应当使用宽松版本号写入requirements中, 而不是用绝对版本号: # requirements # 不使用 Django==1.5.2, 而是用 Django>=1.5,=1.2.3, 10. 版本号 对于Python/Django package, 可以参考PEP 386对package进行版本编号, 形式如A.B.C: A代表着major release, B代表minor relsean, C代表bugfix release. 11. 名字 package的名字至关重要. 恰当的命名使得package容易被发现. 12. 使用协议 License 每个package都应当有合适的License, 对于没有特殊的package可以使用BSD或MIT license, 这两个license允许大多数商用和非商用. 将License的内容拷贝黏贴到LICENSE文档中. 13. 代码 你的package中的代码应当清晰易懂, 不要使用奇怪的python语法. 14. URL Namespaces 对于Django package, 为了避免与其他package的url设置重提, 可以使用的URL namespaces. -
The SaaS methodology
Hey guys! This one's not a tutorial. So just sit back with a cup of coffee and relax. I assure you this is going to be fun.Up until now we've seen two names associated with programming in Django. The first one is Web Design, which is very mundane. Any Tom, Dick and Harry can visit a CMS like Wordpress nowadays and make a website for themselves.Then we saw the slightly more colorful and yet highly misunderstood name Web Application Design, or simply Web App Design.I'm finally going to tell you a name that is not only prestigious, but one that will blow your mind whole. It's SaaS, or Software as a Service.I'll give you a minute to let the awesomeness sink in.Done?Good.Yes, Django programming falls under software. People think that software only means the ones we open on our computers.The Service in SaaS is not service as in social service. It means the service you provide to computers.SaaS pieces are hosted on servers and can be accessed from anywhere with an Internet connection. They may be free or charged. The charged ones are called Proprietary Software. Also note that the free ones are not called Open Source. That's completely different. … -
An important thing
Hey guys! This is an important one. This had me stymied for a day and a half. Do not forget to commit the changes before closing the connection in the particular view if that view contains any of insert, update or delete queries. It doesn't matter with select queries, but for the aforementioned it is a must. -
A Trekking Expedition through the Chandrakhani Pass Part 2
This post is the continuation of the Part 1 of the experience. To read Part 1 please click here. Day 5- Behali(8300 ft) to Waching(9300 ft) This was probably the easiest stretch of the trek. We had an estimated time of 3 hours to cover about 5 kms. We had a couple of problems before starting off from Behali. Firstly, one of the participant Ananth had his shoe sole come off. In spite of inquiring around, we couldn’t find an extra pair of shoes for him. So, he just performed a temporary hack by using some glue and rope. The second issue was another participant Prateek fell ill and had high fever. He consumed a lot of paracetamol to help him trek for the remaining journey. After we left Behali, we got to see some glacial left overs on the way. This was our first encounter with ice. After trekking for about two hours upwards, we reached a flat land where we halted for lunch. We were running well ahead of schedule and hence, decided to take a break of atleast 2.5 hours. One particular sport unites everyone in India. And that is the game of cricket. We managed to … -
Magnificent Meetup for Bangalore Django Users!
"Krace played a key role in bringing back the almost dead Bangalore Python Users Group into action."- Shreyansh Singhal on YourStory.Few weeks back, while I was searching for Python I came across Krace's blog. Then I checked his Github, Stackoverflow, Quora profiles and I was amazed.Last week when I found there was a Django users workshop by him & his friends, without a second thought I decided to go.Since the organizers marked the location (ThoughtWorks Technologies) on Google Maps, its quite easy to reach there w/o any trouble.Workshop took place from 10 A.M. to 5 P.M. The goal was to build a simple phone book app to add/view/edit contacts with Django & SQLite.Before starting of workshop, organizers helped with installation of requirements(Django & South).Krace showed the agenda. At each & every step, he first explained what he is going to do. Then he would do it and gives us time to complete the task. All organizers patiently helped in troubleshooting the errors at each and every step. In the end we had little Q & A session.Overall it was a great hands on experience with great content & crew! Looking forward for more meetups!! Thank You very much!!!If you are form Bangalore & love Python, don't … -
Django的秘密武器: 第三方模块/插件
Django真正的强大之处不在于他是一个web framework, 而在于开源社区提供的庞大的持续增长的第三方模块. 这些模块是由来自不同领域的的程序员创建的, 因此能大大减少你的工作量. 大多数的Django项目都由类似或相同的模块经过不同组合而成, 因此大多数的Django开发时关于将已存在的第三方模块整合到一起. 如果你想尝试自己一个一个的创建出这些模块, 那你可得相当努力才行了. 接下来, 我们介绍以下渠道来获取第三方模块: 1. PyPI PyPI是Python Package Index的简称, 其官方网址是https://pypi.python.org/pypi. 截止2014年初, 已有37,000个django相关的第三方模块. 对于大多数的Python社区而言, 只有在PyPI上发布了的项目才算做正式发布. PyPI不光是一个模块目录, 它更是世界上最大的python模块信息中心. 每次你使用pip安装python模块时, pip便会从PyPI上下载相应的模块. (如果你在中国大陆, 你可能需要使用阿里云或豆瓣的PyPI镜像网站) 2. DjangoPackages.com Django Package是一个可重复利用的app和工具的目录. 不像PyPI, django package不会储存模块本身, 而是提供了相似模块的比较表格, 方便用户比对查找需要的模块. 3. 不要重复自己 作为一个Python开发人员, 我们应当了解这些工具, 否则就是白白浪费了这些已存在的资源. 更为重要的是, 我们不应当重复发明轮子(don't reinvent the wheel). 那些最好的第三方模块都是由世界上最具竞争力的开发人员, 花费大量时间创造, 撰写文档, 经过全面测试而来的. 站在这些人的肩膀上可以学到更多的东西. 但是, 如何识别好的第三方模块也是十分重要的! 花时间去了解, 测试那些第三方模块是一件值得我们做的事情. -
Django 1.6 最佳实践: 如何正确使用 User Model
本篇主要讨论一下User Model的使用技巧. 注意, 由于Django 1.5之后user model带来了很大的变化, 本篇内容只针对django 1.5之后的版本. 1. 确定 User Model 我们推荐一下方式来确定某一django项目使用的user model: # 使用默认User model时 >>> from django.contrib.auth import get_user_model >>> get_user_model() <class 'django.contrib.auth.models.User'> # 使用自定义User model时 >>> from django.contrib.auth import get_user_model >>> get_user_model() <class 'xxx.models.UserProfile'> 2. 使用settings.AUTH_USER_MODEL 自从django 1.5之后, 用户可以自定义User model了, 如果需要外键使用user model, 官方推荐的方法如下: 在settings中设置AUTH_USER_MODEL: # settings.py # 格式为 "<django_app名>.<model名>" AUTH_USER_MODEL = "myapp.NewUser" 在models.py中使用 # models.py from django.conf import settings from django.db import models class Article(models.Model): author = models.ForeignKey(settings.AUTH_USER_MODEL) title = models.CharField(max_length=255) 还有需要注意的是, 不要在外键中使用get_user_model(). 3. 自定义 User Model 方法1: 扩展 AbstractUser类 如果你对django自带的User model刚到满意, 又希望额外的field的话, 你可以扩展AbstractUser类: # myapp/models.py from django.contrib.auth.models import AbstractUser from django.db import models class NewUser(AbstractUser): new_field = models.CharField(max_length=100) 不要忘了在settings.py中设置: AUTH_USER_MODEL = "myapp.NewUser" 方法2: 扩展 AbstractBaseUser类 AbstractBaseUser中只含有3个field: password, last_login和is_active. 如果你对django user model默认的first_name, last_name不满意, 或者只想保留默认的密码储存方式, 则可以选择这一方式. 方法3: 使用OneToOneField 如果你想建立一个第三方模块发布在PyPi上, 这一模块需要根据用户储存每个用户的额外信息. 或者我们的django项目中希望不同的用户拥有不同的field, 有些用户则需要不同field的组合, 且我们使用了方法1或方法2: # profiles/models.py from django.conf import settings from django.db import models from flavors.models import Flavor class EasterProfile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL) favorite_ice_cream = models.ForeignKey(Flavor, null=True, blank=True) class ScooperProfile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL) scoops_scooped = models.IntergerField(default=0) class InventorProfile(models.Model): user = models.OneToOneField(settings.AUTH_USER_MODEL) flavors_invented = models.ManyToManyField(Flavor, null=True, blank=True) 使用以上方法, 我们可以使用user.easterprofile.favorite_ice_cream获取相应的profile. 使用这一方法的坏处可能就是增加了代码的复杂性.