Skip to content

Instantly share code, notes, and snippets.

@flaneur2020
Created July 27, 2012 04:15
Show Gist options
  • Select an option

  • Save flaneur2020/3186148 to your computer and use it in GitHub Desktop.

Select an option

Save flaneur2020/3186148 to your computer and use it in GitHub Desktop.
notes on django

python的环境与ruby还是有很大不同的,而且框架多如牛毛,将遇到的坑记在这里。

ps: django跟屎一样。

virtualenv

直觉上很容易当作virtualenv当作rvm的存在,但实际上python的版本往往并非大问题,更多需要对付的还是三方库。virtualenv其实更多扮演的是Bundler的角色,但在操作上有所不同。

Bundler通过Gemfile列出当前项目需要的gem并将它们安装到系统,在代码中通过Bundler.require(:all)引入gem,并在bundle exec中设置环境变量之类,以选择正确版本的gem。

virtualenv会创建一个目录,将特定版本的python以及需要的三方库安装或者link在里面。通过一段bash来进入特定的venv,退出时通过一条deactivate命令。而并无bundle exec的对应物。

django

项目目录下的manage.py相当于rails中Rakefile的作用

  • 启动本地服务器: ./manage.py runserver
  • 依据model来初始化数据库:./manage.py syncdb

需要留意的是django下似乎并无migration的对应物,syncdb仅在第一次初始化时有效,如果Model的结构有所更改,应尝试下south。

MTV

django中View相当于Rails中Controller的一个action。urls.py指明了url到view之间的映射关系。

view可以是函数,也可以是对象。django内置的一些View类(如CreateViewUpdateViewListView之类)就是通用的view了,写代码换成改参数。文档见 https://docs.djangoproject.com/en/1.2/ref/generic-views/

app是django的一个核心概念,admin是app就算了,甚至静态文件都是app的存在。大体与rails engine的性质差不多。

静态文件无法显示? 在urls.py下面加上:

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

Template

django中相当于url_for的函数叫做reverse()。取urls.py中定义的名字为参数,返回url。

如果不想敲这个奇葩的reverse(),可以在模板中使用{% url url_name %}命令。

下载文件

可以使用FileWrapper:

response = HttpResponse(FileWrapper(file(path)), content_type='application/zip')
response['Content-Disposition'] = 'attachment; filename=%s' % os.path.basename(path)
return response

validations

与Rails不同,django将validtion的逻辑独立到了Form对象中。Form对象下面是Field对象,Field对象检查validation的方法叫做clean(),总的检查就是full_clean()。一般不需要直接调用它们,需要的是is_valid()。在view中写起代码来像这样:

form = SubmissionForm(request.POST)
if form.is_valid():
    form.save()
    return redirect('/success')

如果要额外的保存一个字段? 比如submission.author = current_user这种。直接给form设置字段是不可行的,需要这样save两次。第一个save只是为了得到model对象:

form = SubmissionForm(request.POST)
form.problem_id = problem.id
if form.is_valid():
    submission = form.save(commit=False) # the key is commit=False
    submission.author_id = request.user.id
    submission.save()

flash

作为rails中flash的对应物,django提供了一个message模块 https://docs.djangoproject.com/en/dev/ref/contrib/messages/

如果按照文档中的设置依然什么都没有不显示,那么修改view中所有的render_to_response方法加上context_instance=RequestContext(request)这个参数。

return render_to_response('oj/user.html', locals(),
                          context_instance=RequestContext(request)

model

Model中常见到null=True, blank=True这两个参数,意思相近,但不是同一个层次上的东西。null用于指示生成schema时允许字段为null,而blank用于指示表单的生成与验证。

many-to-many

注意django中只在一个model中指定many-to-many的关系,不然会创建出两个many-to-many关系。比如:

class Problem(models.Model):
    solved_by_users = models.ManyToManyField('UserProfile')

class UserProfile(models.Model):
    ...

随后,两边一边是:problem.solved_by_users,一边是:userprofile.problem_set

auth

扩展auth模块的User。不能直接加字段,只能建一个one-to-one的关联。

http://nerdydevel.blogspot.com/2012/07/extending-django-user-model.html

db

django在syncdb时并不会设置数据库的编码,所以在manage.py syncdb之前务必跑一下:

ALTER DATABASE ... CHARACTER SET utf8 COLLATE utf8_general_ci

不然会有Incorrect string value的错误出现。

fixtures

可以在后台加一些测试数据之后,一股脑dump出来

./manage.py dumpdata --format=json myapp > /path/to/myapp/fixtures/initial_data.json

需要用的时候,先将数据库reset掉,再syncdb:

./manage.py reset myapp
./manage.py syncdb

south

安装

pip install south,然后在django的settings.py的INSTALLED_APPS下面加上south。

使用

  • 初始化:./manage.py schemamigration app_name --initial
  • 更改model之后,生成migration文件:./manage.py schemamigration app_name --auto
  • 或者人工编写migration文件:./manage.py schemamigration app_name --empty
  • 执行migration: ./manage.py migrate

jinja2

从没见过django这般蛋疼的模板系统,换到jinja2可能会好一点。这里可以使用coffinpip install coffin之后,在django的view中加入from coffin.shortcuts import render_to_response将django默认的那个render_to_response替换掉。

@bhuztez
Copy link

bhuztez commented Jul 27, 2012

virtualenv的作用仅仅是隔离不同的环境。环境在这里指的就是Python执行文件位置和一堆库的组合。Ruby里也有, https://github.com/nkryptic/sandbox , https://github.com/fesplugas/ruby-virtualenv

Python里面和RVM对应的是PythonBrew http://pypi.python.org/pypi/pythonbrew

Bundler.require更接近的是pkg_resources.require。命令行下用easy_install -m可以同时安装同一个库的多个版本。因为pkg_resources.require要求的参数就是字符串,在这个基础上,你自己定义个EggFile,像Bundler那么干也是可以的。但现在更常见的做法是用pip

pip的话,你在开发的时候,有啥依赖的库就直接装上,等到开发结束后,用pip freeze -l得到一个列表,(编辑之后)保存成requirements.txt。下一次安装这些依赖的时候,只需要运行pip install -r requirements.txt就可以了。但pip最大的缺陷是Windows上用不了。

virtualenv最大的坑是命令行,老版本只有--no-site-packages参数,默认行为和新版本--system-site-packages一样,新版本加了--system-site-packages参数,但默认行为和老版本--no-site-packages一样,尽管API是没变。这导致了之前直接通过命令行调用的脚本都废了。

@flaneur2020
Copy link
Author

flaneur2020 commented Jul 27, 2012 via email

@codeb2cc
Copy link

virtualenv的话推荐上virtualenvwrapper http://www.doughellmann.com/projects/virtualenvwrapper/ ,会方便很多

@flaneur2020
Copy link
Author

@codeb2cc pythonbrew也挺不错的样子,底下也是virtualenv,不过依然不大喜欢这种风格..

@bhuztez
Copy link

bhuztez commented Jul 30, 2012

staticfiles,至少Django 1.4只要INSTALLED_APPS里有django.contrib.staticfiles,就没问题了。

至于MySQL,Django是要求Database默认是UTF-8编码,使用InnoDB引擎的。假如不是这样的,你得自己搞定。

https://docs.djangoproject.com/en/1.4/ref/databases/#mysql-notes

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment