Django community: Community blog posts RSS
This page, updated regularly, aggregates Community blog posts from the Django community.
-
Release 0.7.8
We just released LFS 0.7.8. This is a yet another bugfix release of the 0.7 branch. Changes Bugfix: excludes variants of inactive parents Bugfix: fixes issue #13 in lfs_theme Bugfix: fixes removing of products on manufacturer delete Bugfix: adds field 'link' to action add form; updates docs; issue #51. 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 最佳实践: Django Forms 的其他使用技巧
Django forms确实强大, 但在使用过程中, 你也许会觉得有些地方使用起来很困惑. 不过, 如果你了解forms的结构的, 那么这些困惑就能立刻变得清晰: 1. 何时使用POST方法 如果HTML form中提交的是需要修改数据内容的动作, 那么就应当使用POST, 唯一的例外是search form, 因为提交的搜索并不会修改数据: <form action="/article/add/" method="POST"> 还有需要注意的是, 不要关闭django 的CSRF保护, 详细可以查看https://docs.djangoproject.com/en/1.6/ref/contrib/csrf/ 2. Django Forms的验证过程 上一篇中, 我们介绍了怎么自定义forms的验证. 进一步理解Forms验证的过程, 可能会帮助你编写更好的代码. 接下来让我们看一下forms的验证过程. 当执行form.is_valid()时, 以下步骤会一步接着一步发生: 1.如果form已捆绑数据(bound data), 那么form.is_valid()会调用form.full_clean()方法: 2.form.full_clean()将依次验证每个field: a.通过to_python()方法将field中数据转化为对应python数据类型 b.针对不同field类型, 进行field类型验证和自定义validator验证 c.通过自定义的clean<field>()方法验证 3.执行form.clean()方法 4.如果是ModelForm, 则调用form.post_clean()方法: a.无论form.is_valid()返回是True或False, 将form的数据传到对应的model实例中 b.调用model的clean()方法 (使用ORM保存model时, 并不会调用model的clean()方法) 我们可以看出, form的数据先保存到from实例中, 如果是ModelForm, 则再保存到model实例中. 因为在没有使用form.save()之前, model实例是不会被写入数据库的. 这样, 我们就有机会记录并保存用户的错误输入: # utils/models.py from django.db import models class FailureHistory(models.Model): form_data = models.TextField() model_data = models.TextField() # myapp/models.py import json from django.core import serializers from django.views.generic import CreateView from utils.models import FailureHistory class ArticleCreateView(CreateView): ... def form_invalid(self, form): form_data = json.dumps(form.cleaned_data) model_data = serializers.serialize("json", [form.instance])[1:-1] FailureHistory.objects.create( form_data = form_data, model_data = model_data ) return super(ArticleCreateView, self).form_invalid(form) -
Django 1.6 最佳实践: 如何正确使用 Django Forms
Django forms使用容易, 又方便扩展, 因此Django admin和CBVs基本都基于forms使用. 事实上, 由于django forms的强大验证功能, 大多数Django API 框架都是用forms作为其验证的一部分. 虽然django forms的学习需要花费一点时间, 但如果将forms, models和views结合起来使用, 我们可以花费很少的经历来完成庞大的工作. 1. Django Forms的强大之处 有些django项目并不直接呈现HTML, 二是以API框架的形式存在, 但你可能没有想到, 在这些API形式的django项目中也用到了django forms. django forms不仅仅是用来呈现HTML的, 他们最强的地方应该是他们的验证能力. 下面我们就介绍几种和Django forms结合使用的模式: 2. 模式一: ModelForm和默认验证 最简单的使用模式便是ModelForm和model中定义的默认验证方式的组合: # myapp/views.py from django.views.generic import CreateView, UpdateView from braces.views import LoginRequiredMixin from .models import Article class ArticleCreateView(LoginRequiredMixin, CreateView): model = Article fields = ('title', 'slug', 'review_num') class ArticleUpdateView(LoginRequiredMixin, UpdateView): model = Article fields = ('title', 'slug', 'review_num') 正如以上代码中看到的一样: ArticleCreateView和ArticleUpdateView中设置model为Article 两个view都基于Article model自动生成了ModelForm 这些ModelForm的验证, 是基于Article model中定义的field转换而来的 3. 模式二, 在ModelForm中修改验证 在上面的例子中, 如果我们希望每篇article title的开头都是"new", 那么应该怎么做呢? 首先我们需要建立自定义的验证(validator): # utils/validator.py from django.core.exceptions import ValidationError def validate_begins(value): if not value.startswith(u'new'): raise ValidationError(u'Must start with new') 可见, 在django中的验证程序就是不符合条件便抛出ValidationError的function, 为了方便重复使用, 我们将它们放在django app utils的validators.py中. 接下来, 我们可以在model中加入这些validator, 但为了今后的方便修改和维护, 我们更倾向于加入到ModelForm中: # myapp/forms.py from django import forms from utils.validators import validate_begin from .models import Article class ArticleForm(forms.ModelForm): dev __init__(self, *args, **kwargs): super(ArticleForm, self).__init__(8args, **kwargs) self.fields["title"].validators.append(validate_begin) class Meta: model = Article Django的edit views(UpdateView和CreateView等)的默认行为是根据view中model属性, 自动创建ModelForm. 因此, 我们需要调用我们自己的Modelform来覆盖自动创建的: # myapp/views.py from django.views.generic import CreateView, UpdateView from braces.views import LoginRequiredMixin from .models import Article from .forms import ArticleForm class ArticleCreateView(LoginRequiredMixin, CreateView): model = Article fields = ('title', 'slug', 'review_num') form_class = ArticleForm class ArticleUpdateView(LoginRequiredMixin, UpdateView): model = Article fields = ('title', 'slug', 'review_num') form_class = ArticleForm 4. 模式三, 使用form的clean()和clean_<field>&()方法 如果我们希望验证form中的多个field, 或者验证涉及到已经存在之后的数据, 那么我们就需要用到form的clean()和clean_<field>&()方法了. 以下代码检查密码长度是否大于7位, 并且password是否和password2相同: … -
Newsletter #3
Newsletter #3, May 21st, 2014 Huge Success at the DjangoCon Europe 2014 Raffle We provide in-kind sponsorship for conferences. What that means is that in return for conferences listing us in their sponsors, we send them a signed copy of Two Scoops of Django 1.6 and a signed art print by Audrey Roy. We encourage conferences to raffle them off. This way our book is used as a means for conferences to provide financial assistance for developers who otherwise could not afford to attend their event. This is exactly what DjangoCon Europe did. They raffled off the book, which earned DjangoCon Europe 2015 a whopping €700, or about $950 US. Needless to say, we're amazed and astounded. As two people who have both attended conferences thanks to the assistance of others, we're delighted that our work is being used in this manner. Sponsoring More Conferences! Here are upcoming conferences that we are sponsoring. In alphabetical order: Kiwi PyCon PyCon Australia PyCon India If your conference is interested in us sponsoring your event, please take a look at our in-kind sponsorship program. Django Packages Service on Github We added a service for Django Packages on Github. If you maintain an open-source … -
Newsletter #3
Newsletter #3, May 21st, 2014 Huge Success at the DjangoCon Europe 2014 Raffle We provide in-kind sponsorship for conferences. What that means is that in return for conferences listing us in their sponsors, we send them a signed copy of Two Scoops of Django 1.6 and a signed art print by Audrey Roy. We encourage conferences to raffle them off. This way our book is used as a means for conferences to provide financial assistance for developers who otherwise could not afford to attend their event. This is exactly what DjangoCon Europe did. They raffled off the book, which earned DjangoCon Europe 2015 a whopping €700, or about $950 US. Needless to say, we're amazed and astounded. As two people who have both attended conferences thanks to the assistance of others, we're delighted that our work is being used in this manner. Sponsoring More Conferences! Here are upcoming conferences that we are sponsoring. In alphabetical order: Kiwi PyCon PyCon Australia PyCon India If your conference is interested in us sponsoring your event, please take a look at our in-kind sponsorship program. Django Packages Service on Github We added a service for Django Packages on Github. If you maintain an open-source … -
Newsletter #3
Newsletter #3, May 21st, 2014 Huge Success at the DjangoCon Europe 2014 Raffle We provide in-kind sponsorship for conferences. What that means is that in return for conferences listing us in their sponsors, we send them a signed copy of Two Scoops of Django 1.6 and a signed art print by Audrey Roy. We encourage conferences to raffle them off. This way our book is used as a means for conferences to provide financial assistance for developers who otherwise could not afford to attend their event. This is exactly what DjangoCon Europe did. They raffled off the book, which earned DjangoCon Europe 2015 a whopping €700, or about $950 US. Needless to say, we're amazed and astounded. As two people who have both attended conferences thanks to the assistance of others, we're delighted that our work is being used in this manner. Sponsoring More Conferences! Here are upcoming conferences that we are sponsoring. In alphabetical order: Kiwi PyCon PyCon Australia PyCon India If your conference is interested in us sponsoring your event, please take a look at our in-kind sponsorship program. Django Packages Service on Github We added a service for Django Packages on Github. If you maintain an open-source … -
Django 1.6 最佳实践: 如何正确使用 CBVs (Class-based views)
Class-based views是Django为解决建站过程中的常见的呈现模式而建立的. 在这节中, 我们着重讲一下CBVs的使用技巧和一般原则. 1. CBVs的使用原则 代码越少越好 永远不要重复代码 View应当只包含呈现逻辑, 不应包括业务逻辑 保持view逻辑清晰简单 不要将CBVs用作403, 404, 500的错误处理程序 保持mixin简单明了 2. 如何使用mixin 在编程中mixin是指为继承它的class提供额外的功能, 但它自身却不能单独使用的类. 在具有多继承能力的编程语言中, mixin可以为类增加额外功能或方法. 在Django中, 我们可以使用mixin为CBVs提供更多的扩展性, 当然在类继承过程中, 我们推荐以下原则: Django自身提供的View永远在最右边 mixin依次在以上view的左边 mixin永远继承自Python的object类型 在这里顺便推荐一个很好的django库: django-braces. 该库中提供众多django的mixin, 可以方便我们日常使用. 以下是一个简单地例子, TemplateView是django自身提供的基本View, 因此在最右边; FreshFruitMixin则在TemplateView左边; FreshFruitmixin继承自object: from django.views.generic import TemplateView class FreshFruitMixin(object): def get_context_data(self, **kwargs): context = super(FreshFruitMixin, self).get_context_data(**kwargs) context["has_fresh_fruit"] = True return context class FruitFlavorView(FreshFruitMixin, TemplateView): template_name = "fruit_flavor.html" 3. 如何使用Django自身的CBV CBVs在功能上的可扩展性, 牺牲的是简单性, 一个CBV最多的时候拥有8个import关系. (如果希望进一步了解这些继承关系, 可以使用Classy Class-Based Views进行查看.) 所以要弄懂那个View最适合当下的场景对于开发人员也是一个挑战. 为了减少CBVs的使用难度, 我们将这些View和基本的用法列在下表中, 为了显示方便, 名字前的django.views.generic前缀皆省去: 名字目的例子 View 基本View, 可以在任何时候使用 见后面详细介绍 RedirectView 重新定向到其他URL 将访问"/log-in/"的用户重新定向到"/login/" TemplateView 显示Django HTML template 一般网站中使用模板显示的页 ListView 显示对象列表 文章列表页 DetailView 显示对象详情 文章详细页 FormView 提交From 网站联系我们或emai订阅form CreateView 创建对象 创建新文章页 UpdateView 更新对象 修改文章页 DeleteView 删除对象 删除文章页 Generic date views 显示一段时间内的对象 按时间归类的博客 4. CBVs的使用技巧 a. 限定访问权限 在django tutorial中介绍了如何一起使用django.contrib.auth.decorators.login_required和CBV, 这是一个典型的错误例子. 还好, 我们有django-braces. 在django-braces中已经提供了一个LoginRequiredMixin: # myapp/views.py from django.views.generic import DetailView from braces.views import LoginRequiredMixin from .models import Article class ArticleDetailView(LoginRequiredMixin, DetailView): model = Article b. 在form提交成功后执行代码 当需要在form提交成功后执行自定义的代码时, 可以使用form_valid()方法, form_valid()方法返回的是django.http.HttpResponseRedirect: # myapp/views.py from django.views.generic import CreateView from braces.views import LoginRequiredMixin from .models import Article class ArticleCreateView(LoginRequiredMixin, CreateView): model = Article field = ('title', 'slug', 'content') def form_valid(self, form): # 自定义的代码逻辑写在这里 return super(ArticleCreateView, self).form_valid(form) c. 在form提交不成功后执行代码 当需要在form提交不成功后执行自定义的代码时, 可以使用form_invalid()方法, form_invalid()方法返回的也是django.http.HttpResponseRedirect: # myapp/views.py from django.views.generic import CreateView from braces.views import LoginRequiredMixin from .models import Article class ArticleCreateView(LoginRequiredMixin, … -
A Different View (part 2)
In the previous post, we saw how we could use a single, raw query in Django to combat ORMs’ tendency to generate query explosions within loops. We used raw() with joins and some column renaming to ensure all the data we needed came back in one go. We had to modify the property names in the template slightly (e.g. book.jacket.image became book.jacket_image) and the result was a RawQuerySet which had a fair number of limitations but, we avoided the typical order-of-magnitude increase in query count. Super models There is a way we can use a raw query, to get all the benefits described in the previous post, and return a real QuerySet. We need a Django model and so need an underlying table. A much underused feature of SQL databases is the view. Views are virtual tables derived from queries. Most are currently implemented as read-only, but they provide many benefits – again another blog post would be needed to explain them all – but they include: adding a level of abstraction, effectively an API (which is also available to other applications) protecting the application from underlying table and column changes giving fine-grained control of permissions, especially row-level providing a … -
A Different View
One of the consequences of the mismatches between databases and ORMs is that iterating over objects can generate explosions of database queries. Often, these explosions go unnoticed because the individual queries are fast and the number of concurrent users is small, especially during development. The explosions are sometimes hard to detect, either because developers don’t look for them or the tools that can expose the explosions don’t report everything (e.g. the Django debug toolbar doesn’t report the queries generated by ajax calls). Exploding Django does a good job of lazily evaluating what it can, but the simple act of using the convenient dot-notation inside a loop can turn a single database query into a cascade of supporting queries. For example, given this book model: class Book(models.Model): title = models.CharField(max_length=100) author = models.ForeignKey(Author) jacket = models.ForeignKey(Jacket) shelf = models.ForeignKey(Shelf) and this books query: books = Book.objects.filter(shelf__position__lte = 10) which returns 10 rows. Then this template: {% for book in books %} {{ book.jacket.image }} {{ book.title }} by {{ book.author.name }} {% endfor %} would issue a single query to get all 10 rows, but would then generate 2 additional queries per iteration to get the jacket and the author for … -
Django 1.6 最佳实践: 如何正确使用 FBVs (Function-based views)
在Django发展的前期阶段, function-based views被开发人员广为使用. 即使在class-based views出现之后, 并且django的作者也推荐使用CBVs (Class-based views), 还是有大量的django新手或经验丰富的开发人员因为FBV说的简洁, 而还在使用FBVs. 接下来我们主要讨论一下使用FBVs时的最佳实践. 1. FBVs的优势 FBVs相对于CBVs, 缺少代码重复领用性, 因为FBVs无法像CBVs一样继承class. 但同时FBVs比CBVs具有更易读性. 以下是一些编写FBVs的原则: 代码越少越好 永远不要重复代码 View应当只包含呈现逻辑, 不应包括业务逻辑 保持view逻辑清晰简单 可以用作403, 404, 500的错误处理程序 应尽量避免内套的"if"逻辑 2. 多使用HttpRequest对象 有时我们想将在view中重复使用一段代码, 又不想把它写入到middleware或context processor中. 我们应当将这些可重复使用的工具程序归并到utils.py中, 方便今后在整个项目中再使用. 对于这种小工具程序, 通常我们的逻辑是从django.http.HttpRequest中提取一些属性, 然后稍加处理, 完成操作. 我们发现, 如果将HttpRequest作为主要参数传入和传出这些工具程序中, 可以大大简化操作和提高可用性: # myapp/utils.py from django.core.exceptions import PermissionDenied def check_rights(request): if request.user.can_do_this or request.user.is_staff: return request # 返回 Http 403 错误 raise PermissionDenied check_rights检查用户是否拥有某项权限, 如果没有则返回403错误. 你会发现, 该程序传回的是HttpRequest对象, 而不是其他特定的值或None. 这样做的好处是, Python是动态类型语言, 我们可以在必要时为HttpRequest添加属性: # myapp/utils.py from django.core.exceptions import PermissionDenied def check_rights(request): if request.user.can_do_this or request.user.is_staff: # 在这里添加can_do_this属性, 意味着在template中 # 可以使用 {% if request.can_do_this %} 语句 # 而不用这样: {% if request.user.can_do_this or request.user.is_staff %} request.can_do_this = True return request # 返回 Http 403 错误 raise PermissionDenied 之后我们便可以在FBVs中使用这些工具: # myapp/views.py from django.shortcuts import get_object_or_404, render from .utils import check_rights from .models import Article def article_list(request): request = check_rights(request) return render(request, "myapp/article_list.html", {"articles": Article.objects.all()} ) def article_detail(request, pk): article = get_object_or_404(Article, pk=pk) request = check_rights(request) return render(request, "myapp/article_detail.html", {"article": article} ) def article_preview(request): """ 不使用check_rights() """ articles = Article.objects.all() return render(request, "myapp/article_preview.html", {"articles": articles} ) 还有一个好处是, 我们可以将这一工具轻易的应用到CBVs中: # myapp/views.py from django.views.generic import DetailView from .utils import check_rights from .models import Article class ArticleDetail(DetailView): model = Article def dispatch(self, request, *args, **kwargs): request = check_rights(request) return super(ArticleDetail, … -
No need to use get_context_data, use {{ view.some_method }}
There's a super nice super elegant productivity trick for Django class based views. Something that is not very well know, as I discovered at last week's djangocon. So... time to share it! The problem? Getting information into your template's context. What most people do is to overwrite get_context_data(), just like the example from the django 1.5 docs def get_context_data(self, **kwargs): # Call the base implementation first to get a context context = super(PublisherDetailView, self).get_context_data(**kwargs) # Add in a QuerySet of all the books context['book_list'] = Book.objects.all() return context In the template you'd use it like this: {% for book in book_list %} ... {% endfor %} The solution? A new feature in Django 1.5 : Django's generic class based views now automatically include a view variable in the context. This variable points at your view object. So... you basically never need to modify get_context_data() anymore! Example: from django.views.generic import TemplateView class SomethingView(TemplateView): template_name = "something.html" title = "My beautiful list of books" def books(self): return Book.objects.all() # Note: no get_context_data() here! The template then uses the automatic view variable to grab the list of books and the title: <h1>{{ view.title }}</h1> <ul> {% for book in view.books %} <li>{{ book … -
Django 1.6 最佳实践: 如何组织和设置urls.py
在本节中, 我们主要讨论一下urls.py设置的主要原则. 在Django中, 每一个request, 都通过URLConfs(通常是urls.py)指向一个view. 这种松散的耦合使得我们拥有无穷的灵活性. 但是需要注意的是: views.py中应该包含view的逻辑 urls.py中应该包含URL逻辑 来看Django tutorial中的一段代码: # 不要这么干! from django.conf.urls import patterns, url from django.views.generic import DetailView from tastings.models import Tasting urlpatterns = patterns("", url(r"^(?<pk>\d+)/$", DetailView.as_view(model=Tasting, template_name="tastings/detail.html"), name="detail"), url(r"^(?<pk>\d+)/results/$", DetailView.as_view(model=Tasting, template_name="tastings/results.html"), name="results"), ) 初看以上代码好像没什么问题, 但是仔细思考之后, 我们会发现他违反了多想Django的哲学: views, urls和models之间的松散耦合性 不重复自己的原则 灵活性原则: class view无法被继承使用 其他: 例如如何增加权限验证, 身份验证等 1. URLConf的松散耦合性 以下是对上面代码的纠正: # tastings/views.py from django.views.generic import ListView, DetailView, UpdateView from django.core.urlresolvers import reverse from .models import Tasting class TasteListView(ListlView): model = Tasting class TasteDetailView(DetailView): model = Tasting class TasteResultsView(TasteDetailView): template_name = "tastings/results.html" class TasteUpdateView(UpdateView): model = Tasting def get_success_url(self): return reverse("tastes:detail", kwargs={"pk": self.object.pk}) # tastings/urls.py from django.conf.urls import patterns, url from .models import views urlpatterns = patterns("", url( regex=r"^$", view=views.TasteListView.as_view(), name="list" ), url( regex=r"^(?P<pk>\d+)/$", view=views.TasteDetailView.as_view(), name="detail" ), url( regex=r"^(?P<pk>\d+)/results/$", view=views.TasteResultsView.as_view(), name="results" ), url( regex=r"^(?P<pk>\d+)/update/$", view=views.TasteUpdateView.as_view(), name="update" ) ) 看了以上代码, 你可能会问, 这真的是正确的做法吗? 你不仅使用了两个文件, 而且代码的行数也增加了! 以下是我们做出这些修改的原因: 符合"不重复自己"的原则: 在views中, 没有重复的参数(包括argument和attribute) 符合松散耦合原则: 我们将model和template的从URLConf中分离了出来, 使得我们有可能从一个或多个URLConf中调用view URLConf应当只做一件事, 且要把它做好: 修改后的URLConf只做一件事情, 就是URL routing, 并且我们没有把view中的逻辑混入URLConf中 使用Class-based view之后, 使我们能继承view: 这意味着, 如果需要增加权限验证, 或其他逻辑都将会变得简单易做 增加了灵活性: 通过建立view class, view逻辑的扩展变得更为便捷 2. 使用 URl Namespaces URL namespaces的作用是, 为URL提供了额外的标签. 表面上看来, 这样做对我们帮助不大, 但是, 一旦你开始使用它们之后, 你就会想, "我为什么 不早点使用URL namespaces呢?". URL namespaces使 tastings_detail 这样的URL变为 tastings:detail. 还是借助以上tasting app的代码, 以下是项目根urls.py中的设置: # 项目根urls.py from django.conf.urls import patterns, include, url urlpatterns += patterns("", url(r"^tastings/", include("tastings.urls", namespaces="tastings")), ) 此时, 在python代码中就可以使用namaspaces了: # 截取自上面tastings/views.py … -
Django 1.6 最佳实践: 如何正确的使用和设置Database和Model
Model是django项目的基础, 如果一开始没有好好设计好, 那么在接下来的开发过程中就会遇到更多的问题. 然而, 大多数的开发人员都容易在缺少思考 的情况下随意的增加或修改model. 这样做的后果就是, 在接下来的开发过程中, 我们不得不做出更多努力来修正这些错误. 因此, 在修改model时, 一定尽可能的经过充分的考虑再行动! 以下列出的是我们经常用到的一些工具和技巧: South, 用于数据迁移, 我们会在每个django项目中都用到. 但到django 1.7时, 将会有django.db.migrations代替. django-model-utils, 用于处理常见的模式, 例如TimeStampedModel. django-extensions, 主要用到shell_plus命令, 该命令会在shell中自动载入所有的app的model 1. 基本原则 第一, 将model分布于不同的app中. 如果你的django项目中, 有一个app拥有超过20个model, 那么, 你就应当考虑分拆该app了. 我们推荐每个app拥 有不超过5个model. 第二, 尽量使用ORM. 我们需要的大多数数据库索引都能通过Object-Relational-Model实现, 且ORM带给我们许多快捷方式, 例如生成SQL语句, 读取/更新数据库时的安全验证. 因此, 如果能使用简单的ORM语句完成的, 应当尽量使用ORM. 只有当纯SQL语句极大地简化了ORM语句时, 才使用纯SQL语句. 并且, 在写纯SQL语句是, 应当优先考虑使用raw(), 再是extra(). 第三, 必要时添加index. 添加db_index=True到model中非常简单, 但难的是理解何时应该添加. 在建立model时, 我们事先不会添加index, 只有当 以下情况时, 才会考虑添加index: 在所有的数据库查询中使用率在10%-25%时 或当有真实的数据, 或能正确估计出使用index后的效果确实满意时 第四, 注意model的继承. model的继承在django中需要十分小心, django提供了三种继承方式, 1.abstract base class继承(不要和Pyhton标准库的abc模块 搞混), 2.多表(multi-table)继承, 3.proxy model继承. 下表罗列了这三种继承的优劣: model继承类型 优势 劣势 不使用继承, 即每个相同的field会重复出现在不同的model中 容易明白model和数据表的关系 如果有大量相同的field, 会较难维护 abstract base class继承, 即只有继承自该类的model才会有数据表, 其自身没有对应的数据表 不用在每个model重复编写相同的field. 也没有多表继承带来的过多消耗 无法单独使用其共同的abstract base class 多表(multi-table)继承 每个model都有数据表, 因此可以既使用母表, 又使用子表. 也能通过parent.child从母表访问子表 增加了消耗, 因为每次查询子表, 都会自动查询其母表. 强烈建议不使用这一方法! proxy model继承, 即只有原始model才会有相应的数据表 在不建立新数据表的情况下, 使我们拥有不同行为的model 无法修改model的field django的创造者和其他许多开发人员都认为, 多表继承的方法不是一个良好的方法. 因此我们强烈建议大家不要使用该方法. 下面列举了一些常见的如何 选择model继承的情形: 如果只有少数model拥有重复的field时, 大可不必使用model继承, 只需要在每个model中添加这些相同的field即可. 如果有足够的model拥有重复的field时, 大多是情况下, 可以使用abstract base class继承, 将相同的field提取到abstract base class 中. Proxy model继承很少被用到, 和其他两种继承也有着许多不一样之处. 请不要使用多表(multi-table)继承, 因为它既消耗资源又复杂, 如果可以, 尽量使用OneToOneFields和ForeignKeys代替. django项目中, 创建时间和修改时间这两个field是最用到的, 下面给出一个abstract base class继承的例子: # models.py from django.db import models class TimeStampedModel(models.Model): """ abstract base class, 提供创建时间和修改时间两个通用的field """ created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) class Meta: abstract = True 注意以上代码的最后两行, 正式这两行将这一model变味了abstract base class, 下面以TimeStampedModel为abstract base class建立model: from django.db import models ... class Article(TimeStampedModel): title = models.CharField(max_length=200) 以上两个class, 在执行syncdb时, 只会建立一个数据表, 这也正是我们希望得到的. 第五, 使用south进行数据迁移, 可以参见以前的文章: 如何在 Django 中使用 django-south, 实现数据迁移 (data migrations) 2. Django Model的设计 如何设计出好的django model可能是最难也是最复杂的一个话题了, 在此, 我们看看一些基本的技巧吧: a. … -
Django 1.6 最佳实践: 如何组织和储存django项目的设置和部署文件
在Django 1.6中的settings.py中可以修改130多项设置, 但大多数都继承自默认值. 设置是在web服务器启动时首次载入的, 服务器重启时重新载入, 因此, 程序员们应尽量避免修改正式服务器上使用的settings.py文件. 以下是一些我们应当遵循的原则: 所有的设置文件应当进行版本管理 不要重复自己 (don't repeat yourself) 妥善保存关键信息 之前, 我们采用的方法是, 不将设置文件放入git库中, 每个开发人员本地有一份自己的设置文件. 但我们发现这样做是错误的. 因为: 在debug之前, 我们可能已经花费了大量精力去模拟正式服务器上出现的错误, 但最终发现这是由于正式服务器的settings文件设置和本地不同而 出现的问题. 这时你的心情会是怎样? 当你在开发django项目时, 发现并修复了一个bug. 当将这一commit push到服务器后, 你突然发现这一bug的出现完全是因为你修改了本地的 settings文件而产生的, 而由于你的push, 又导致了服务器的宕机. 这时你又会是怎样的感受? 每个人都会从另一个程序员那里拷贝/黏贴settings文件内容, 这难道不是违反了"不要重复自己"的原则吗? 正式由于这些问题, 所以我们现在采用不一样的设置方式. 我们首先建立一个基本的设置文件, 然后将开发和正式部署的设置文件分离成不同的模块, 但 这些模块都继承自同一个基本设置文件: 1. 使用分离式的设置文件 django项目建立时, 会自动生成settings.py文件. 为了实现分离式的设置文件, 我们首先删除settings.py, 然后建立settings目录: settings/ __init__.py base.py local.py test.py production.py ... 设置文件目的 base.py 基本设置文件, 在各个环境中都相同的设置可以放入其中. local.py 当在开发时使用的设置文件. 可以设置开发时的选项, 包括DEBUG, log的等级, 是否开启例如 django-debug-toolbar等开发工具等. test.py 运行test时的配置, 包括test runners, in-memory数据库定义和log设置等. production.py 当部署到正式服务器上所用的设置. 我们可以使用以下命令使用这些不同的设置文件: python manage.py shell --settings=mysite.settings.local python manage.py runserver --settings=mysite.settings.local 当然如果你熟悉 DJANGO_SETTINGS_MODULE 和 PYTHONPATH 的话, 也可以事先设置好 DJANGO_SETTINGS_MODULE 和 PYTHONPATH 环境变量, 这样做的好处就是你不必使用--settings了. 如果你对virtualenv有深入的了解的话, 也可以在postactivate脚本中设置 DJANGO_SETTINGS_MODULE 和 PYTHONPATH. local.py的例子 # settings/local.py from .base import * DEBUG = True TEMPLATE_DEBUG = DEBUG EMAIL_BACKEND = 'django.core.email.backends.console.EmailBackend' DATABASES = { "defaults": { "ENGINE": "django.db.backends.postgresql_psycopg2", "NAME": "weiguda", "USER": "", "PASSWORD": "", "HOST": "localhost", "PORT": "", } } INSTALLED_APPS += ("debug_toolbar",) 有时, 一个开发人员的配置文件可能与另一个不同, 这时, 我们可以在settings目录中新建local_name.py: # settings/local_name.py from .local import * # 设置不同的配置 CACHE_TIMEOUT = 30 2. 将关键信息和设置文件分离 将SECTET_KEY, AWS key文件, API key文件等关键信息放入设置文件中也是违反基本原则的. 因为: 配置环境不同时关键信息会改变, 程序却不会. 关键信息不是程序. 关键信息应当是隐蔽的, 如果储存在了版本管理系统中, 则任何有权访问该版本库的用户都能获知这些关键信息. 许多PAAS服务无法为每台服务器编辑设置文件, 即使可以, 这也是不正确的做法. 环境变量 为了避免以上的问题, 我们使用环境变量 (environment variables) 来储存这些关键信息, (需要注意的是, apache不支持环境变量, 我们会在下面讲到). 使用环境变量储存关键信息有以下好处: 将关键信息从代码中移除, 这样你就可以安心的将所有文件放入版本管理系统中. 每个开发人员都拥有一样的local.py文件. 在部署django项目时, 不需要修改程序代码. 大多数PAAS都推荐这一方法, 并提供了方便的设置方法, 因此容易实现. 设置环境变量 在使用bash的Mac或Linux中设置环境变量比较容易, 你只需要将以下代码加入.bashrc, .bash_profile, 或.profile其中之一即可. 如果多个项目 使用相同的API, 并且关键信息都不同时, 可以将以下代码加入到virtualenv的bin/activate脚本中: $ export SOME_SECRET_KEY=654-3jgwg-4r3-2t4h-76jk $ … -
Django在开发环境下的静态文件服务配置方法
在Django的开发环境下配置服务静态文件服务有多种方式,但我发现很多童鞋在开始使用时就会遇到配置问题,耽误很 […] -
Imaginary realities volume 6, issue 1
I'm a bit late with writing about it, but the latest issue of Imaginary Realities has been out for a month or so now. You can find it here.Here is a brief summary of the articles in the latest issue. In A Journey Through Paradice, Part II, Matthew Chaplan continues his description of the C++ codebase Paradice9, notably focusing on its input handling, which uses character-mode telnet to produce plenty of interesting effects in a custom terminal client. There are plenty of interesting features (or potential features) discussed. An example is the client knowing to store the receiver of a "reply" command the moment the command is entered rather than waiting for the player the press return (at which point someone else might have written to you and the reply-to target would have changed in a traditional setup). There is no denying the power of having a custom client for your game. And whereas I think some more secure protocol than telnet would maybe be better to use when you control both server and client anyway, it's really interesting to see the power and features you can achieve with it. Building a Giant Mech in Evennia - this is my entry … -
The story of dpaste.com 2.0
Eight years ago, I launched a simple pastebin site written in Django. In those early Django days I spent a lot of time in the #django IRC channel, and thought we should have a pastebin that knew how to correctly colorize our code, and which was written in our framework to boot. So I wrote one. Eventually its URL ended up in the channel topic, then in the Django source code itself. Over the years, changes have been minimal. I switched from a Javascript-powered colorizer to Pygments. I added an API. I fixed things that broke. Mostly I just kept it running and usable. (I'll also note that many excellent new pastebins were created in those years as well.) Of course I kept a growing list of "someday" improvements and fixes. Despite having no free time (full-time job, twin baby boys, 100-year-old house), a year or so ago I started hacking away on the items on that list. In very tiny steps. Eventually I had enough in place for what I call the 2.0 release of dpaste.com. I presented a preview to my co-workers, and went live about three weeks ago. I call out the fun new stuff on the … -
简单几步, 将VIM打造成Python/Django开发的现代化IDE
编程常用的文本编辑器就那么几种常见的, 有人喜欢Vim, 有人喜欢emacs, 也有人喜欢IDE, 例如Pycharm, Aptana等. 今天我们不谈孰优孰劣, 只要适合自己就可以了. 如果你喜欢VIM, 又希望有IDE常见的自动补全, 语法高亮, 方便的文件切换等功能. 你完全可以将这些功能集成到Vim中, 但是, 对于一个初学者, 或像我一样的懒人, 一个一个的查找并试验配置这些插件未免有些太麻烦. 因此, 本文介绍一个Vim的设置分发系统, 可以简单的满足我们的需要: spf13-vim spf13-vim是一个vim设置分发系统, 适用于Vim, GVim和MacVim. spf13-vim是跨平台的, 它可以让我们既保留Vim的原汁原味, 又为我们增添了插件管理, 自动补全, tag管理等诸多功能. 1. 安装和升级 可以使用spf13-vim的简单安装功能, 一步安装好spf13-vim: curl http://j.mp/spf13-vim3 -L -o - | sh 如果需要升级, 则可以切换到spf13-vim安装目录(默认是~/.spf13-vim/), 运行: cd $HOME/to/spf13-vim/ git pull vim +BundleInstall! +BundleClean +q 如果要在windows安装spf13-vim, 首先需要安装和设置git和curl, 最后运行spf13-vim-windows-install.cmd, 详细信息参见spf13-vim官网 2. 设置 默认的.vimrc文件非常适合编程. 如果你查看.vimrc文件的内容, 你会发现其良好的组织既方便阅读, 又方便学习. 默认的.vimrc文件可以在跨平台系统中使用, 如果你还需要进一步的定制化设置的话, 则可以建立~/.vimrc.local实现. 3. 插件介绍 spf13-vim自带许多插件, 方便我们使用: Vundle Vundle是Vim的插件管理系统, Vundle将vim插件组织在同一目录中, 并可以方便的安装, 升级和删除vim插件. NERDTree NERDTree是一个文件浏览器, 在spf13-vim找中可以通过ctrl+e调出. ctrlp ctrlp是文件载入插件, 通过ctrlp可以方便的浏览系统中文件并打开. 默认情况下可以通过ctrl+p调出. NERDCommenter NERDCommenter可以用来方便的切换代码注释, 默认的快捷键是 , + c + 空格, (','是spf13-vim默认的leader键). 4. 定制化 添加插件 如果想添加新的插件, 则可以通过以下命令添加: echo Bundle \'spf13/vim-colors\' >> ~/.vimrc.bundles.local 修改默认设置 希望修改默认的设置, 例如修改颜色配置, 则可以通过以下方式: echo colorscheme ir_black >> ~/.vimrc.local -
Django 1.6 最佳实践: Django项目的布局结构和目录结构
不同的程序员对于项目布局都有着不同的见解, 在本文中, 我们会介绍我们使用的布局结构. 这种结构应该也是使用最为广泛的结构了. 1. Django默认的项目部局 当我们使用django-admin.py startproject mysite 和 django-admin.py startapp my_app 建立新的Django项目时, Django默认的结构如下: mysite/ manage.py my_app/ __init__.py admin.py models.py tests.py views.py mysite/ __init__.py settings.py urls.py wsgi.py 在Django默认的项目部局中, 存在着一些问题, 特别是在部署到真正的服务器时, 这些问题会越发的明显, 下面我们会一一阐述这些问题: 2. 最终的项目布局 我们使用三层结构来布局我们的Django项目: 最外层是git仓库, 中间层则是django-admin.py默认的生成的项目层, 最里层则是设置层: repository_root/ django_project_root/ configuration_root/ a. 最外层 最外层是整个项目的容器, 除了包括django程序外, 还包括README.rst, docs/, .gitignore, requirements.txt等用于部署到服务器的 必须文件或目录. 这样这些文件便可以通过git管理, 方便开发和维护的使用. README.rst文件和docs目录是用于介绍本项目的文档, 方便程序员了解项目的基本功能等, 我们会在今后详细介绍这一文档. .gitignore文件是git版本控制系统的设置文件之一, 用于设置本仓库中需要忽略的文件或目录, 既不需要保存版本记录文件或目录. requirements.txt则记录着本项目中用到的Python模块和版本的列表, 通常是通过pip freeze获取的. 我们会在今后详细介绍这一文档. b. 中间层 中间层则是由django-admin.py生成, 也就是django默认的项目布局, 中间层生成时, 也包括了最里层: 设置层. 这一层中包括了media目录, static目录, templates目录, 和Django app. c. 最里层 最里层设置层中, 包含了django-admin.py生成的设置文件, 包括settings.py, urls.py等文件. 3. Virtualenv 我们建议将所有virtualenv文件放在统一的目录下, 如果你使用virtualenvwrapper的话, 它位于~/.virtualenvs/中. 并且, 这些文件没有必要保存到git版本管理中, 因为我们已经保存了requirements.txt文件. -
Djangocon: good schema design and why it matters - Andrew Godwin
(One of the summaries of a talk at the 2014 djangocon.eu). Andrew Godwin is a django core developer and he's the author of South and its successor, the database migrations inside django itself. Schemas can be explicit or implicit. Postgresql, mysql and so have explicit schemas, they're regular . Redis, ZODB, couchDB: implicit, you basically "just" put data in (which in probably does have some kind of structure, of course). A problem with implicit schemas is that you can get silent failures: a weight might be "85kg" instead of 74, so a string instead of an int. Schemas inform storage, which might help with performance. And they enforce structure upon the data. The drawback? It enforces structure upon the data. It is less flexible. When you add columns to your table or if you add an index, postgresql often behaves much better than mysql. It is faster and does much less locking. In case you use oracle or mssql, learn their strengths. Well. Schemas. They will need to change. You can put your schema into a vcs, but there's no guarantee that your data will survive the modification. Django has migrations build-in now. But migrations aren't enough: you can't automate … -
Djangocon: introduction to docker - Amjith Ramanujam
(One of the summaries of a talk at the 2014 djangocon.eu). Amjith Ramanujam Why docker? Your site consists of a full stack. Django, database, apache, celery, etc. If you're a full stack deveoper, you need to be able to look at all of them. And ideally you'd have exactly the same environment locally as on the server. Docker calls itself "an easy, lightweight virtualized environment for portable applications". A portable, self-sufficient container. It is a sandboxing technique that is a bit similar to BSD chroots. It uses Linux containers, AUFS, Git-like versioning and a REST API. What is the difference with a normal virtual machine? A VM needs: Host OS Hypervisor Guest OS Libs The app Docker needs: Host Libs. Your app. The libs and the app are part of a docker image. It is faster and much more lightweight. It reuses the host OS (but it is completely isolated!). On OSX: use boot2docker plus an OSX docker client. It uses a virtualbox with linux, the docker client still runs on OSX, but talks to docker inside the virtualbox. Some terminology: an image is a base that contains libs, binaries, environment variables, files and so. When you instantiate ("run") it, … -
Djangocon: Making angularjs play nice with django - Jacob Rief
(One of the summaries of a talk at 2014 djangocon.eu) Remark by Jacob beforehand: there's a bit of trend to put a lot of the UI in javascript. Fine for games and single page apps, but don't do it for ecommerce or CMS sites that you want to have indexed by google. Jacob Rief loves django. The three best parts according to him: Single source of truth. Model view control. Separation of concern. How about doing MVC on the client? A problem is that the browser UI is event-driven: you cannot do a simple one-way data binding from a model + a template to the html code. What you need is a two-way data binding. The model and the view are contiously updated both ways. The model is the single source of thruth. Changes to the view update the model; changes to the model update the view. This way of working is used by many javascript libraries. Angularjs is one of them. The view itself is compiled from a template inside the html code. You mark part of the html structure with angular directives (<div ng-something="bla">) and angular then turns that into the proper view (html DOM) that's bound in … -
Djangocon: challenges when building high profile news sites - Yann Malet
(One of the summaries of a talk at the 2014 djangocon.eu). Yann Malet talks about editorial sites (=newspapers). And especially high profile ones, so ones that see a lot of visitors. Multi layer cache to protect your database Django is web scale. No problem. Django won't be in your way regarding performance. Which means: if you use something else, you'll run into the very same problems. A news item on one of their sites got mentioned a lot on twitter and other sites. Their servers even didn't break a sweat. Caching for the win! You should add caching. You don't need to re-calculate the very same page in the very same way for every new visitor. That takes way too much time. Luckily, adding caching for a news site is relatively easy. Varnish is the first layer of defence. A "web application accelerator", also known as "a caching HTTP reverse proxy". A page coming out of the varnish cache will be 10-1000 times faster than calculating it fresh inside django. Note: building something that caches reliably is very hard. Don't build it yourself, don't re-invent it. Just use varnish and configure it. Some varnish tips: Strip the cookies. Increasing the … -
Djangocon: pytest helps you write better django apps - Andreas Pelme
(One of the summaries of a talk at the 2014 djangocon.eu). Andreas Pelme's slides are at http://speakerdeck.com/pelme . Django already provides some nice tools to make testing easier. The testing experience can become even better, for instance by using pytest. Pytest is quite popular. The ones using it don't want to use anything else. (He showed a couple of tweets of well-known django developers to prove it). Pytest is exensible. Andreas is the maintainer of the pytest-django plugin. The main advantage of pytest is that it allows you to write pythonic tests, without boilerplate. No more self.assertEquals(a, b) but simply assert a == b. Advantage: the error message when it doesn't match is much clearer than the regular test exception. You don't need to subclass from TestCase anymore. Just a function is enough. Django's TestCase would normally give you self.client. The function will look something like def test_something(client): .... The django extension for pytest recognizes "client" and passes in the correct object automatically. That auto-recognized "client" attribute? Pytest calls that a "fixture". No, that's something else than django's fixtures. Test fixtures are very handy for test dependencies. You run the tests with py.test. For this, you need to have your … -
Djangocon keynote: the programmer's body - Daniele Procida
(One of the summaries of a talk at the 2014 djangocon.eu). Daniele Procida talks about diversity in our industry. Everybody seems to share the values and advantages of diversity as the python/django community. So he doesn't need to sell them to us now. What were the earliest computers? Women. The power of early computers was measured in "girl years": the work of how many computing women could it do? Women were highly prized for their manual computing work because they were paid half the salary of male colleagues. Programmers are now building the world. Anyone in the world will live in the world we build. The systems that govern us. The systems that govern our relations. The way we are educated. The way we are formed. Programmers are quite important. So a valid question is "who are these programmers?" But: does the question matter? Doesn't it matter more what we do rather than what we are? Liberalism says that what we do is much more important. Liberalism abstracts from "particulars". And it makes asusmptions and assertions of equality. It actually says that people should be equal. It asserts individual autonomy, responsibility and merit. In case you don't like those answers, …