Django community: Community blog posts RSS
This page, updated regularly, aggregates Community blog posts from the Django community.
-
lxml的元素构建器和CDATA对象
lxml有着非常好用的元素构建器, 但对于CDATA对象似乎没这么给力: >>> from lxml.builder import E >>> from lxml.etree import CDATA >>> E.stuff(CDATA('Some stuff that needs to be in a CDATA section')) Traceback (most recent call last): File "<ipython-input-4-40103024e8d8>", line 1, in <module> E.stuff(CDATA('Some stuff that needs to be in a CDATA section')) File "/usr/lib/python2.7/dist-packages/lxml/builder.py", line 220, in __call__ raise TypeError("bad argument type: %r" % item) TypeError: bad argument type: <lxml.etree.CDATA object at 0x238a130> 可以使用以下方式修复: from lxml.builder import ElementMaker from lxml.etree import CDATA def add_cdata(element, cdata): assert not element.text, "Can't add a CDATA section. Element already has some text: %r" % element.text element.text = cdata E = ElementMaker(typemap={ CDATA: add_cdata }) 然后就可以正常使用了: >>> from lxml import etree >>> etree.tostring(E.stuff(CDATA('Some stuff that needs to be in a CDATA section'))) '<stuff><![CDATA[Some stuff that needs to be in a CDATA section]]></stuff>' -
如何在Python中发送邮件
使用python发送邮件有以下几种情况: 纯文本的邮件 带附件的邮件 其他邮件 首先我们使用virtualenv创建环境: $ virtualenv env $ env/bin/pip install wheezy.core 纯文本邮件 直接上代码: # plain.py from wheezy.core.mail import MailMessage from wheezy.core.mail import SMTPClient mail = MailMessage( subject='Welcome to Python', content='Hello World!', from_addr='someone@dev.local', to_addrs=['you@dev.local']) client = SMTPClient() client.send(mail) 然后使用以下命令发送: python plain.py 如果需要发送HTML的邮件的话, 只需要将content换成HTML, 将content_type设置成'text/html', 设置charset即可: from wheezy.core.mail import MailMessage from wheezy.core.mail import SMTPClient content = """\ <html><body> <h1>Hello World!</h1> </body></html>""" mail = MailMessage( subject='Welcome to Python', content=content, content_type='text/html', charset='utf-8', from_addr='someone@dev.local', to_addrs=['you@dev.local']) client = SMTPClient() client.send(mail) 另外, 还可以设置SMTPClient的host, port, tls, credentials等. 带附件的邮件 # attachment.py from wheezy.core.mail import Attachment from wheezy.core.mail import MailMessage from wheezy.core.mail import SMTPClient mail = MailMessage( subject='Welcome to Python', content='Hello World!', from_addr='someone@dev.local', to_addrs=['you@dev.local']) mail.attachments.append(Attachment( name='welcome.txt', content='Hello World!')) client = SMTPClient() client.send(mail) 可以使用factory方法Attachment.from_file从本地文件创建一个附件 其他邮件 我们下载python的logo作为邮件: import os.path from wheezy.core.mail import Alternative from wheezy.core.mail import MailMessage from wheezy.core.mail import Related from wheezy.core.mail import SMTPClient mail = MailMessage( subject='Welcome to Python', content='Hello World!', from_addr='someone@dev.local', to_addrs=['you@dev.local']) alt = Alternative("""\ <html><body> <h1>Hello World!</h1> <p><img src="cid:python-logo.gif" /></p> </body></html>""", content_type='text/html') curdir = os.path.dirname(__file__) path = os.path.join(curdir, 'python-logo.gif') alt.related.append(Related.from_file(path)) mail.alternatives.append(alt) client = SMTPClient() client.send(mail) -
Python Dev Tip: DRY your shell with PYTHONSTARTUP
Python Dev Tip: DRY your shell with PYTHONSTARTUP -
可重复使用的 juju charm: ansible role
我们时常会使用juju charms来自动化部署许多不同的paas, 大多数是wsgi应用. 我们通常使用ansible使juju charms自动化部署更加轻松, 但是每个wsgi charm还是得重复坐以下相同的事情: 设置特定的用户 安装build代码到特定目录 安装依赖包 与后台连接(postesql, elasticsearch等) 生成设置 设置wsgi服务 设置log 支持更新代码而不必升级charm 支持不断地更新代码 其中只有三项是会随着paas不同而存在略微差别的: 依赖包, 生成设置和后台连接. 在尝试创建一个可重复使用的wsgi charm后, 我们借助ansible内置的对可重复利用的roles的支持创建了charm-bootstrap-wsgi, 其中包含了以上所有需求. 其中charm非常简单, 重新是使用wsgi-app的role: roles: - role: wsgi-app listen_port: 8080 wsgi_application: example_wsgi:application code_archive: "{{ build_label }}/example-wsgi-app.tar.bzip2" when: build_label != '' 我们只需要做两件事情: tasks: - name: Install any required packages for your app. apt: pkg={{ item }} state=latest update_cache=yes with_items: - python-django - python-django-celery tags: - install - upgrade-charm - name: Write any custom configuration files debug: msg="You'd write any custom config files here, then notify the 'Restart wsgi' handler." tags: - config-changed # Also any backend relation-changed hooks for databases etc. notify: - Restart wsgi 其他则是由reusable wsgi-app role提供支持. -
From LIKE to Full-Text Search (part II)
If you missed it, read the first post of this series What do you do when you need to filter a long list of records for your users? That was the question we set to answer in a previous post. We saw that, for simple queries, built-in filtering provided by your framework of choice (think Django) is just fine. Most of the time, though, you'll need something more powerful. This is where PostgreSQL's full text search facilities comes in handy. We also saw that just using to_tsvector and to_tsquery functions goes a long way filtering your records. But what about documents that contain accented characters? What can we do to optimize performance? How do we integrate this with Django? Hola, Mundo! We have found that the need to search documents in multiple languages is fairly common. You can query your data using to_tsquery without passing a language configuration name but remember that, under the hood, the text search functions always use one. The default language is english, but you have to use the right language stemmer according to your document language or you might not get any matches. If, for example, we search for física in spanish documents that have … -
Django 和 PostgreSQL, 从 SQL 的 LIKE 到全文搜索(Full-Text-Search) (1)
一般我们是这样从超多记录中过滤出相应的query的: &gt;&gt;&gt; Entry.objects.filter(title__icontains='Man bites dog') 这一语句在PostgreSQL中则被转化为: SELECT ... WHERE title ILIKE '%Man bites dog%'; 但对于"Man Bites Dogs Tails"这样的记录还是无法过滤出. PostgreSQL的全文搜索 我们可以使用PostgreSQL的全文搜索功能, 而不是正则表达式来解决这一问题. 因为这则表达式: 没有语言支持, 不支持派生词, 衍生词, 相近词等 不能根据相近性排序 运行慢, 因为没有index支持 当使用全文搜索时, 则可以做到返回衍生词: &gt;&gt;&gt; Entry.objects.search('man is biting a tail') [&gt;Entry: Man Bites Dogs Tails&lt;] Document 和 Query document指的是全文搜索的一个单位, document可以是任何东西, 在这里, 我们定义为title和body栏为一个单一的document. 为了搜索的速度和效率考虑, 数据库使用document的compact representation (tsvetor). compact representation是经过特殊处理的原始内容. 为了使用查询(query) tsvector, 我们需要使用tsquery. tsquery是经过普通化的query. 通过tsvector和tsquery的匹配, 才能完成搜索. 在query中使用他们, 则需要to_tsvector和to_query的帮助, 以下是解决本篇开头问题的一个语句: SELECT ... WHERE to_tsvector(COALESCE(title, '') || ' ' || COALESCE(body, '')) @@ to_tsquery('man & bites & dog'); 关于 Stem 为了将搜索项和document文字整合起来, PostgreSQL使用了stemming词典. 显示PostgreSQL中已安装的词典: => \dFd List of text search dictionaries Schema | Name | Description ------------+-----------------+------------------------------- pg_catalog | danish_stem | snowball stemmer for danish language pg_catalog | dutch_stem | snowball stemmer for dutch language pg_catalog | english_stem | snowball stemmer for english language pg_catalog | finnish_stem | snowball stemmer for finnish language pg_catalog | french_stem | snowball stemmer for french language pg_catalog | german_stem | snowball stemmer for german language pg_catalog | hungarian_stem | snowball stemmer for hungarian language pg_catalog | italian_stem | snowball stemmer for italian language pg_catalog | norwegian_stem | snowball stemmer for norwegian language pg_catalog | portuguese_stem | snowball stemmer for portuguese language pg_catalog | romanian_stem | snowball stemmer for romanian language pg_catalog | … -
Creating a custom user model in Django 1.6 - Part 5
Hello everyone and welcome back to the fifth part of this tutorial (part of the Babbler tutorial series). If you haven't read the first four parts I'd encourage you to do so now: part 1: the model part 2: migration and admin forms part 3: frontend login form part 4: admin login form This week we will cover user registration with e-mail validation as well as the "lost / change password" workflow.As we did two weeks ago we will be using (generic) class-based views to build our forms and Crispy forms to render them. We will also be using Templated emails to handle our email needs and we will create our first management command. -
如何在 Django models 中使用多语言 (i18n) 的简单方法
本篇介绍一个在django model中使用多语言支持的快速方法, 该方法通过建立自定义的template tag 选取model中重复的语言field来达到多语言显示的目的. 假设我们有这样一个models.py, 某一个model中包含多个重复的field, 每个重复的field都是用来保存其对应的显示语言: class MyObject(models.Model): name = models.CharField(max_length=50) title_en = models.CharField(max_length=50) title_es = models.CharField(max_length=100) title_fr = models.CharField(max_length=100) description_en = models.CharField(max_length=100) description_es = models.CharField(max_length=100) description_fr = models.CharField(max_length=100) class MyOtherObject(models.Model): name = models.CharField(max_length=50) content_en = models.CharField(max_length=200) content_es = models.CharField(max_length=200) content_fr = models.CharField(max_length=200) 注意, 我们将下划线和语言代码作为后缀放在对应的field后面, 这将作为一个语言的查找标记. 然后我们在settings.py中添加需要翻译的field名: TRANSLATION_FIELDS = ('title', 'description', 'content') 在项目目录中添加templatetags目录(不要忘了怎家__init__.py), 并在其中建立lazy_tags.py: from django import template from settings import TRANSLATION_FIELDS register = template.Library() class LocalizedContent(template.Node): def __init__(self, model, language_code): self.model = model self.lang = language_code def render(self, context): model = template.resolve_variable(self.model, context) lang = template.resolve_variable(self.lang, context) for f in TRANSLATION_FIELDS: try: setattr(model, f, getattr(model, '%s_%s' % (f, lang))) except AttributeError: pass return '' @register.tag(name='get_localized_content') def get_localized_content(parser, token): bits = list(token.split_contents()) if len(bits) != 3: raise template.TemplateSyntaxError("'get_localized_content' tag takes exactly 2 arguments") return LocalizedContent(model=bits[1], language_code=bits[2]) 为了在template中使用自定义的tag, 我们首先载入: {% load lazy_tags %} 然后使用自定义tag, 传入object和语言代码, 取的翻译. 比如西班牙语: {% get_localized_content object 'es' %} 此时, 如果没有语言代码传入, 那么无法使用obj.description调用某一个语言field. 所以我们配合django.core.context_processors.request, context processor一起使用: TEMPLATE_CONTEXT_PROCESSORS = ( ... 'django.core.context_processors.request', ) 我们就能在template中这样使用: {% get_localized_content object request.LANGUAGE_CODE %} -
Release 1.2b3
-
Release 1.2b2
-
Using Chart.js with Django
Chart.js is the new kid on on the block for JavaScript charts. Learn how to use them here to chart out the number of user registrations for the last 30 days. The View This view builds an array of people that registered on the site daily for the last 30 days. from django.views.generic import TemplateView from django.contrib.auth.models import User import arrow class AnalyticsIndexView(TemplateView): template_name = 'analytics/admin/index.html' def get_context_data(self, **kwargs): context = super(AnalyticsIndexView, self).get_context_data(**kwargs) context['30_day_registrations'] = self.thirty_day_registrations() return context def thirty_day_registrations(self): final_data = [] date = arrow.now() for day in xrange(1, 30): date = date.replace(days=-1) count = User.objects.filter( date_joined__gte=date.floor('day').datetime, date_joined__lte=date.ceil('day').datetime).count() final_data.append(count) return final_data The method thirty_day_registrations loops through from 1 to 30, and gets the count of registrations for that day. Then it returns that array back to the get_context_data method and assigns it to 30_day_registrations which is what we will use in our template. The Template The template is very basic in that it has just enough data to generate a line chart. {% extends "base.html" %} {% block extrahead %} <script src="//cdnjs.cloudflare.com/ajax/libs/Chart.js/0.2.0/Chart.min.js" type="text/javascript"></script> <script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.1/jquery.min.js" type="text/javascript"></script> <script type="text/javascript"> $( document ).ready(function() { var data = { labels: ['1', '5', '10', '15', '20', '25', '30'], datasets: [ { label: "Site … -
Tips for Upgrading Django
From time to time we inherit code bases running outdated versions of Django and part of our work is to get them running a stable and secure version. In the past year we've done upgrades from versions as old as 1.0 and we've learned a few lessons along the way. Tests are a Must You cannot begin a major upgrade without planning how you are going to test that the site works after the upgrade. Running your automated test suite should note warnings for new or pending deprecations. If you don’t have an automated test suite then now would be a good time to start one. You don't need 100% coverage, but the more you have, the more confident you will feel about the upgrade. Integration tests with Django's TestClient can help cover a lot of ground with just a few tests. You'll want to use these sparingly because they tend to be slow and fragile. However, you can use them to test your app much like a human might do, submitting forms (both valid and invalid), and navigating to various pages. As you get closer to your final target version or you find more edge cases, you can add focused unittests to … -
Release 1.2b2
-
Release 1.2b1
-
将 Django 作为 bootstrap 的后台框架
如果你想在Django中使用Bootstrap作为前台框架, 但又不知道如何将他们整合到一起的话, 那么本篇我们就介绍一下使用django自带的staticfiles app将Bootstrip整合到Django中: 首先我们需要在GetBootstrip.com下载Bootstrip. 然后我们解压缩zip文件, 将加压缩的文件放入项目中. 接着在settings.py的STATICFILES_DIRS中添加bootstrip目录. 最后我们使用以下base.html为基础: <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Bootstrap | {% block title %}Untitled{% endblock %}</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content=""> <meta name="author" content=""> <!-- Le styles --> <link href="{{STATIC_URL}}css/bootstrap.css" rel="stylesheet"> <style> body { padding-top: 60px; /* 60px to make the container go all the way to the bottom of the topbar */ } </style> <link href="{{STATIC_URL}}css/bootstrap-responsive.css" rel="stylesheet"> <!-- Le HTML5 shim, for IE6-8 support of HTML5 elements --> <!--[if lt IE 9]> <script src="http://html5shim.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> <script src="{{STATIC_URL}}js/jquery-1.8.1.min.js" type="text/javascript"></script> {% block extrahead %} {% endblock %} <script type="text/javascript"> $(function(){ {% block jquery %} {% endblock %} }); </script> </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </a> <a class="brand" href="/">Bootstrap</a> <div class="nav-collapse collapse"> <ul class="nav"> <li class="active"><a href="/">Home</a></li> <li><a href="#about">About</a></li> <li><a href="#contact">Contact</a></li> </ul> </div><!--/.nav-collapse --> </div> </div> </div> <div id="messages"> {% if messages %} {% for message in messages %} <div class="alert alert-{{message.tags}}"> <a class="close" data-dismiss="alert">×</a> {{message}} </div> {% endfor %} {% endif %} </div> <div class="container"> {% block content %} {% endblock %} </div> <!-- /container --> </body> </html> 有了以上base.html之后, 我们就可以按照自己的需求修改并获得最佳效果了. -
使用 pyrrd 收集系统信息
上星期, 我们想测试几个WSGI应用的评分, 由于不同的concurrency模式, 使我们很难一一设置并评测. 其中的系统信息也是一项重要的指标, 例如CPU消耗, 内存消耗等信息的收集和图像化. RRDtool是一个广泛使用的测试工具. 我们可以通过pyrrd和subprocess模块对每个WSGI应用进行测试: from pyrrd.rrd import DataSource, RRA, RRD dss = [ DataSource(dsName='cpu', dsType='GAUGE', heartbeat=4), DataSource(dsName='mem', dsType='GAUGE', heartbeat=4) ] rras = [RRA(cf='AVERAGE', xff=0.5, steps=1, rows=100)] rrd = RRD('/tmp/heartbeat.rrd', ds=dss, rra=rras, step=1) rrd.create() 以上代码将会使用CPU和内存实用信息创建/tem/heartbeat.rrd文件. 两者都定义为GAUGE类型. 然后我们定义了round-robin archive(RRA)来储存最多100个数据点. 在代码最后, 我们使用之前的设置, 以每秒的速度保存到RRD文件中. pyrrd模块使用的属于与rrdtool相同, 因此我们可以使用现成的rrdtool知识. 使用subprocess: pattern = re.compile('\s+') command = '/bin/ps --no-headers -o pcpu,pmem -p %s' % ' '.join(pids) while True: ps = subprocess.check_output(command, shell=True) pcpu = 0.0 pmem = 0.0 for line in ps.split('\n'): if line.strip(): cpu, mem = map(float, pattern.split(line.strip())) pcpu += cpu pmem += mem rrd.bufferValue(time.time(), pcpu, pmem) rrd.update() time.sleep(1) 使用ps命令过滤显示每个pid的%CPU和%MEM使用信息, 然后输出经过处理保存到rrd文件. 请注意, 这不是一个典型的rrdtool使用案例. 通常的使用情形是: # -*- coding: utf-8 -*- from __future__ import (absolute_import, division, print_function, with_statement, unicode_literals) import re import signal import sys import time import subprocess from random import random, randint from pyrrd.rrd import DataSource, RRA, RRD def usage(): print('%s rrdfile pid, ...' % __file__) print('sample the %cpu and %mem for specified pids, aggregated') def sigint_handler(signal, frame): print("Sampling finishes: %.2f." % time.time()) sys.exit(0) def main(): rrd_file = sys.argv[1] pids = sys.argv[2:] dss = [ DataSource(dsName='cpu', dsType='GAUGE', heartbeat=4), DataSource(dsName='mem', dsType='GAUGE', heartbeat=4) ] rras = [RRA(cf='AVERAGE', xff=0.5, steps=1, rows=100)] rrd = RRD(rrd_file, ds=dss, rra=rras, step=1) rrd.create() signal.signal(signal.SIGINT, sigint_handler) pattern = re.compile('\s+') command = '/bin/ps … -
Release 1.2b1
-
在Python模块顶层运行的代码引起的一个Bug
几个星期前, 我的同事跑过来, 说发现一个奇怪的Bug: 在使用Python的subprocess运行子进程时, 当子进程运行失败时居然没有抛出错误! 然后我们在Interactive Python prompt中测试了一下: >>> import subprocess >>> subprocess.check_call("false") 0 而在其他机器运行相同的代码时, 却正确的抛出了错误: >>> subprocess.check_call("false") Traceback (most recent call last): File "", line 1, in File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/subprocess.py", line 542, in check_call raise CalledProcessError(retcode, cmd) subprocess.CalledProcessError: Command 'false' returned non-zero exit status 1 看来是subprecess误以为子进程成功的退出了导致的原因. 深入分析 第一眼看上去, 这一问题应该是Python自身或操作系统引起的. 这到底是怎么发生的? 于是我的同事查看了subprocess的wait()方法: def wait(self): """Wait for child process to terminate. Returns returncode attribute.""" while self.returncode is None: try: pid, sts = _eintr_retry_call(os.waitpid, self.pid, 0) except OSError as e: if e.errno != errno.ECHILD: raise # This happens if SIGCLD is set to be ignored or waiting # for child processes has otherwise been disabled for our # process. This child is dead, we can't get the status. pid = self.pid sts = 0 # Check the pid and loop as waitpid has been known to return # 0 even without WNOHANG in odd situations. issue14396. if pid == self.pid: self._handle_exitstatus(sts) return self.returncode 可见, 如果os.waitpid的ECHILD检测失败, 那么错误就不会被抛出. 通常, 当一个进程结束后, 系统会继续记录其信息, 直到母进程调用wait()方法. 在此期间, 这一进程就叫"zombie". 如果子进程不存在, 那么我们就无法得知其是否成功还是失败了. 以上代码还能解决另外一个问题: Python默认认为子进程成功退出. 大多数情况下, 这一假设是没问题的. 但当一个进程明确表明忽略子进程的SIGCHLD时, waitpid()将永远是成功的. 回到原来的代码中 我们是不是在我们的程序中明确设置忽略SIGCHLD? 不太可能, 因为我们使用了大量的子进程, 但只有极少数情况下才出现同样的问题. 再使用git grep后, 我们发现只有在一段独立代码中, 我们忽略了SIGCHLD. 但这一代吗根本就不是程序的一部分, 只是引用了一下. 一星期后 一星期后, 这一错误又再一次发生. 并且通过简单的调试, 在debugger中重现了该错误. 经过一些测试, 我们确定了正是由于程序忽略了SIGCHLD才引起的这一bug. 但这是怎么发生的呢? 我们查看了那段独立代码, 其中有一段: signal.signal(signal.SIGCHLD, signal.SIG_IGN) 我们是不是无意间import了这段代码到程序中? 结果显示我们的猜测是正确的. 当import了这段代码后, 由于以上语句是在这一module的顶层, 而不是在一个function中, 导致了它的运行, 忽略了SIGCHLD, 从而导致了子进程错误没有被抛出! 总结 这一bug的发生, … -
Python Deque 模块简单介绍和示例
Deque模块是Python标准库collections中的一项. 它提供了两端都可以操作的序列, 这意味着, 你可以在序列前后都执行添加或删除. 创建Deque序列: from collections import deque d = deque() Deque提供了类似list的操作方法: d = deque() d.append('1') d.append('2') d.append('3') len(d) d[0] d[-1] 输出结果: 3 '1' '3' 两端都使用pop: d = deque('12345') len(d) d.popleft() d.pop() d 输出结果: 5 '1' '5' deque(['2', '3', '4']) 我们还可以限制deque的长度: d = deque(maxlen=30) 当限制长度的deque增加超过限制数的项时, 另一边的项会自动删除: d = deque(maxlen=2) d.append(1) d.append(2) d d.append(3) d deque([1, 2], maxlen=2) deque([2, 3], maxlen=2) 添加list中各项到deque中: d = deque([1,2,3,4,5]) d.extendleft([0]) d.extend([6,7,8]) d 输出结果: deque([0, 1, 2, 3, 4, 5, 6, 7, 8]) -
Erratum
Hello everyone.We are sorry but it appears we published a partial post yesterday evening. It has been unpublished and its full version will be re-published tonight.In the mean time, have a great day everyone. -
cached-property: Don't copy/paste code
In Python, the @cached_property decorator is a really nice piece of code. What it does is it caches the result of a property call. The cached result will persist as long as the instance does, so if the instance is passed around and the function subsequently invoked, the cached result will be returned. If that doesn't make much sense, below is a snippet of code that shows the code and demonstrates it in action. As always, I'm using pytest to validate my code: from datetime import datetime, timedelta import time class cached_property(object): """ A property that is only computed once per instance and then replaces itself with an ordinary attribute. Deleting the attribute resets the property. Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76 """ def __init__(self, func): self.__doc__ = getattr(func, '__doc__') self.func = func def __get__(self, obj, cls): if obj is None: return self value = obj.__dict__[self.func.__name__] = self.func(obj) return value class SlowClass1(object): @cached_property def very_slow(self): """Represents a performance heavy property.""" time.sleep(1) # Wait a WHOLE second! return "I am slooooow" def test_slow_class1(): # Instantiate the slow class slow_class = SlowClass1() # Start the clock! start = datetime.now() # Call the property. This time it's really slow... assert slow_class.very_slow == "I am slooooow" # Check … -
cached-property: Don't copy/paste code
In Python, the @cached_property decorator is a really nice piece of code. What it does is it caches the result of a property call. The cached result will persist as long as the instance does, so if the instance is passed around and the function subsequently invoked, the cached result will be returned. If that doesn't make much sense, below is a snippet of code that shows the code and demonstrates it in action. As always, I'm using pytest to validate my code: from datetime import datetime, timedelta import time class cached_property(object): """ A property that is only computed once per instance and then replaces itself with an ordinary attribute. Deleting the attribute resets the property. Source: https://github.com/bottlepy/bottle/commit/fa7733e075da0d790d809aa3d2f53071897e6f76 """ def __init__(self, func): self.__doc__ = getattr(func, '__doc__') self.func = func def __get__(self, obj, cls): if obj is None: return self value = obj.__dict__[self.func.__name__] = self.func(obj) return value class SlowClass1(object): @cached_property def very_slow(self): """Represents a performance heavy property.""" time.sleep(1) # Wait a WHOLE second! return "I am slooooow" def test_slow_class1(): # Instantiate the slow class slow_class = SlowClass1() # Start the clock! start = datetime.now() # Call the property. This time it's really slow... assert slow_class.very_slow == "I am slooooow" # Check … -
Creating a custom user model in Django 1.6 - Part 4
Hi everyone and welcome back to this Django tutorial. If you haven't done so yet, make sure to check out the first, second and third part of this tutorial before getting started today.This week we will start by covering the admin login form and allowing users to log into the admin site using their e-mail address instead of their username.Then we will go through a couple more advanced cases of custom user model in Django, including expirable users. -
将 Sublime 3 打造成 Python/Django IDE
Sublime Text 是一款非常强大的文本编辑器, 下面我们介绍如何将 Sublime Text 3 打造成一款 Python/Django 开发利器: 1. 安装 Sublime Text 3 虽然现在的 Sublime 3 还处于 beta 阶段, 但已经非常稳定了, 而且速度比 Sublime 2 得到了增强. Sublime 3 可以到官网下载并安装. Sublime 虽然是免费软件, 但如果有足够的经济能力, 可以考虑购买以表示支持. 2. 安装 Package Control Sublime Package Control 可以说是必须安装的插件, 因为其方便的提供了安装/升级/删除 Sublime 插件的功能, 安装方法见Package Control 官网. 安装完毕后, 就可以使用快捷键 ctrl+shift+p (Win, Linux) 或 cmd+shift+p (OS X), 其中以 Package Control: 开头的都是其相关命令, 最常用的可能就是 Package Control: Install Package, Package Control: Remove Package, Package Control: List Packages 这几个命令了. 3. 推荐安装的插件 现在可以使用 Package Control 安装其他插件了. 使用快捷键 ctrl+shift+p (Win, Linux) 或 cmd+shift+p (OS X), 输入 Package Control: Install Package 回车, 输入 package 名再回车安装: Anaconda Anaconda是目前 Sublime 3 中最好的 Python 自动补全和语法提示插件, 并且提供了"跳转到定义", "查找使用", "显示文档", "自动重命名"等 IDE 中插件的功能. Djaneiro 提供了对Django的支持. SideBarEnhancements 提供了对默认的侧边栏的增强功能. Sublime的侧边栏可以使用快捷键 Ctrl+k Ctrl+b (Linux, Win), CMD+k CMD+b (OS X) 调出来. 安装之后, 还可以通过F12键在浏览器中打开当前文件. Git 相关 我们需要安装 SublimeGit 和 GitGutter, 前者可以帮助我们在 Sublime 中使用 Git 命令 (通过 ctrl+shift+p 或 cmd+shift+p), 后者在编辑时在 Gutter 显示 Git 差异, 十分方便. 主题相关 Theme - Soda 和 Monokai Extended, 安装之后在 user settings 中设置使用: "color_scheme": "Packages/Monokai Extended/Monokai Extended.tmTheme", "theme": "Soda Dark 3.sublime-theme", 其他插件 还可以安装 Emmet, SublimeLinter (注意依赖关系), ColorPicker, Gitignore等插件 4. 设置 以下是推荐的设置, 可以直接复制黏贴放入 user settings 中, 需要注意的是字体文件需要提前安装: { "always_show_minimap_viewport": true, "auto_complete_commit_on_tab": false, "auto_find_in_selection": true, "bold_folder_labels": true, "color_scheme": "Packages/Monokai Extended/Monokai Extended.tmTheme", "theme": "Soda Dark 3.sublime-theme", "default_line_ending": "unix", … -
O'Reilly Deal: 50% Off Lightweight Django
O'Reilly Media, the go-to source for technical books, just let us know that they're having a 50% off sale on eBook pre-orders of Lightweight Django today. Lightweight Django is being written by our very own Technical Director, Mark Lavin and Caktus alumna Julia Elman. We would've thought the book was a fantastic intro to the power of Django in web app development anyway, but since Mark and Julia wrote it, we think it’s extra fantastic. Mark and Julia are continuing to write, but O'Reilly is providing this special pre-release peek for pre-orders. Those that pre-order automatically receive the first three chapters, content as it’s being added, the complete ebook, free lifetime access, multiple file formats, and free updates.