Contents
  1. 1. 应用挂载
  2. 2. 模板路径
  3. 3. 自定义用户

原标题: 这几天搬砖所得

搬了大概一周的砖头以后, 对Django这个框架的想法就是, 真tm好用, 又真tm难用. 好用的地方在于web开发中你一切遇到的所有问题, 都会有一套对应的解决方案; 难用的地方就是, 遇到的那些问题, 你必须要按照它的那套解决方案. 所以写Django的时候, 基本上不需要休息思考的时间, 就是查手册, 查源码, 搜方案, 面向stackoverflow编程, 必须用IDE, 爬断点, 文件改名全局索引, debug热点表达式, 不然手动打log工作量就不是人能承受的了.当然, 如果你是个熟练工的话,用Django的工作量可能是最小的…

应用挂载

Django是一个典型的Restful架构框架, 举个例子, 在animal应用下挂载一个猫应用, tree如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
.
├── animal
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── cat
│   ├── __init__.py
│   ├── admin.py
│   ├── models.py
│   ├── tests.py
│   └── views.py
└── manage.py

如果在cat下继续挂应用, 比如挂喂养的子应用, 此时无法直接通过manage.py创建cat/feed应用, 需要手动构建, 具体做法如下(feed模块为手动构建):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
.
├── animal
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── cat
│   ├── __init__.py
│   ├── admin.py
│   ├── feed
│   │   ├── __init__.py
│   │   ├── models.py
│   │   ├── templates
│   │   │   └── feed
│   │   │   └── home.html
│   │   ├── urls.py
│   │   └── views.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
└── manage.py

先在项目setting.py中注册下列模块:

1
2
'cat'
'cat.feed'

项目url配置, animal/urls.py

1
2
3
4
...
url(r'^admin/', include(admin.site.urls)),
url(r'^cat/', include('cat.urls'))
)

挂载app的url, 新建cat/urls.py, namespace可选

1
2
3
...
url(r'^feed/', include('cat.feed.urls', namespace='cat_feed'))
)

就可以通过配置 cat/feed/urls.py, 配置子项目的MVC了

1
2
3
...
url(r'^$', 'cat.feed.views.home', name='home'),
)

模板路径

Django的模板路径优先级是先去搜索setting.pyTEMPLATES变量里的DIRS对象中的路径下遍历的templates文件夹, 同名的按照先搜索到的为准. 因此除了一些公用模板(例如base.html404.html), 一般子应用的模板不应该随意用长变量名的方式放在应用挂载下, 应该放在templates内同名的文件夹中,例如feed应用应该在feed目录下的templates文件夹中新建一个feed文件夹,在这个文件夹中放feed应用的专用模板, 这样挂载在子应用下的子应用内的view层就能通过应用名/模板名的方式去引用模板, 一层一层的extend上一层应用的base.html, 这样就遵循了代码组件化的原则, 类似于React.
同时使用namespace可以使路由可读性变得更好.

自定义用户

这里涉及到Django庞大的第三方库的使用, 一般第三方库都不会去重写User类, 倾向于到Django中django.contrib.auth.model去重写/继承/封装,例如要在User中添加字段的技巧

————————— 以下引用 —————————

本篇主要讨论一下User Model的使用技巧. 注意, 由于Django 1.5之后user model带来了很大的变化, 本篇内容只针对django 1.5之后的版本.

1.确定 User Model

我们推荐一下方式来确定某一django项目使用的user model:

1
2
3
4
5
6
7
8
9
# 使用默认User model时
>>> from django.contrib.auth import get_user_model
>>> get_user_model()
<class 'django.contrib.auth.models.User'>
# 使用自定义User model时
>>> from django.contrib.auth import get_user_model
>>> get_user_model()
<class 'xxx.models.UserProfile'>

2.使用settings.AUTH_USER_MODEL

自从django 1.5之后, 用户可以自定义User model了, 如果需要外键使用user model, 官方推荐的方法如下:

在settings中设置AUTH_USER_MODEL:

1
2
3
# settings.py
# 格式为 "<django_app名>.<model名>"
AUTH_USER_MODEL = "myapp.NewUser"

在models.py中使用

1
2
3
4
5
6
7
# models.py
from django.conf import settings
from django.db import models
class Article(models.Model):
author = models.ForeignKey(settings.AUTH_USER_MODEL)
title = models.CharField(max_length=255)

还有需要注意的是, 不要在外键中使用get_user_model().

3.自定义 User Model

方法1: 扩展 AbstractUser类

如果你对django自带的User model刚到满意, 又希望额外的field的话, 你可以扩展AbstractUser类:

1
2
3
4
5
6
# myapp/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class NewUser(AbstractUser):
new_field = models.CharField(max_length=100)

不要忘了在settings.py中设置:

1
AUTH_USER_MODEL = "myapp.NewUser"

方法2: 扩展 AbstractBaseUser类

AbstractBaseUser中只含有3个field: password, last_login和is_active. 如果你对django user model默认的first_name, last_name不满意, 或者只想保留默认的密码储存方式, 则可以选择这一方式.

参考官方文档:
https://docs.djangoproject.com/en/1.7/topics/auth/customizing/

方法3: 使用OneToOneField

如果你想建立一个第三方模块发布在PyPi上, 这一模块需要根据用户储存每个用户的额外信息. 或者我们的django项目中希望不同的用户拥有不同的field, 有些用户则需要不同field的组合, 且我们使用了方法1或方法2:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# profiles/models.py
from django.conf import settings
from django.db import models
from flavors.models import Flavor
class EasterProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
favorite_ice_cream = models.ForeignKey(Flavor, null=True, blank=True)
class ScooperProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
scoops_scooped = models.IntergerField(default=0)
class InventorProfile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
flavors_invented = models.ManyToManyField(Flavor, null=True, blank=True)

使用以上方法, 我们可以使用user.easterprofile.favorite_ice_cream获取相应的profile.

使用这一方法的坏处可能就是增加了代码的复杂性.

原文链接: http://www.weiguda.com/blog/28/

————————— 引用完毕 —————————

目前我用方法3的方式, 就是使用OneToOneField的方式, 因为这样做的显著降低代码耦合性, 使应用结构更加松散.

Contents
  1. 1. 应用挂载
  2. 2. 模板路径
  3. 3. 自定义用户