Django community: Community blog posts RSS
This page, updated regularly, aggregates Community blog posts from the Django community.
-
Links
There is a new version of gunicorn, 19.0 which has a couple of significant changes, including some interesting workers (gthread and gaiohttp) and actually responding to signals properly, which will make it work with Heroku. The HTTP RFC, 2616, is now officially obsolete. It has been replaced by a bunch of RFCs from 7230 to 7235, covering different parts of the specification. The new RFCs look loads better, and it’s worth having a look through them to get familiar with them. Some kind person has produced a recommended set of SSL directives for common webservers, which provide an A+ on the SSL Labs test, while still supporting older IEs. We’ve struggled to find a decent config for SSL that provides broad browser support, whilst also having the best levels of encryption, so this is very useful. A few people are still struggling with Git. There are lots of git tutorials around the Internet, but this one from Git Tower looks like it might be the best for the complete beginner. You know it’s for noobs, of course, because they make a client for the Mac I haven’t seen a lot of noise about this, but the EU has outlawed pre-ticked … -
django-chile-payments
If you have ever implemented support for a payment broker in your project there's a chance that you have come across brokers that are a delight to use and implement. And others that are, frankly, a pain in the ass to work with. Here in Chile, the only choice you have (as we are writing this post in June 2014) if you want to process payments through credit or debit cards is Webpay Plus from Transbank. There are certainly some other services wrapping Transbank platform to offer a more user-friendly, but they charge higher rates as they become a re-seller. Also you could implement solutions such as Paypal and operate with dollars, but although it has become recently easier for businesses to transfer Paypal funds to chilean pesos, it is not likely that most of your chilean customers will have Paypal accounts ready with dollars to spend. Things would not be so terrible if Transbank API was something enjoyable to implement as Stripe or similar. Dream on. Documentation is frequently outdated or incomplete, their list of requirements to fulfill is tough, and they force you to set up your stack with legacy technologies (e.g. you must run CGI scripts) and … -
Heroku Django S3 for serving Media files
Why should i store my media files on AWS S3? Heroku dynos have limited life span, and when they die and get replaced, the files within them are lost. So you should set up Django media handler to put the files somewhere permanent. Let's begin: 1) Install dependencies: $ pip install django-storages boto (Update your requirements.txt using pip freeze > requirements.txt) 2) Update INSTALLED_APPS in your settings.py: INSTALLED_APPS += ('storages',) 3) Sign in to AWS Console, select S3 under Storage & Content Delivery and create a bucket. 4) Don't forget to generate AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY. 5) Add the below to your settings file: AWS_QUERYSTRING_AUTH = False AWS_ACCESS_KEY_ID = os.environ['AWS_ACCESS_KEY_ID'] AWS_SECRET_ACCESS_KEY = os.environ['AWS_SECRET_ACCESS_KEY'] AWS_STORAGE_BUCKET_NAME = os.environ['S3_BUCKET_NAME'] MEDIA_URL = 'http://%s.s3.amazonaws.com/your-folder/' % AWS_STORAGE_BUCKET_NAME DEFAULT_FILE_STORAGE = "storages.backends.s3boto.S3BotoStorage" Note: You should never expose your AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY there is some reason why they are called SECRET. 6) Install AWS CLI on your machine. 7) Its time to move your files to AWS S3 bucket. $ aws s3 cp myfolder s3://mybucket/myfolder --recursive 8) After the previous step you can use the following command to view the contents of your bucket. $ aws s3 ls s3://mybucket 9) Grant public-read permission to everyone, add the below to your … -
Django 1.6 最佳实践: django项目的服务器部署
如果详细说明django项目的不熟的话,可能需要整本书才能说明清楚, 这里我们只从较高角度讨论. 1. 使用一台服务器 如果django项目较小, 也不会有太多用户访问的话, 我们可以使用一台服务器来部署. 此时我们需要以下部件: 关系型数据库: PostgreSQL 或 MySQL HTTP 服务器: Nginx + uWSGI, Nginx + gunicore 或 Apache + mod_wsgi 进程管理: Supervisord 或 init scripts NoSQL数据库 (为短时间数据存在): Redis用于cache和消息列队, Memcached用于cache, RabbitMQ为消息列队 2. 使用多台服务器 简单情景 如下图, 你需要至少两台服务器, 一台是数据库服务器, 另一台则是 WSGI application 服务器. 如果可能还可以增加CDN用于储存媒体文件, cache服务器用于储存缓存, 任务服务器用于单独运行CPU敏感的任务. 复杂情景 如下图, 你需要software-based或hardware-based 的 loading balancer, software-based的有HAPProxy, Varnish, Nginx. hardware-based的有Foundry, Juniper, DNS load balancer. 当然还可以使用cloud-based的, 例如Amazon Elastic Load Balancer, Rackspace Cloud Load Balancer. 3. WSGI Application 服务器 首先需要说明的是, 永远使用WSGI部署django项目. django 的 startproject 会为我们设置好wsgi.py文件, 这一文件中包含了部署django项目到wsgi服务器的默认设置. 最常见的WSGI服务器配置包括: Nginx + uWSGI Nginx + Gunicorn Apache + mod_wsgi 以下是这三者的一个简单对比表: 配置优势劣势 Nginx + uWSGI 使用纯C语言构造; 拥有许多优秀的特性和选项; 声称具有更好的性能 文档不够完整; 没有经过长时间测试 Nginx + Gunicorn Gunicorn使用纯Python构造; 声称具有更好的内存管理能力 Gunicorn和Nginx的文档不足; 没有经过长时间测试 Apache + mod_wsgi 存在已经, 经过长时间测试; 非常稳定; 在windows下可运行; 文档丰富 不提供 environment variable 支持; 设置较复杂 虽然现在有许多测试表明哪个组合更快, 但不要盲目的相信这些测试结果, 因为大多数的测试可能都是基于测试小页面而得到的结果, 因此与实际的情况可能相差甚远. 则三种组合在现实环境中都有大量的使用案例. 要想使任何一种配置达到高通量的要求都需要我们投入时间和精力来测试获得. 使用自己的服务器的缺点就是我们需要额外的系统管理员, 而不像使用PaaS平台那么简便. 4. 自动化部署 当我们设置服务器时, 不应该每次都使用ssh登录服务器, 再按照记忆一步一步的配置. 因为这样实在是太容易忘记某些步骤了. 服务器设置应当自动化, 并写成文档. 在django用户中, Ansible, SaltStack, Puppet和Chef是最流行的四款自动化部署工具. 这些工具似乎都需要长时间学习才能使用, 因为这些工具不是为一台服务器设置的, 而是针对多台服务器的. 以下是这些工具的基本功能: 远程通过apt-get或其他包管理系统安装软件包 远程运行命令 远程启动, 重启各项服务 记录远程运行的命令和其结果 创建或更新服务配置文件 为不同服务器载入不同的配置文件 部署和更新项目代码 比较表: 工具优势劣势 SaltStack 主要用push模式; 使用0mq传输快; 许多例子; 庞大的社区支持; 开源; 由Python写成 较复杂 Ansible 主要用push模式; 可使用Fireball模式加速传输; 不需要远程进程运行; 使用YAML语言设置; 开源; 由Python写成 新项目, 例子较少, 没有官方WSGI和Django配置例子 Chef 有许多例子; 庞大的社区支持; 开源 难学; 由ruby写成, 配置也是ruby语言; Puppet 庞大的社区支持; 开源 较难学; 由ruby写成; 配置文件由自定义DSL设置 Fabric和Invoke则是专注于远程运行命令, 常可以和以上四个工具配合使用. 现在的趋势是更多的使用SaltStack或Ansible, 因为使用Python写成的, 所以更利于Python用户深入了解. 但需要注意的是, 这些趋势会变化, 如果想了解最新的趋势, 需要我们多关注相关的博客. -
Creating a custom user model in Django 1.6 - Part 3
Hello everyone and welcome back to the third part of this tutorial series. If you haven't done so yet, make sure to checkout part 1 and 2 first.Last week we saw how to create and use admin forms with a custom user model. This week we will go through the process of creating a frontend login form. During this process we will also cover (part of) template inheritance, csrf, the messages framework, accessing the user from the template and Crispy forms. I know last week I announced that this week's post would also cover the admin login form but finally the admin login form will be covered next week. -
Django 1.6 最佳实践: 部署到PaaS (Platforms as a Service) 平台
如果你的django项目是一个小型项目, 或者你的公司是初创公司, 使用PaaS平台部署django项目可能是个不错的选择. PaaS平台既能节约时间, 又省去了自己部署服务器的麻烦. 有些大型的django项目也可以利用PaaS带来的好处. 但需要注意的是, 永远不要绑定到某个平台. 虽然这些平台为我们提供了非常好的代码, 数据库, 媒体文件的储存和依托, 但如果其收费发生变化, 服务发生变化, 那么我们将会变得措手不及. 因此, 我们开发项目时, 不能一开始便为某一平台开发, 而是需要注重通用性, 方便在各平台或自己的服务器质检切换. 1. 如何衡量PaaS 标准 在衡量各PaaS前, 我们首先需要查看PaaS是够符合项目的一些硬性标准, 比如在医疗领域, 可能需要符合HIPAA标准, 许多电子商务型的网站也需要SSL支持. 价格 比较一下项目所需要的配置在各个平台间的价格是最基本的考查方式. 但我们还需要考虑到当项目的访问人数增加, 高流量的配置需要增加的费用在各平台间有什么分别. 稳定性 稳定性也十分重要, 许多平台都会打出标语, 保证99.9999%及以上的在线稳定运行时间, 但这些可信度如何还需要我们自己来测试. 服务 我们还需要查看的是各平台是否有足够的员工为我们提供技术支援, 如果PaaS平台的员工人数不足, 那24x7的服务时间肯定是无法保证的. 扩展性 每个平台是否能够轻易的scale up也是一个基本的问题. 有时我们会面对突然增加的流量, 这时可扩展性就显得非常重要. 文档 每个平台是否提供足够的文档支持也十分重要. 地点 选择一个离客户距离较近的PaaS平台能增加客户的访问速度, 因此也是一个需要考虑的因素. 公司 PaaS平台的所属公司也是需要考虑的因素之一, 有一个稳定的后台公司支持才能保障平台的长期存在. 2. 如何部署到PaaS 保持环境一致 部署项目的环境应当与开发环境尽量保持一致, 这样才能利于维护. 自动化部署 我们可以使用Makefiles, Invoke等工具将部署的步骤自动化, 从而减少工作难度. 测试 自动化部署工具往往自带测试功能, 即将项目部署到一个测试的PaaS实例中, 一切正常后才部署到正式PaaS实例中. 备份 随时为突发灾难准备好备份, 并且将这些备份分别保存在本地和其他储存环境中. -
Stripe, Webhooks and dj-stripe
Stripe is great for working with payments. Webhooks and dj-stripe make it even better, in this video learn how to use stripe webhooks with your application to get the most out of your stripe integration.Watch Now... -
Getting Started Scheduling Tasks with Celery
Many Django applications can make good use of being able to schedule work, either periodically or just not blocking the request thread. There are multiple ways to schedule tasks in your Django app, but there are some advantages to using Celery. It’s supported, scales well, and works well with Django. Given its wide use, there are lots of resources to help learn and use it. And once learned, that knowledge is likely to be useful on other projects. Celery versions This documentation applies to Celery 3.0.x. Earlier or later versions of Celery might behave differently. Introduction to Celery The purpose of Celery is to allow you to run some code later, or regularly according to a schedule. Why might this be useful? Here are a couple of common cases. First, suppose a web request has come in from a user, who is waiting for the request to complete so a new page can load in their browser. Based on their request, you have some code to run that's going to take a while (longer than the person might want to wait for a web page), but you don't really need to run that code before responding to the web request. … -
Django 1.6 最佳实践: Django项目中的小工具
1. 自定义工具 有时为了完成Django项目, 我们不得不自己写一些通用的function, class等工具. 这些临时工具不属于任何一个特定的app, 而我们又不希望将这些工具放在其他相关的app中, 而变得难以查找到和再次利用. 我们的方式是将他们放入一个名字为core的django app中(也可以叫utils, generic等): core/ __init__.py managers.py # 包含自定义的model manager models.py views.py # 包含自定义的view mixin 注意, 不要漏掉models.py, 为了是core app成为django app, models.py是必须的. 2. Django自带工具 在django中, 包含了许多自带的工具: django.contrib.humanize 提供了一系列用于本地化的template filter, 例如intcomma可以将整数转化为带有逗号或点的字符串. 你也可以单独引入其中的工具作为function使用. django.utils.encoding.force_text(value) 该util可以将任何东西转为文本字符串, 避免了显示django.utils.functional.__proxy__. django.utils.functional.cached_property 作为decorator使用, 可以将单个method的结果进行cache, 具体使用方法见https://docs.djangoproject.com/en/dev/ref/utils/#module-django.utils.functional. django.utils.html.format_html(format_str. *args, **kwargs) 类似于Python的str.format(), 但专为html设计. 所有的args和kwargs中的HTML tag都会自动去除后再传到str.format(). django.utils.html.remove_tags(value, tags) 当我们需要从用户那边接受内容, 但有希望过滤掉特定tag时, 可以使用. django.utils.html.strip_tags(value) 当我们需要从用户那边接受内容, 但有希望过滤掉所有html tag时, 可以使用. django.utils.six six是一个python2和python3兼容库. django.utils.timezone 最好开启django的timezone功能, 因为我们的用户可能住在不同的时区. 但我们开启timezone支持后, 时间信息将会以UTC形式储存在数据库中, 并在显示时自动转为当地时间. 3. Exception django自带了许多exception, 大多数是供内部使用的, 但还有一些exception则可以被狠和好的利用. django.core.exceptions.ImproperlyConfigured 用于设置错误抛出错误, 我们在之前的博文中讨论过: Django 1.6 最佳实践: 如何设置django项目的设置(settings.py)和部署文件(requirements.txt). django.core.exceptions.ObjectDoesNotExist 这是所有DoesNotExist exception的最基本class, 当我们获取未知类型model时十分有用: from django.core.exceptions import ObjectDoesNotExist class BorkedObject(object): loaded = False def generic_load_tool(model, pk): try: instance = model.objects.get(pk=pk) except ObjectDoesNotExist: return BorkedObject() instance.loaded = True return instance django.core.exceptions.PermissionDenied 这一exception用于用户未被授权执行某一操作时抛出, view则会自动返回django.http.HttpResponseForbidden. 4. Serializer 和 Deserializer 当用到JSON, Python, YAML或XML数据时, 我们都可以使用django自带的Serializer和Deserializer: from django.core.serializers import get_serializer from favorites.models import Favorite # json可以替换成python或xml, 如果装了pyyaml, 也可替换成pyyaml JSONSerializer = get_serializer("json") serializer = JSONSerializer() favs = Favorite.objects.filter()[0:5] serialized_data = serializer.serialize(favs) with open("data.json", "w") as f: f.write(serialized_data) from django.core.serializers import get_serializer from favorites.models import Favorite favs = Favorite.objects.filter()[0:5] # json可以替换成python或xml, 如果装了pyyaml, 也可替换成pyyaml JSONSerializer = get_serializer("json") serializer = JSONSerializer() with open("data.txt") as f: serialized_data = f.read() # deserialize model 数据 python_data = serializer.deserialize(serialized_data) for element in python_data: print(type(element)) print( element.object.pk element.object.created ) Python自带的JSON模块无法处理date/time 和 decimal类型, 但django提供了一个JSONEncoder class: … -
Travel Grants for DjangoCon Europe 2104
The Django Software Foundation has opened applications for grants to help those who would otherwise find it difficult to meet the cost of attending DjangoCon Europe 2104. The procedure is easy and fairly informal. Complete the application form by March 21st at 11:59pm PDT, and you should have a response within a week. Everyone's welcome to apply, and speakers who need assistance are particularly encouraged to. Good luck! -
Two Scoops at DjangoCon Europe
Our friends Audrey and Danny may not be able to be with us in person this year, but here's the next best thing: they're sponsoring the event, and they'll be sending copies of their book, Two Scoops of Django: Best Practices for Django 1.6. To get your copy, just buy a Two Scoops ticket, and when you arrive the book will be waiting for you! We're going to use the revenue from Two Scoops sales to help subsidise the attendance of a speaker who's on a low budget, so buying the book this way means that you're not just buying a book, you're making a small but meaningful contribution to the event. And speaking of making a contribution: if you'd like to put something into a fund to help subsidise another attendee, there's a ticket for that too. If you have a little to spare, feel free to put it into the ticket to Contribution to help an attendee on a low budget. Any amount will help, and every penny that we receive will help another attendee. There'll be other Two Scoops goodies at DjangoCon Europe - you'll find out more when you get there. Orders for Two Scoops will … -
Django 1.6 最佳实践: 如何正确使用 Signal
如何正确的使用signal: 简单回答是: 在其他方法无法使用的情况下, 才最后考虑使用signal. 因为新的django开发人员得知signal之后, 往往会很高兴去使用它. 他们在能使用signal的地方就使用signal, 并且这是他们觉得自己是django专家一样. 然而, 像这样编码一段时间后, django项目就会变得异常复杂, 许多内容都纠结在一起无法解开. 许多开发者也会将django signal和异步消息列队(例如celery)搞混. signal是同步处理, 因此通过signal调用大处理量的进程时并无法提高性能. 事实上, 将这些需要大处理量的进程移到signal中被视作是一种不好的习惯. 1. 何时使用signal 以下情况不要使用signal: signal与一个model紧密相关, 并能移到该model的save()时 signal能使用model manager代替时 signal与一个view紧密相关, 并能移到该view中时 以下情况可以使用signal: signal的receiver需要同时修改对多个model时 将多个app的相同signal引到同一receiver中处理时 在某一model保存之后将cache清除时 无法使用其他方法, 但需要一个被调函数来处理某些问题时 2. Signal的代替方法 使用mod而来manager 以下代码演示了当用户创建Event model时, 需要通知管理员, 如果改写model中的post_save(), 则需要添加额外的逻辑来区分用户还是管理员: # myapp/managers.py from django.db import models class EventManager(models.Manager): def create_event(self, title, start, end, creator): event = self.model(title=title, start=start, end=end, creator=creator) event.save() event.notify_admins() return event 在model中设置model manager: # myapp/models.py from django.conf import settings from django.core.mail import mail_admins from django.db import models from model_utils.models import TimeStampedModel from .managers import EventManager class Event(TimeStampedModel): STATUS_UNREVIEWED, STATUS_REVIEWED = (0, 1) STATUS_CHOICES = ( (STATUS_UNREVIEWED, "Unreviewed"), (STATUS_REVIEWED, "Reviewed") ) title = models.CharField(max_length=100) start = models.DateTimeField() end = model.dateTimeField() status = models.IntegerField(choices=STATUS_CHOICES, default=STATUS_UNREVIEWED) creator = models.ForeignField(settings.AUTH_USER_MODEL) objects = EventManager() def notify_admins(self): subject = "{user} submitted a new event!".format(user=self.creator.get_full_name()) message = """TITLE: {title} START: {start} END: {end}""".format(title=self.title, start=self.start, end=self.end) mail_admins(subject=subject, message=message, fail_silently=False) 在view中使用create_event()代替create()时, 便会通知管理员了. 在其他代码中验证model 如果你使用pre_save signal来验证某一model, 则应当尝试自己写一个validator取代之. 如果验证是通过ModelForm时, 通过改写clean()实现验证. 使用model的save()和delete() 如果使用pre_save 或 post_save signal, 如果可以, 则将这些代码移到model的save()方法中. 同样如果使用pre_delete 或 post_delete signal, 如果可以, 则将这些代码移到model的delte()方法中. 使用其他代码代替signal 如果可能, 我们可以将signal的逻辑使用其他帮助程序实现. -
Django 1.6 最佳实践: 如何设置和使用log
任何参与过高要求的大型项目的编程人员都明白设置适当的log等级, 创建不同的logger, 记录重要事件的重要性. 正确的设置和使用log并不是一件容易的事, 但对于系统的稳定性而言, logging则是必不可少的. log不仅能用来debug程序, 并能追踪影响程序表现的指标. 之前我们提到需要定期查看access和error文件, 除了记录这些外, 还需要定期查看log文件, 以保证程序安全. 本片的内容主要关于Django项目的log. 但除此之外, 还有服务器log, 数据库log等, 这些都为我们提供了检测系统运行状况的依据. 不同的log等级分别是: DEBUG, INFO, WARING, ERROR和CRITICAL. 1. 如何选择log level log等级是在Django settings中设置的, 因此我们可以根据需要进行适当的调节. DEBUG: 在正式服务器中不使用DEBUG等级. 当你想使用print显示默写信息时, 使用DEBUG log代替. CRITICAL: 当任何导致项目崩溃的事件发生时使用. 这一等级在Django自身的代码中从未使用过, 但我们还是可以在极严重错误发生时使用, 例如关键性的第三方服务无法响应时 ERROR: 当代码抛出exception但未被捕捉到时, 或任何值得通知项目负责人的错误发生时使用. 例如Django项目发生500错误时, 默认便以ERROR等级记录并通知项目管理人员. 再例如view中的第三方API无法使用时 WARNING: 当任何不寻常, 可能带来潜在危险的事件发生, 但不及ERROR时. 例如Django发生403错误时, 默认使用WARNING记录. 当使用django-admin-honeypot记录到由用户登录虚假的admin界面时. INFO: 当需要记录有用的信息时. 例如开启关闭某一模块, 状态改变, 权限更改等, 再例如用INFO等级记录与系统表现相关的信息, 帮助我们找到系统瓶颈. 使用DEBUG log代替print的例子: import logging from django.views.generic import TemplateView from .helper import pint_counter logger = logging.getLogger(__name__) class PrintView(TemplateView): def get_context_data(self, *args, **kwargs): context = super(PrintView, self).get_context_data(self, *args, **kwargs) pints_remaining = pint_counter() logger.debug("Only %d pints of ice cream left" % pints_remaining) return context 2. 记录exception 当log一个exception时, 如果能统计记录下exception的traceback的话, 对于我们debug十分有用, 我们可以使用: Logger.exception(): 自动记录traceback, 并以ERROR等级log 对于其他log level, 使用exc_info argument import logging import requests logger = logging.getLogger(__name__) def get_additional_data(): try: r = request.get("http:..example.com/something-optional/") except: request.HTTPError as e: logger.exception(e) logger.debug("Cound not get additional data", exc_info=True) return None return r 3. logger和模块一一对应 当在一个模块中使用logger时, 不要从其他模块中引用, 而应新建一个logger. 你可以在任何模块中使用以下代码, 以获取新的logger: import logging logger = logging.getLogger(__name__) 这样做的好处是, 你可以为特定模块开启或关闭logger. 例如, 当正式服务器上出现问题, 但我们无法再开发服务器重现这一问题时, 我们便可以在正式服务器上开启相关模块的logger来帮助我们debug. 待解决问题后, 再关闭该logger, 而不需要开启整站的logger. 4. 记录到rotation文件 默认情况下, 当django出现ERROR及以上log时, 系统会通过AdminEmailHandler将log信息发送给settings的ADMINS list中的管理人员. 除此之外, 我们建议将INFO及以上的log记录到rotating文件中. 记录到磁盘的log可以在没有网路的情况下帮助我们解决问题, rotation则能保证文件不会太大贰占据整个系统. 最常见的使用rotation文件记录log的方法是使用logging.handlers.WatchedFileHandler配合UNIX的logrotate工具. -
Release 0.8.0 alpha 3
We just released LFS 0.8.0a3. This is a feature release. Changes Reverts all changes from 0.8.0a2 (these has been moved to 0.9.0 alpha 1) Adds checkboxes to filters Adds "For Variants" checkbox to Property (see help for more) 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 -
Release 0.9.0 alpha 1
We just released LFS 0.9.0a1. This is a feature release. Changes Adds Django 1.6 support Removes double colons from management forms Removes django-tagging from dependencies 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 -
Tastypie & Django-Polymorphic
I ran into this problem last night, and since Googling for it didn't help, I thought it prudent to post my solution publicly in case anyone else might have a similar problem. Tastypie is a nifty REST API server app for Django that does a lot of the work for you when all you want to do is share your model data with the world using standardised methods. It's smart enough to do introspection of your models and then use what it finds to make serialisation decisions further down the line. That's how you get from a series of model field definitions to an easy to parse JSON object. Django-Polymorphic is an amazing piece of software that lets you effortlessly dump polymorphic attributes into your models in an understandable and performant way. With it you can do things like ask for a list of Items and get back a series of EdibleItems and MetalItems. While both of these technologies are awesome, they don't appear to play nice together. From what I can tell, this is due to how Tastypie does its introspection: at startup time rather than run time. Introspection is done once, on the initial class, and then never … -
Enforcing case sensitivity in databases
Hey guys! When I was developing today I realized that the username primary keys were not case sensitive. This is a big drawback. It reduces the number of unique and viable usernames. Even though this number is still gargantuan, case sensitive usernames are a must everywhere.The demonstrate my problem, here's what was happening:nitin was a username registered on my site. It was allowing entry and showing the same account when logged in with Nitin, nItin, and so on. There are 32 possibilities (2^5) of nitin being spelled with either upper or lower case characters.Thus, 32 possible user accounts were being mapped on to only one. To do this, the username has to be checked in the query itself.Now, select something from some_table where username = "nitin" would give you the same result for all 32 possibilities of nitin.To avoid this, the query has to be altered:select something from some_table where binary username = "nitin"The binary checks for case also.Cheers! -
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的载入.