Django 2008
Django 2008
ndice general
Preliminares
xvii
Reconocimientos
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
xvii
xvii
xvii
xviii
Sobre el libro
xviii
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Introduccin
xix
1. Introduccin a Django
1.1.
Qu es un Framework Web?
1.2.
1.3.
La historia de Django
1.4.
1.5.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.1.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
1.4.2.
1.4.3.
1.4.4.
Obteniendo ayuda
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2. Empezando
2.1.
Instalar Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.
Instalar Django . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.2.1.
2.2.2.
2.3.1.
2.3.2.
2.3.3.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
2.3.4.
2.3.
2.4.
Comenzando un proyecto
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
El servidor de desarrollo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10
Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11
2.4.1.
2.5.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
13
3.1.
13
3.2.
14
3.3.
16
3.3.1.
. . . . . . . . . . . . . . . . . . . . . .
16
3.4.
18
3.5.
Errores 404
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
18
3.6.
20
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.6.1.
20
3.6.2.
20
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
3.7.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
22
3.8.
Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
23
NDICE GENERAL
iv
4.2.
4.3.
25
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
25
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
26
4.2.1.
26
4.2.2.
28
4.2.3.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
29
4.2.4.
29
4.2.5.
32
32
4.3.1.
Etiquetas
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
32
4.3.2.
Filtros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
36
4.4.
Filosofa y Limitaciones
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
37
4.5.
38
4.6.
Cargadores de plantillas
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
39
4.6.1.
render_to_response() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
4.6.2.
El truco locals()
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
42
4.6.3.
Subdirectorios en get_template() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
4.6.4.
La etiqueta de plantilla
43
include
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
4.7.
Herencia de plantillas
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
43
4.8.
Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
46
47
5.1.
47
5.2.
48
5.3.
49
5.4.
Tu primera aplicacin
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
51
5.5.
52
5.6.
Tu primer modelo
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
52
5.7.
Instalando el modelo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
54
5.8.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
56
5.9.
56
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
57
58
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
59
60
60
61
61
62
62
. . . . . . . . . . . . . . . . . . . . . . . . . .
62
64
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
64
5.14. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
65
67
6.1.
6.2.
68
6.2.1.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
73
6.3.
73
6.4.
77
6.5.
79
6.6.
79
6.7.
Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
79
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
67
NDICE GENERAL
7. Procesamiento de formularios
81
7.1.
Bsquedas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7.2.
El formulario perfecto
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
83
7.3.
83
7.4.
86
7.5.
87
7.6.
88
7.7.
89
7.8.
Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
90
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
91
Trucos de URLconf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
91
8.1.1.
91
8.1.2.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
92
8.1.3.
93
8.1.4.
93
8.1.5.
95
8.1.6.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
95
8.1.7.
99
8.1.8.
100
8.1.9.
8.3.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
100
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
101
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
101
8.2.1.
102
8.2.2.
102
Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
103
9. Vistas genricas
105
9.1.
9.2.
9.3.
9.4.
81
105
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
106
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
107
9.3.1.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
108
9.3.2.
108
9.3.3.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
109
9.3.4.
109
9.3.5.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
110
Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
111
113
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
113
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
113
10.2.1. django.core.context_processors.auth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
117
10.2.2. django.core.context_processors.debug
117
10.2.3. django.core.context_processors.i18n
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
10.2.4. django.core.context_processors.request
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
117
117
117
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
118
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
119
119
120
121
. . . . . . . . . . . . . . . . . . . . . . . . . .
125
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
125
126
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
127
128
10.8. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
128
NDICE GENERAL
vi
129
129
130
131
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
131
131
132
133
133
11.5.1. Inicializacin
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
133
134
135
136
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
11.5.5. Enclosures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
137
11.5.6. Idioma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
137
11.5.7. URLs
137
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
137
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
138
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
138
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
139
139
140
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
141
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
141
11.7. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
142
143
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
143
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
144
145
145
146
146
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
147
148
148
149
149
150
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
151
151
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
153
154
155
. . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . .
156
158
. . . . . . . . . . . . . . . . . . . . . . . . .
159
12.5.1. Permisos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
159
12.5.2. Grupos
12.5.3. Mensajes
12.5.4. Perles
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
160
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
160
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
161
12.6. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
161
NDICE GENERAL
vii
13.Cache
163
163
13.1.1. Memcached . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
164
164
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
165
165
165
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
165
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
165
166
. . . . . . . . . . . . . . . . . . . . . . . . . . . .
167
167
168
169
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
169
170
171
171
13.8. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
172
173
173
14.2. Sites . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
174
174
174
. . . . . . . . . . . .
174
175
14.2.5. CurrentSiteManager
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
177
178
14.3. Flatpages
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
178
179
180
180
14.4. Redirects
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
181
181
181
182
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
182
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
182
183
184
14.6.1. apnumber . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
184
14.6.2. intcomma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
184
14.6.3. intword
184
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
14.6.4. ordinal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
184
185
14.8. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
185
15.Middleware
187
15.1. Qu es middleware . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
187
188
188
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
188
188
. . . . . . . . . . . . .
189
189
189
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
190
190
NDICE GENERAL
viii
190
190
191
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . .
191
191
191
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
191
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
191
15.5. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
191
inspectdb
193
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
193
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
193
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
194
194
. . . . . . . . . . . . . . . . . . . . . . . . . . . . .
195
195
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
196
16.4. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
196
199
200
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
200
200
200
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
200
201
201
203
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
203
205
17.5. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
205
18.Internacionalizacin
207
208
208
209
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
209
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
209
. . . . . . . . . . . . . . . . . . . . . . . .
210
211
211
212
212
214
214
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
215
215
. . . . . . . . . . . . . . . . . . . . . . . . . . .
216
216
gettext
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
217
18.9. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
217
NDICE GENERAL
ix
19.Seguridad
219
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
219
219
19.2.1. La solucin
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
220
221
221
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
222
222
19.5.1. La solucin
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
223
223
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
224
224
19.7.1. La solucin
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
224
225
225
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
225
19.10.Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
226
20.Implementando Django
227
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
227
228
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
229
229
. . . . . . . . . . .
230
. . . . . . . . . . . . . . . . . . . . . . .
231
231
232
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
232
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
232
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
232
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
233
234
235
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
236
236
237
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
237
237
239
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
239
242
242
242
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
242
242
243
20.7. Qu sigue? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
243
A. Casos de estudio
245
A.1. Elenco . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
245
246
A.3. Comenzando
247
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
247
247
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
249
A.7. Implementacin . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
249
NDICE GENERAL
251
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
251
B.1.1. AutoField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
252
B.1.2. BooleanField
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
252
B.1.3. CharField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
252
B.1.4. CommaSeparatedIntegerField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
252
B.1.5. DateField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
252
B.1.6. DateTimeField
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
252
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
252
B.1.8. FileField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
252
B.1.9. FilePathField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
253
B.1.7. EmailField
B.1.10. FloatField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
254
B.1.11. ImageField
254
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B.1.12. IntegerField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
254
B.1.13. IPAddressField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
254
B.1.14. NullBooleanField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
254
B.1.15. PhoneNumberField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
254
B.1.16. PositiveIntegerField
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B.1.17. PositiveSmallIntegerField
B.1.18. SlugField
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
254
254
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
255
B.1.19. SmallIntegerField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
255
B.1.20. TextField
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
255
B.1.21. TimeField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
255
B.1.22. URLField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
255
B.1.23. USStateField
255
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B.1.24. XMLField . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
255
255
B.2.1. null
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
256
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
256
B.2.3. choices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
256
B.2.4. db_column . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
257
B.2.2. blank
B.2.5. db_index
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
257
B.2.6. default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
257
B.2.7. editable
257
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B.2.8. help_text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
257
B.2.9. primary_key
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
257
B.2.10. radio_admin
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
257
B.2.11. unique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
257
B.2.12. unique_for_date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
257
B.2.13. unique_for_month . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
258
B.2.14. unique_for_year . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
258
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
258
B.3. Relaciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B.2.15. verbose_name
258
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
258
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
260
261
B.4.1. db_table
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B.4.2. get_latest_by
261
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
262
B.4.3. order_with_respect_to . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
262
B.4.4. ordering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
262
B.4.5. permissions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
262
B.4.6. unique_together
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
263
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
263
B.4.7. verbose_name
B.4.8. verbose_name_plural . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
B.5. Managers
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
263
263
264
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
264
266
NDICE GENERAL
xi
B.6.1. __str__ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
266
B.6.2. get_absolute_url . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
267
268
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
268
268
B.7.1. date_hierarchy . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
269
B.7.2. elds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
269
B.7.3. js . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
270
B.7.4. list_display . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
270
B.7.5. list_display_links
B.7.6. list_lter
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
271
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
272
B.7.7. list_per_page
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
272
B.7.8. list_select_related . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
272
B.7.9. ordering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
272
B.7.10. save_as . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
272
B.7.11. save_on_top . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
272
B.7.12. search_elds
272
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
275
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
275
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
276
276
277
277
278
278
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
279
280
280
C.5.4. Metodos de
283
QuerySet
que no devuelven un
QuerySet
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
285
C.6.1. exact . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
286
C.6.2. iexact
286
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
C.6.3. contains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
286
C.6.4. icontains . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
286
287
C.6.6. in
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
287
C.6.7. startswith . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
287
C.6.8. istartswith
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
287
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
287
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
287
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
287
C.6.12. isnull . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
288
C.6.13. search . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
288
288
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
289
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
289
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
290
290
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
290
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
292
292
292
293
C.10.1. get_FOO_display()
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
293
293
C.10.3. get_FOO_lename()
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
294
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
294
C.10.4. get_FOO_url()
NDICE GENERAL
xii
C.10.5. get_FOO_size() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
294
294
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
C.11.1. get_object_or_404()
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
294
294
294
C.11.2. get_list_or_404() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
295
295
297
297
298
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
298
298
299
299
300
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
302
302
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
303
304
306
307
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
308
308
309
310
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
311
312
E. Variables de conguracin
313
313
E.1.1.
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
313
E.1.2.
313
E.1.3.
E.1.4.
E.1.5.
Seguridad . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
314
E.1.6.
314
. . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . .
314
314
314
E.2.1.
La utilidad django-admin.py
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
315
E.2.2.
En el servidor (mod_python) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
315
. . . . . . . . . . . . .
315
E.3.1.
. . . . . . . . . . . . . . . . . . . . . . .
316
E.3.2.
316
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
316
E.4.1.
ABSOLUTE_URL_OVERRIDES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
316
E.4.2.
ADMIN_FOR
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
316
E.4.3.
ADMIN_MEDIA_PREFIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
317
E.4.4.
ADMINS
E.4.5.
ALLOWED_INCLUDE_ROOTS
E.4.6.
APPEND_SLASH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
317
E.4.7.
CACHE_BACKEND
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
317
E.4.8.
CACHE_MIDDLEWARE_KEY_PREFIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
317
E.4.9.
DATABASE_ENGINE
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
317
317
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
317
E.4.10. DATABASE_HOST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
317
E.4.11. DATABASE_NAME
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
318
E.4.12. DATABASE_OPTIONS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
318
E.4.13. DATABASE_PASSWORD
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
318
E.4.14. DATABASE_PORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
318
E.4.15. DATABASE_USER . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
318
NDICE GENERAL
xiii
E.4.16. DATE_FORMAT
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
318
E.4.17. DATETIME_FORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
318
E.4.18. DEBUG . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
318
E.4.19. DEFAULT_CHARSET
319
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.4.20. DEFAULT_CONTENT_TYPE
E.4.21. DEFAULT_FROM_EMAIL
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
319
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
319
E.4.22. DISALLOWED_USER_AGENTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
319
E.4.23. EMAIL_HOST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
319
E.4.24. EMAIL_HOST_PASSWORD
E.4.25. EMAIL_HOST_USER
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
319
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
319
E.4.26. EMAIL_PORT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
319
E.4.27. EMAIL_SUBJECT_PREFIX
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
319
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
320
E.4.28. FIXTURE_DIRS
E.4.29. IGNORABLE_404_ENDS
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
320
E.4.30. IGNORABLE_404_STARTS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
320
E.4.31. INSTALLED_APPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
320
E.4.32. INTERNAL_IPS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
320
E.4.33. JING_PATH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
320
E.4.34. LANGUAGE_CODE
320
E.4.35. LANGUAGES
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
320
E.4.36. MANAGERS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
321
E.4.37. MEDIA_ROOT
321
E.4.38. MEDIA_URL
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
321
E.4.39. MIDDLEWARE_CLASSES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
321
E.4.40. MONTH_DAY_FORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
321
E.4.41. PREPEND_WWW
321
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.4.42. PROFANITIES_LIST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
322
E.4.43. ROOT_URLCONF
322
E.4.44. SECRET_KEY
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.4.45. SEND_BROKEN_LINK_EMAILS
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
322
322
E.4.46. SERIALIZATION_MODULES . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
322
E.4.47. SERVER_EMAIL
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
322
E.4.48. SESSION_COOKIE_AGE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
322
E.4.49. SESSION_COOKIE_DOMAIN
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
322
E.4.50. SESSION_COOKIE_NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
322
E.4.51. SESSION_COOKIE_SECURE
323
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.4.52. SESSION_EXPIRE_AT_BROWSER_CLOSE
. . . . . . . . . . . . . . . . . . . . . . . . . .
323
E.4.53. SESSION_SAVE_EVERY_REQUEST . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
323
E.4.54. SITE_ID
323
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
E.4.55. TEMPLATE_CONTEXT_PROCESSORS . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
323
E.4.56. TEMPLATE_DEBUG
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
323
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
323
E.4.58. TEMPLATE_LOADERS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
323
E.4.57. TEMPLATE_DIRS
E.4.59. TEMPLATE_STRING_IF_INVALID
E.4.60. TEST_RUNNER
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
324
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
324
E.4.61. TEST_DATABASE_NAME . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
324
E.4.62. TIME_FORMAT
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
324
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
324
E.4.63. TIME_ZONE
E.4.64. URL_VALIDATOR_USER_AGENT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
324
E.4.65. USE_ETAGS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
324
E.4.66. USE_I18N
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
325
E.4.67. YEAR_MONTH_FORMAT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
325
NDICE GENERAL
xiv
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
327
327
F.1.1.
block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
327
F.1.2.
comment
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
327
F.1.3.
cycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
327
F.1.4.
debug
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
328
F.1.5.
extends
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
328
F.1.6.
lter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
328
F.1.7.
rstof
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
328
F.1.8.
for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
328
F.1.9.
if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
F.1.10. ifchanged
329
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
330
F.1.11. ifequal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
330
F.1.12. ifnotequal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
330
F.1.13. include . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
331
F.1.14. load
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
331
F.1.15. now
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
F.1.16. regroup
331
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
333
F.1.17. spaceless . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
333
F.1.18. ssi
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
334
F.1.19. templatetag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
334
F.1.20. url . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
334
F.1.21. widthratio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
335
335
F.2.1.
add
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
335
F.2.2.
addslashes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
335
F.2.3.
caprst
F.2.4.
center
F.2.5.
cut . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
335
F.2.6.
date
336
F.2.7.
default . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
336
F.2.8.
default_if_none
336
F.2.9.
dictsort
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
335
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
335
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
336
F.2.10. dictsortreversed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
336
F.2.11. divisibleby . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
336
F.2.12. escape . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
336
F.2.13. lesizeformat
F.2.14. rst
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
337
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
337
F.2.15. x_ampersands
F.2.16. oatformat
F.2.17. get_digit
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
337
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
337
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
337
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
338
F.2.19. length . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
338
F.2.20. length_is
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
338
F.2.21. linebreaks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
338
F.2.18. join
F.2.22. linebreaksbr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
338
F.2.23. linenumbers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
338
F.2.24. ljust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
338
F.2.25. lower . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
338
F.2.26. make_list . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
339
F.2.27. phone2numeric . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
339
F.2.28. pluralize . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
339
F.2.29. pprint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
339
F.2.30. random
339
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
F.2.31. removetags
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
340
F.2.32. rjust . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
340
F.2.33. slice
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
340
F.2.34. slugify . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
340
NDICE GENERAL
xv
F.2.35. stringformat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
340
F.2.36. striptags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
340
F.2.37. time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
340
F.2.38. timesince
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
341
F.2.39. timeuntil
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
341
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
341
F.2.40. title
F.2.41. truncatewords . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
341
F.2.42. truncatewords_html . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
341
F.2.43. unordered_list
341
F.2.44. upper
F.2.45. urlencode
F.2.46. urlize
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
342
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
342
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
342
F.2.47. urlizetrunc
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
342
F.2.48. wordcount . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
342
F.2.49. wordwrap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
342
F.2.50. yesno
343
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
G. El utilitario django-admin
345
G.1. Uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
345
345
346
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
346
G.2.3. dbshell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
346
G.2.4. disettings
346
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
346
G.2.6. ush . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
346
G.2.7. inspectdb
346
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
347
348
348
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . .
348
G.2.12. shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
348
349
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
349
349
349
349
349
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
349
349
349
G.2.22. syncdb . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
349
G.2.23. test
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
G.2.24. validate
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
G.3.2. --pythonpath
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
350
350
350
350
350
G.3.3. --format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
350
G.3.4. --help
350
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
G.3.5. --indent
G.3.6. --noinput
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
350
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
351
G.3.7. --noreload . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
351
G.3.8. --version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
351
G.3.9. --verbosity . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
351
G.3.10. --adminmedia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
351
NDICE GENERAL
xvi
353
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
353
355
356
H.2. HttpResponse . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
357
357
357
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
358
358
359
359
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
361
Preliminares
Reconocimientos
El aspecto ms graticante de trabajar con Django es la comunidad. Hemos sido especialmente afortunados de que
Django haya atrado a tanta gente inteligente, motivada y amistosa. Un segmento de esa comunidad nos sigui durante
el lanzamiento online beta de este libro. Sus revisiones y comentarios fueron indispensables; este libro no hubiese
sido posible sin esa maravillosa revisin de pares. Casi mil personas dejaron comentarios que ayudaron a mejorar la
claridad, calidad y el ujo del libro nal. Queremos agradecer a todos y cada uno de ellos.
Estamos especialmente agradecidos con aquellos que dispusieron de su tiempo para revisar el libro en profundidad
y dejarnos decenas (a veces cientos) de comentarios: Marty Alchin, Max Battcher, Oliver Beattie, Rod Begbie, Paul
Bissex, Matt Boersma, Robbin Bonthond, Peter Bowyer, Nesta Campbell, Jon Colverson, Je Croft, Chris Dary, Alex
Dong, Matt Drew, Robert Dzikowski, Nick Eord, Ludvig Ericson, Eric Floehr, Brad Fults, David Grant, Simon Greenhill, Robert Haveman, Kent Johnson, Andrew Kember, Marek Kubica, Eduard Kucera, Anand Kumria, Scott Lamb,
Fredrik Lundh, Vadim Macagon, Markus Majer, Orestis Markou, R. Mason, Yasushi Masuda, Kevin Menard, Carlo
Miron, James Mulholland, R.D. Nielsen, Michael O'Keefe, Lawrence Oluyede, Andreas Pfrengle, Frankie Robertson,
Mike Robinson, Armin Ronacher, Daniel Roseman, Johan Samyn, Ross Shannon, Carolina F. Silva, Paul Smith, Bjrn
Stabell, Bob Stepno, Graeme Stevenson, Justin Stockton, Kevin Teague, Daniel Tietze, Brooks Travis, Peter Tripp,
Matthias Urlichs, Peter van Kampen, Alexandre Vassalotti, Jay Wang, Brian Will y Joshua Works.
Muchas gracias a nuestro editor tcnico, Jeremy Dunck. Sin Jeremy, este libro habra quedado en desorden, con
errores, inexactitudes y cdigo roto. Nos sentimos realmente afortunados de que alguien con el talento de Jeremy
encontrase el tiempo de ayudarnos.
Un especial agradecimiento a Simon Willison por escribir el captulo de procesamiento de formularios. Realmente
apreciamos la ayuda y nos enorgullece que la excelente redaccin de Simon pueda ser parte de este libro.
Estamos agradecidos por todo el duro trabajo que la gente de Apress hizo en este libro. Su ayuda y paciencia ha
sido asombrosa; este libro no habra quedado terminado sin todo ese trabajo de su parte. Nos pone especialmente
felices que Apress haya apoyado e incluso alentado el lanzamiento libre de este libro on line; es maravilloso ver a un
editor tan abrazado al espritu del open source.
Finalmente, por supuesto, gracias a nuestros amigos, familias y compaeros que gentilmente toleraron nuestra
ausencia mental mientras terminbamos este trabajo.
Jacob Kaplan-Moss es uno de los principales desarrolladores de Django. En su empleo diurno, es el desarrollador
principal para el Lawrence Journal-World, un peridico de dueos locales en Lawrence, Kansas, donde Django fue
desarrollado. En el Journal-World, supervisa el desarrollo de Ellington, una plataforma de publicacin online de
noticias para compaas de medios de comunicacin. A Jacob se lo puede encontrar online en jacobian.org.
NDICE GENERAL
xviii
http://humitos.homelinux.net/django-book.
Sobre el libro
Ests leyendo El libro de Django, publicado en Diciembre de 2007 por Apress con el ttulo The Denitive Guide
to Django: Web Development Done Right.
Hemos lanzado este libro libremente por un par de razones. La primera es que amamos Django y queremos que sea
tan accesible como sea posible. Muchos programadores aprenden su arte desde material tcnico bien escrito, as que
nosotros intentamos escribir una gua destacada que sirva adems como referencia para Django.
La segunda, es que resulta que escribir libros sobre tecnologa es particularmente difcil: sus palabras se vuelven
anticuadas incluso antes de que el libro llegue a la imprenta. En la web, sin embargo, la tinta nunca se seca -podremos mantener este libro al da (y as lo haremos) --.
La respuesta de los lectores es una parte crtica de ese proceso. Hemos construido un sistema de comentarios que
te dejar comentar sobre cualquier parte del libro; leeremos y utilizaremos estos comentarios en nuevas versiones.
Introduccin
Al comienzo, los desarrolladores web escriban cada una de las pginas a mano. Actualizar un sitio web signicaba
editar HTML; un rediseo implicaba rehacer cada una de las pginas, una por vez.
Como los sitios web crecieron y se hicieron ms ambiciosos, rpidamente se hizo obvio que esta situacin era tediosa,
consuma tiempo y al nal era insostenible. Un grupo de emprendedores del NCSA (Centro Nacional de Aplicaciones
para Supercomputadoras, donde Mosaic, el primer navegador web grco, fue desarrollado) solucion este problema
permitiendo que el servidor web invocara programas externos capaces de generar HTML dinmicamente. Ellos llamaron
a este protocolo Puerta de Enlace Comn, o CGI
Ahora es duro imaginar la revelacin que CGI debe haber sido: en vez de tratar con pginas HTML como simples
archivos del disco, CGI te permite pensar en pginas como recursos generados dinmicamente bajo demanda. El
desarrollo de CGI hace pensar en la primera generacin de pgina web dinmicas.
Sin embargo, CGI tiene sus problemas: los scripts CGI necesitan contener gran cantidad de cdigo repetitivo que
los hace difcil de reutilizar, as como complicados de entender y escribir para los desarrolladores novatos.
PHP solucion varios de estos problemas y tom al mundo por sorpresa --ahora es, por lejos, la herramienta ms
popular usada para crear sitios web dinmicos, y decenas de lenguajes y entornos similares (ASP, JSP, etc.) siguieron
de cerca el diseo de PHP. La mayor innovacin de PHP es que es fcil de usar: el cdigo PHP es simple de embeber
en un HTML plano; la curva de aprendizaje para algunos que recin conocen HTML es extremadamente llana.
Pero PHP tiene sus propios problemas; por su facilidad de uso alienta a la produccin de cdigo mal hecho. Lo
que es peor, PHP hace poco para proteger a los programadores en cuanto a vulnerabilidades de seguridad, por lo que
muchos desarrolladores de PHP se encontraron con que tenan que aprender sobre seguridad cuando ya era demasiado
tarde.
Estas y otras frustraciones similares, condujeron directamente al desarrollo de los actuales frameworks de desarrollo
web de tercera generacin. Estos frameworks -- Django y Ruby on Rails parecen ser muy populares en estos das
-- reconocen que la importancia de la web se ha intensicado en los ltimos tiempos. Con esta nueva explosin del
desarrollo web comienza otro incremento en la ambicin; se espera que los desarrolladores web hagan ms y ms cada
da.
Django fue inventado para satisfacer esas nuevas ambiciones. Django te permite construir en profundidad, de
forma dinmica, sitios interesantes en un tiempo extremadamente corto. Django est diseado para hacer foco en la
diversin, en las partes interesantes de tu trabajo, al mismo tiempo que alivia el dolor de las partes repetitivas. Al
hacerlo, proporciona abstracciones de alto nivel de patrones comunes del desarrollo web, atajos para tareas frecuentes
de programacin y claras convenciones sobre cmo resolver problemas. Al mismo tiempo, Django intenta mantenerse
fuera de tu camino, dejando que trabajes fuera del alcance del framework cuando es necesario. Escribimos este libro
porque creemos rmemente que Django mejora el desarrollo web. Est diseado para poner rpidamente en movimiento
tu propio proyecto de Django, en ltima instancia aprenders todo lo que necesites saber para producir un diseo,
desarrollo y despliegue de sitios satisfactorios y de los cuales te sientas orgulloso.
Estamos extremadamente interesados en la retroalimentacin. La versin online de este libro te permite dejar
un comentario en cualquier parte del libro y discutir con otros lectores. Hacemos cuanto podemos para leer todos
los comentarios posteados all y responder tantos como sea posible. Si preeres utilizar correo electrnico, por favor
envanos unas lneas (en ingls) a [email protected]. De cualquier modo, nos encantara escucharte! Nos
alegra que ests aqu, y esperamos que encuentres a Django tan emocionante, divertido y til como nosotros.
1 N.
Captulo 1
Introduccin a Django
Este libro es sobre Django, un framework de desarrollo Web que ahorra tiempo y hace que el desarrollo Web sea
divertido. Utilizando Django puedes crear y mantener aplicaciones Web de alta calidad con un mnimo esfuerzo.
En el mejor de los casos, el desarrollo web es un acto entretenido y creativo; en el peor, puede ser una molestia
repetitiva y frustrante. Django te permite enfocarte en la parte divertida -- el quid de tus aplicaciones Web -- al
mismo tiempo que mitiga el esfuerzo de las partes repetitivas. De esta forma, provee un alto nivel de abstraccin de
patrones comunes en el desarrollo Web, atajos para tareas frecuentes de programacin y convenciones claras sobre
cmo solucionar problemas. Al mismo tiempo, Django intenta no entrometerse, dejndote trabajar fuera del mbito
del framework segn sea necesario.
El objetivo de este libro es convertirte en un experto de Django. El enfoque es doble. Primero, explicamos en
profundidad lo que hace Django, y cmo crear aplicaciones Web con l. Segundo, discutiremos conceptos de alto nivel
cuando se considere apropiado, contestando la pregunta Cmo puedo aplicar estas herramientas de forma efectiva en
mis propios proyectos? Al leer este libro, aprenders las habilidades necesarias para desarrollar sitios Web poderosos
de forma rpida, con cdigo limpio y de fcil mantenimiento.
En este captulo ofrecemos una visin general de Django.
1.1.
Qu es un Framework Web?
Django es un miembro importante de una nueva generacin de frameworks Web. Y qu signica ese trmino
exactamente?
Para contestar esa pregunta, consideremos el diseo de una aplicacin Web escrita usando el estndar Common
Gateway Interface (CGI), una forma popular de escribir aplicaciones Web alrededor del ao 1998. En esa poca, cuando
escribas una aplicacin CGI, hacas todo por ti mismo -- el equivalente a hacer una torta desde cero --. Por ejemplo,
aqu hay un script CGI sencillo, escrito en Python, que muestra los diez libros ms recientemente publicados de una
base de datos:
#!/usr/bin/python
import MySQLdb
print
print
print
print
print
print
"Content-Type: text/html"
"<html><head><title>Libros</title></head>"
"<body>"
"<h1>Los ultimos 10 libros</h1>"
"<ul>"
print "</body></html>"
conexion.close()
Este cdigo es fcil de entender. Primero imprime una lnea de Content-Type, seguido de una lnea en blanco, tal
como requiere CGI. Imprime HTML introductorio, se conecta a la base de datos y ejecuta una consulta que obtiene los
diez libros ms recientes. Hace un bucle sobre esos libros y genera una lista HTML desordenada. Finalmente imprime
el cdigo para cerrar el HTML y cierra la conexin con la base de datos.
Con una nica pgina dinmica como esta, el enfoque desde cero no es necesariamente malo. Por un lado, este
cdigo es sencillo de comprender -- incluso un desarrollador novato puede leer estas 16 lneas de Python y entender
todo lo que hace, de principio a n --. No hay ms nada que aprender; no hay ms cdigo para leer. Tambin es sencillo
de utilizar: tan slo guarda este cdigo en un archivo llamado
ultimoslibros.cgi,
1.2.
Comencemos con un rpido ejemplo que demuestra la diferencia entre el enfoque anterior y el empleado al usar un
framework Web. As es como se podra escribir el cdigo CGI anterior usando Django:
models.py contiene una descripcin de la tabla de la base de datos, como una clase Python.
El archivo
A esto se lo llama el modelo. Usando esta clase se pueden crear, buscar, actualizar y borrar entradas
de tu base de datos usando cdigo Python sencillo en lugar de escribir declaraciones SQL repetitivas.
El archivo
la denomina vista.
El archivo
/latest/
El archivo
urls.py
latest_books.html
latest_books().
Tomadas en su conjunto, estas piezas se aproximan al patrn de diseo Modelo-Vista-Controlador (MVC). Dicho
de manera ms fcil, MVC dene una forma de desarrollar software en la que el cdigo para denir y acceder a los
datos (el modelo) est separado del pedido lgico de asignacin de ruta (el controlador), que a su vez est separado
de la interfaz del usuario (la vista).
Una ventaja clave de este enfoque es que los componentes tienen un acoplamiento dbil (N. de T.: por loosely
coupled ) entre s. Eso signica que cada pieza de la aplicacin Web que funciona sobre Django tiene un nico propsito
clave, que puede ser modicado independientemente sin afectar las otras piezas. Por ejemplo, un desarrollador puede
cambiar la URL de cierta parte de la aplicacin sin afectar la implementacin subyacente. Un diseador puede cambiar
el HTML de una pgina sin tener que tocar el cdigo Python que la renderiza. Un administrador de base de datos
puede renombrar una tabla de la base de datos y especicar el cambio en un nico lugar, en lugar de tener que buscar
y reemplazar en varios archivos.
En este libro, cada componente tiene su propio captulo. Por ejemplo, el Captulo 3 trata sobre las vistas, el
Captulo 4 sobre las plantillas, y el Captulo 5 sobre los modelos. El Captulo 5 profundiza tambin en la losofa MVC
de Django.
1.3.
La historia de Django
Antes de continuar con ms cdigo, deberamos tomarnos un momento para explicar la historia de Django. Es til
entender por qu se cre el framework, ya que el conocimiento de la historia pone en contexto la razn por la cual
Django trabaja de la forma en que lo hace.
Si has estado creando aplicaciones Web por un tiempo, probablemente ests familiarizado con los problemas del
ejemplo CGI presentado con anterioridad. El camino clsico de un desarrollador Web es algo como esto:
1. Escribir una aplicacin Web desde cero.
World, Adrian Holovaty y Simon Willison, comenzaron a usar Python para crear sus aplicaciones. El equipo de
The World Online, responsable de la produccin y mantenimiento de varios sitios locales de noticias, prosperaban
en un entorno de desarrollo dictado por las fechas lmite del periodismo. Para los sitios -- incluidos LJWorld.com,
Lawrence.com y KUsports.com -- los periodistas (y los directivos) exigan que se agregaran nuevas caractersticas y
que aplicaciones enteras se crearan a una velocidad vertiginosa, a menudo con slo das u horas de preaviso. Es as que
Adrian y Simon desarrollaron por necesidad un framework de desarrollo Web que les ahorrara tiempo -- era la nica
forma en que podan crear aplicaciones mantenibles en tan poco tiempo -- .
En el verano boreal de 2005, luego de haber desarrollado este framework hasta el punto en que estaba haciendo
funcionar la mayora de los sitios World Online, el equipo de World Online, que ahora inclua a Jacob Kaplan-Moss,
decidi liberar el framework como software de cdigo abierto. Lo liberaron en julio de 2005 y lo llamaron Django, por
el guitarrista de jazz Django Reinhardt.
A pesar de que Django ahora es un proyecto de cdigo abierto con colaboradores por todo el mundo, los desarrolladores originales de World Online todava aportan una gua centralizada para el crecimiento del framework, y
World Online colabora con otros aspectos importantes tales como tiempo de trabajo, materiales de marketing, y
hosting/ancho de banda para el Web site del framework (http://www.djangoproject.com/).
Esta historia es relevante porque ayuda a explicar dos cuestiones clave. La primera es el punto dulce de Django.
Debido a que Django naci en un entorno de noticias, ofrece varias caractersticas (en particular la interfaz admin,
tratada en el Captulo 6) que son particularmente apropiadas para sitios de contenido -- sitios como eBay, craigslist.org
y washingtonpost.com que ofrecen informacin basada en bases de datos --. (De todas formas, no dejes que eso te quite
las ganas -- a pesar de que Django es particularmente bueno para desarrollar esa clase de sitios, eso no signica que
no sea una herramienta efectiva para crear cualquier tipo de sitio Web dinmico --. Existe una diferencia entre ser
1.4.
Al escribir este libro, tratamos de alcanzar un balance entre legibilidad y referencia, con una tendencia a la
legibilidad. Nuestro objetivo con este libro, como se mencion anteriormente, es hacerte un experto en Django, y
creemos que la mejor manera de ensear es a travs de la prosa y numerosos ejemplos, en vez de proveer un exhaustivo
pero intil catlogo de las caractersticas de Django (Como alguien dijo una vez, no puedes esperar ensearle a alguien
cmo hablar simplemente ensendole el alfabeto).
Con eso en mente, te recomendamos que leas los captulos del 1 al 7 en orden. Ellos forman los fundamentos de
cmo se usa Django; una vez que los hayas ledo, sers capaz de construir sitios Web que funcionan sobre Django. Los
captulos restantes, los cuales se enfocan en caractersticas especcas de Django, pueden ser ledos en cualquier orden.
Los apndices son para referencia. Ellos, junto con la documentacin libre en
http://www.djangoproject.com/,
son probablemente lo que releers de vez en cuando para recordar la sintaxis o buscar un resumen rpido de lo que
hacen ciertas partes de Django.
1.5. QU SIGUE?
1.4.1.
Los lectores de este libro deben comprender las bases de la programacin orientada a objetos e imperativa: estruc-
while
for),
La experiencia en desarrollo Web es, como podrs esperar, muy til, pero no es requisito para leer este libro. A
lo largo del mismo, tratamos de promover las mejores prcticas en desarrollo Web para los lectores a los que les falta
este tipo de experiencia.
1.4.2.
En esencia, Django es sencillamente una coleccin de bibliotecas escritas en el lenguaje de programacin Python.
Para desarrollar un sitio usando Django escribes cdigo Python que utiliza esas bibliotecas. Aprender Django, entonces,
es slo cuestin de aprender a programar en Python y comprender cmo funcionan las bibliotecas Django.
Si tienes experiencia programando en Python, no deberas tener problema en meterte de lleno. En conjunto, el
cdigo Django no produce magia negra (es decir, trucos de programacin cuya implementacin es difcil de explicar
o entender). Para ti, aprender Django ser slo cuestin de aprender las convenciones y APIs de Django.
Si no tienes experiencia programando en Python, te espera una grata sorpresa. Es fcil de aprender y muy divertido
de usar. A pesar de que este libro no incluye un tutorial completo de Python, s hace hincapi en las caractersticas y
funcionalidades de Python cuando se considera apropiado, particularmente cuando el cdigo no cobra sentido de inme-
http://pyspanishdoc.sourceforge.
http://docs.python.org/tut/. Tambin recomendamos
Python, disponible en http://es.diveintopython.org/ y
net/tut/tut.html
1.4.3.
Tal como hicimos notar anteriormente, Django es mejorado con frecuencia, y probablemente tendr un gran nmero
de nuevas -- e incluso esenciales -- caractersticas para cuando este libro sea publicado. Por ese motivo, nuestro objetivo
como autores de este libro es doble:
Asegurarnos que este libro sea a prueba de tiempo tanto como nos sea posible, para que cualquier
cosa que leas aqu todava sea relevante en futuras versiones de Django.
Actualizar este libro continuamente en el sitio Web en ingls,
http://www.djangobook.com/,
para
que puedas acceder a la mejor y ms reciente documentacin tan pronto como la escribimos.
Si quieres implementar con Django algo que no est explicado en este libro, revisa la versin ms reciente de este
libro en el sitio Web antes mencionado y tambin revisa la documentacin ocial de Django.
1.4.4.
Obteniendo ayuda
Uno de los mayores benecios de Django es su comunidad de usuarios amable y servicial. Para ayuda con cualquier
aspecto de Django -- desde instalacin y diseo de aplicaciones, hasta diseo de bases de datos e implementaciones -sintete libre de hacer preguntas online.
En la lista de correo en ingls de usuarios de Django se juntan miles de usuarios para preguntar
http://www.djangoproject.com/r/django-users
http://groups.google.es/group/django-es (espaol).
El canal de IRC de Django donde los usuarios de Django se juntan a chatear y se ayudan unos a otros
en tiempo real. nete a la diversin en #django (ingls) o #django-es (espaol) en la red de IRC
Freenode.
1.5.
Qu sigue?
Captulo 2
Empezando
Creemos que es mejor empezar con fuerza. En los captulos que le siguen a este descubrirs los detalles y el alcance
del framework Django, pero por ahora, confa en nosotros, este captulo es divertido.
Instalar Django es fcil. Django se puede usar en cualquier sistema que corra Python, por eso es posible instalarlo
de varias maneras. En este captulo explicamos las situaciones ms comunes de instalacin de Django. El Captulo 20
explica como utilizar Django en produccin.
2.1.
Instalar Python
Django est escrito 100 % en puro cdigo Python, as que necesitars instalar Python en tu computadora. Django
necesita Python 2.3 o superior.
Si ests usando Linux o Mac OS X probablemente ya tienes Python instalado. Escribe
python
en una terminal. Si
Si ves un error como: "command not found" u "orden no encontrada", tienes que bajar e instalar Python. Fjate
http://www.python.org/download/ para empezar. La instalacin es rpida y fcil.
2.2.
Instalar Django
En esta seccin explicamos dos opciones de instalacin: instalar un lanzamiento ocial e instalar desde Subversion.
2.2.1.
download/.
distutils
http://www.djangoproject.com/
3.
cd Django-*
4.
En Windows, recomendamos usar 7-Zip para manejar archivos comprimidos de todo tipo, incluyendo
http://www.djangoproject.com/r/7zip/.
otro directorio e inicia python. Si todo est funcionando
.tar.gz.
django:
CAPTULO 2. EMPEZANDO
Nota
El intrprete interactivo de Python es un programa de lnea de comandos que te permite escribir
un programa Python de forma interactiva. Para iniciarlo slo ejecuta el comando
python
en la
lnea de comandos. Durante todo este libro, mostraremos ejemplos de cdigo Python como si
estuviesen escritos en el intrprete interactivo. El triple signo de mayor que (>>>) es el prompt de
Python.
2.2.2.
Si quieres trabajar sobre la versin de desarrollo, o si quieres contribuir con el cdigo de Django en s mismo,
deberas instalar Django desde el repositorio de Subversion.
Subversion es libre, es un sistema de control de versiones de cdigo abierto similar a CVS, y es el que el equipo de
Django utiliza para administrar cambios en el cdigo base de Django. Puedes utilizar un cliente de Subversion para
hacerte con el cdigo fuente ms actual de Django y, en cualquier momento, puedes actualizar tu copia local del cdigo
de Django, conocido como un checkout local, para obtener los ltimos cambios y mejoras hechas por los desarrolladores
de Django.
Al ltimo cdigo de desarrollo de Django se hace referencia como el trunk. El equipo de Django ejecuta sitios de
produccin sobre el trunk y procura permanecer estable.
Para obtener el trunk de Django, sigue los siguientes pasos:
1. Asegrate de tener un cliente de Subversion instalado. Puedes conseguir este programa libremente
desde http://subversion.tigris.org/, y puedes encontrar documentacin excelente en http:
//svnbook.red-bean.com/.
djtrunk.
3. Crea
svn co http://code.djangoproject.com/svn/django/trunk
agregando
4. Incluye
djtrunk/django/bin en el PATH
django-admin.py.
administracin como
Consejo:
Si los archivo
aprender ms de ellos en
http://www.
Luego de descargarlo desde Subversion y haber seguido los pasos anteriores, no necesitas ejecutar
install
python setup.py
Debido a que el trunk de Django cambia a menudo corrigiendo bugs y agregando funcionalidades, probablemente
quieras actualizarlo con frecuencia -- a cada hora, si eres un obsesivo. Para actualizar el cdigo, solo ejecuta el
svn update desde el directorio djtrunk. Cuando ejecutes este comando, Subversion contactar http://
code.djangoproject.com, determinar si el cdigo ha cambiado, y actualizar tu versin local del cdigo con cualquier
comando
2.3.
El nico prerequisito de Django es una instalacin funcionando de Python. Sin embargo, este libro se centra en una
de las mejores funcionalidades de Django, el desarrollo de sitios web con soporte de base de datos, para esto necesitars
instalar un servidor de base de datos de algn tipo, para almacenar tus datos.
Si slo quieres comenzar a jugar con Django, salta a la seccin Comenzando un proyecto -- pero crenos, querrs
instalar una base de datos nalmente. Todos los ejemplos de este libro asumen que tienes una base de datos congurada.
Hasta el momento de escribir esto, Django admite tres motores de base de datos:
PostgreSQL (http://www.postgresql.org/)
SQLite 3 (http://www.sqlite.org/)
MySQL (http://www.mysql.com/)
Se est trabajando para admitir Microsoft SQL Server y Oracle. El sitio web de Django siempre contendr la ltima
informacin acerca de las base de datos admitidas.
A nosotros el que ms nos gusta es PostgreSQL, por razones que exceden el alcance de este libro, por eso lo
mencionamos primero. Sin embargo, todos los motores que listamos aqu trabajan bien con Django.
SQLite merece especial atencin como herramienta de desarrollo. Es un motor de base de datos extremadamente
simple y no requiere ningn tipo de instalacin y conguracin del servidor. Es por lejos el ms fcil de congurar si
slo quieres jugar con Django, y viene incluido en la biblioteca estndar de Python 2.5.
En Windows, obtener los drivers binarios de la base de datos es a veces un proceso complicado. Ya que slo ests
inicindote en Django, recomendamos usar Python 2.5 y el soporte incluido para SQLite. La compilacin de drivers
puede ser estresante.
2.3.1.
r/python-pgsql/.
psycopg
disponible en
http://www.djangoproject.com/
Toma nota de la versin que ests usando (1 o 2); necesitars esta informacin luego.
//www.djangoproject.com/r/python-pgsql/windows/.
2.3.2.
psycopg
en
http:
Si ests usando una versin de Python igual o posterior a 2.5, ya tienes SQLite. Si ests trabajando con Python
http://www.djangoproject.com/r/sqlite/ y el paquete
http://www.djangoproject.com/r/python-sqlite/. Asegrate de tener pysqlite en una versin
pysqlite
desde
2.0.3 o superior.
En Windows, puedes omitir la instalacin separada de los binarios de SQLite, ya que estn enlazados dentro de los
binarios de
2.3.3.
pysqlite.
Django requiere MySQL 4.0 o superior; la versin 3.x no admite subconsultas anidadas ni algunas otras sentencias
SQL perfectamente estndar. Tambin necesitas instalar el paquete
r/python-mysql/.
2.3.4.
Como mencionamos anteriormente, Django actualmente no requiere una base de datos. Si slo quieres usar este
como un servidor dinmico de pginas que no use una base de datos, est perfectamente bien.
Con esto dicho, ten en cuenta que algunas de las herramientas extras de Django requieren una base de datos, por lo
tanto si eliges no usar una base de datos, perders estas utilidades. (Sealaremos estas utilidades a lo largo del libro).
2.4.
Comenzando un proyecto
Un proyecto es una coleccin de conguraciones para una instancia de Django, incluyendo conguracin de base
de datos, opciones especcas de Django y conguraciones especcas de aplicaciones.
Si esta es la primera vez que usas Django, tendrs que tener cuidado de algunas conguraciones iniciales. Crea un
nuevo directorio para empezar a trabajar, quizs algo como
/home/username/djcode/,
Nota
actual.
Echemos un vistazo a lo que
startproject
cre:
mysite
en el directorio
10
CAPTULO 2. EMPEZANDO
mysite/
__init__.py
manage.py
settings.py
urls.py
Estos archivos son los siguientes:
__init__.py:
Un archivo requerido para que Python trate a este directorio como un paquete (i.e. un
grupo de mdulos).
manage.py:
Una utilidad de lnea de comandos que te deja interactuar con este proyecto de Django
de varias formas.
tabla de contenidos de tu
/var/www). Con Django, no tienes que hacer esto. No es una buena idea poner
cualquier cdigo Python en la carpeta raz del servidor web, porque al hacerlo se arriesga a que
la gente sea capaz de ver el cdigo en la web. Esto no es bueno para la seguridad.
Pon tu cdigo en algn directorio
2.4.1.
El servidor de desarrollo
Django incluye un servidor web ligero que puedes usar mientras ests desarrollando tu sitio. Incluimos este servidor
para que puedas desarrollar tu sitio rpidamente, sin tener que lidiar con conguraciones de servidores web de produccin (i.e., Apache) hasta que ests listo para la produccin. Este servidor de desarrollo vigila tu cdigo a la espera
de cambios y se reinicia automticamente, ayudndote a hacer algunos cambios rpidos en tu proyecto sin necesidad
de reiniciar nada.
Entra en el directorio
mysite,
Vers
Validating models...
0 errors found.
Django version 1.0, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Aunque el servidor de desarrollo es extremadamente til para, bueno, desarrollar, resiste la tentacin de usar este
servidor en cualquier entorno parecido a produccin. El servidor de desarrollo puede manejar ablemente una sola
peticin a la vez, y no ha pasado por una auditora de seguridad de ningn tipo. Cuando sea el momento de lanzar tu
sitio, mira el Captulo 20 para informacin sobre cmo hacerlo con Django.
slo conexiones locales. Si quieres cambiar el puerto del servidor, pasa este como un argumento
de lnea de comandos:
2.5. QU SIGUE?
2.5.
11
Qu sigue?
12
CAPTULO 2. EMPEZANDO
Captulo 3
3.1.
Lo primero que haremos es crear una pgina web que muestre la fecha y la hora actual. Este es un buen ejemplo
de una pgina dinmica, porque el contenido de la misma no es esttico -- al contrario, los contenidos cambian de
acuerdo con el resultado de un clculo (en este caso, el clculo de la hora actual). Este simple ejemplo no involucra
una base de datos cualquier tipo de entrada del usuario, slo muestra la salida del reloj interno del servidor.
Para crear esta pgina, crearemos una funcin de vista. Una funcin de vista, o vista en pocas palabras, es una
simple funcin de Python que toma como argumento una peticin Web y retorna una respuesta Web. Esta respuesta
puede ser el contenido HTML de la pgina web, una redireccin, o un error 404, o un documento XML, o una imagen...
o en realidad, cualquier cosa. La vista en s contiene toda la lgica necesaria para retornar esa respuesta. El cdigo
puede encontrarse donde quieras, mientras que se encuentre dentro de tu Python path. No hay otro requerimiento
-- no hay magia, por as decirlo. Por poner el cdigo en algn lugar, creemos un archivo llamado
directorio
mysite,
views.py
en el
Esta es la vista que retorna la fecha y hora actual, como un documento HTML:
datetime
datetime
con fechas y horas, incluyendo una funcin que retorna la hora actual.
A continuacin, denimos la funcin llamada
request.
Nota que el nombre de la funcin de vista no importa; no tiene que ser nombrada de una determinada
repugnante. A Django no le interesa. La siguiente seccin explica cmo Django encuentra esta funcion.
La primera lnea de cdigo dentro de la funcin calcula la fecha/hora actual, como un objeto
y almacena el resultado en la variable local
now.
datetime.datetime,
14
La segunda lnea de cdigo dentro de la funcin construye la respuesta HTML usando el formato de
3.2.
Repasemos, esta funcin de vista retorna un pgina HTML que contiene la fecha y hora actual. Pero cmo le
decimos a Django que utilice ese cdigo?. Ah es donde vienen las URLconfs.
Una URLconf es como una tabla de contenido para tu sitio web hecho con Django. Bsicamente, es un mapeo entre
los patrones URL y las funciones de vista que deben ser llamadas por esos patrones URL. Es como decirle a Django,
Para esta URL, llama a este cdigo, y para esta URL, llama a este otro cdigo. Recuerda que estas funciones de
vista deben estar en tu Python path.
Python Path
Python path es la lista de directorios en tu sistema en donde Python buscar cuando uses la
sentencia
import
de Python.
supongamos
que
tu
Python
path
tiene
el
valor
['',
'/usr/lib/python2.4/site-packages', '/home/username/djcode/']. Si ejecutas el
cdigo Python from foo import bar, Python en primer lugar va a buscar el mdulo llamado
foo.py en el directorio actual. (La primera entrada en el Python path, una cadena de caracteres
Por
ejemplo,
vaca, signica el directorio actual.) Si ese archivo no existe, Python va a buscar el mdulo
/usr/lib/python2.4/site-packages/foo.py.
/home/username/djcode/foo.py. Finalmente,
ImportError
en
en
Si ests interesado en ver el valor de tu Python path, abre un interprete interactivo de Python y
escribe
import sys,
seguido de
print sys.path.
Generalmente no tienes que preocuparte de asigarle valores al Python path -- Python y Django se
encargan automticamente de hacer esas cosas por ti entre bastidores. (Si eres curioso, establecer
el Python path es una de las cosas que hace el archivo
Cuando ejecutaste
manage.py).
patterns.
django.conf.urls.defaults, incluyendo
15
urlpatterns.
La funcin
patterns()
patterns()
El resto de las lneas estn comentadas. (La cadena de caracteres puede ser usada para proveer un
prejo comn para las funciones de vista, pero dejemos este uso ms avanzado para ms adelante).
Lo principal que debemos notar aqu es la variable
ROOT_URLCONF.
urlpatterns,
Esta variable dene el mapeo entre las URLs y el cdigo que manejan esas URLs.
Por defecto, todo lo que est en URLconf est comentado -- tu aplicacin de Django es una pizarra blanca. (Como
nota adicional, esta es la forma en la que Django saba que deba mostrar la pgina It worked! en el captulo anterior.
Si la URLconf esta vaca, Django asume que acabas de crear el proyecto, por lo tanto, muestra ese mensaje).
Editemos este archivo para exponer nuestra vista
current_datetime:
current_datetime),.
Esta lnea hace referencia a un URLpattern -- es una tupla de Python en dnde el primer
elemento es una expresin regular simple y el segundo elemento es la funcin de vista que usa para ese patrn.
En pocas palabras, le estamos diciendo a Django que cualquier peticin a la URL
funcin de vista
current_datetime.
/time
current_datetime
llamar a la funcin. Esto es una caracterstica de Python (y otros lenguajes dinmicos): las funciones
son objetos de primera clase, lo cual signica que puedes pasarlas como cualquier otra variable. Qu
bueno!, no?
La
en
r'^time/$'
signica que
'^time/$
permite que las expresiones regulares sean escritas sin demasiadas sentencias de escape.
Puedes excluir la barra al comienzo de la expresin
automticamente agrega una barra antes de toda expresin. A primera vista esto parece raro, pero
una URLconf puede ser incluida en otra URLconf, y el dejar la barra de lado simplica mucho las
cosas. Esto se retoma en el Captulo 8.
El caracter acento circunejo (^) y el carcter signo de dlar ($) son importantes. El acento circunejo
signica que requiere que el patrn concuerde con el inicio de la cadena de caracteres, y el signo de
dlar signica que exige que el patrn concuerde con el n de la cadena.
Este concepto se explica mejor con un ejemplo. Si hubiramos utilizado el patrn
el signo de dlar al nal), entonces cualquier URL que comience con
/time/foo
/time/bar,
no slo
/time/.
time/
'^time/'
circunejo inicial ('time/$'), Django concordara con cualquier URL que termine con
como
/foo/bar/time/.
(sin
concordara, as como
time/,
as
Por lo tanto, usamos tanto el acento circunejo como el signo de dlar para
/time/
python manage.py runserver. (Si ya lo tenas corriendo, est bien tambin. El servidor de
desarrollo automticamente detecta los cambios en tu cdigo de Python y recarga de ser necesario, as no tienes que
reiniciar el servidor al hacer cambios). El servidor est corriendo en la direccin
abre tu navegador web y ve a
http://127.0.0.1:8000/time/.
http://127.0.0.1:8000/,
entonces
16
Expresiones Regulares
Las Expresiones Regulares (o regexes ) son la forma compacta de especicar patrones en un texto.
Aunque las URLconfs de Django permiten el uso de regexes arbitrarias para tener un potente
sistema de denicin de URLs, probablemente en la prctica no utilices ms que un par de
patrones regex. Esta es una pequea seleccin de patrones comunes:
Smbolo
Coincide con
. (punto)
\d
[A-Z]
[a-z]
[A-Za-z]
+
[^/]+
*
{1,3}
Cualquier carcter
Cualquier dgito
Cualquier carcter, A-Z (maysculas)
Cualquier carcter, a-z (minsculas)
Cualquier carcter, a-z (no distingue entre mayscula y minscula)
Una o ms ocurrencias de la expresin anterior (ejemplo,
djangoproject.com/r/python/re-module/.
3.3.
http://www.
Debemos sealar varias cosas en lo que hemos visto. Este es el detalle de lo que sucede cuando ejecutas el servidor
de desarrollo de Django y hacemos una peticin a una pgina Web.
El comando
settings.py
desde el mis-
mo directorio. Este archivo contiene todo tipo de conguraciones opcionales para esta instancia de
Django en particular, pero una de las conguraciones ms importantes es
ROOT_URLCONF
ROOT_URLCONF.
La variable
le dice a Django qu mdulo de Python debera usar para la URLconf de este sitio
Web.
Recuerdas cuando
el
settings.py
automticamente. Qu conveniente!
Cuando llega una peticin-- digamos, una peticin a la URL
apuntada por la variable
ROOT_URLCONF.
/time/
URLconf en orden, comparando la URL solicitada con un patrn a la vez, hasta que encuentra uno
que coincida. Cuando encuentra uno que coincide, llama a la funcin de vista asociada con ese patrn,
pasando un objeto
luego).
La funcin de vista es responsable de retornar un objeto
HttpResponse.
Conoces ahora lo bsico sobre cmo hacer pginas Web con Django. Es muy sencillo, realmente -- slo tenemos
que escribir funciones de vista y relacionarlas con URLs mediante URLconfs. Podras pensar que es lento enlazar las
URL con funciones usando una serie de expresiones regulares, pero te sorprenders.
3.3.1.
Adems del mapeo directo de URLs con funciones vista que acabamos de describir, Django nos provee un poco
ms de exibilidad en el procesamiento de peticiones.
El ujo tpico -- resolucin de URLconf a una funcin de vista que retorna un
circuitado o
HttpResponse--
*augmented* mediante middleware. Los secretos del middleware sern tratados en profundidad en el
Captulo 15, pero un esquema (ver Figura 3-1) te ayudar conceptualmente a poner todas las piezas juntas.
17
18
Cuando llega una peticin HTTP desde el navegador, un manejador especco a cada servidor construye la
HttpRequest,
El manejador luego llama a cualquier middleware de Peticin o Vista disponible. Estos tipos de middleware son
tiles para
HttpRequest
HttpResponse
la vista no es invocada.
Hasta a los mejores programadores se le escapan errores (bugs ), pero el middleware de excepcin ayuda a aplastarlos.
Si una funcin de vista lanza una excepcin, el control pasa al middleware de Excepcin. Si este middleware no retorna
un
HttpResponse,
Sin embargo, no todo est perdido. Django incluye vistas por omisin para respuestas amigables a errores 404 y
500.
Finalmente, el middleware de respuesta es bueno para el procesamiento posterior a un
HttpResponse
justo antes
de que se enve al navegador o haciendo una limpieza de recursos especcos a una peticin.
3.4.
Ahora es el momento de resaltar una parte clave de losofa detrs de las URLconf y detrs de Django en general:
el principio de acoplamiento dbil (loose coupling ). Para explicarlo simplemente, el acoplamiento dbil es una manera
de disear software aprovechando el valor de la importancia de que se puedan cambiar las piezas. Si dos piezas de
cdigo estn dbilmente acopladas (loosely coupled ) los cambios realizados sobre una de dichas piezas va a tener poco
o ningn efecto sobre la otra.
Las URLconfs de Django son un claro ejemplo de este principio en la prctica. En una aplicacin Web de Django,
la denicin de la URL y la funcin de vista que se llamar estn dbilmente acopladas; de esta manera, la decisin
de cul debe ser la URL para una funcin, y la implementacin de la funcin misma, residen en dos lugares separados.
Esto permite el desarrollo de una pieza sin afectar a la otra.
En contraste, otras plataformas de desarrollo Web acoplan la URL con el programa. En las tpicas aplicaciones PHP
(http://www.php.net/), por ejemplo, la URL de tu aplicacin es designada por dnde colocas el cdigo en el sistema
de archivos. En versiones anteriores del framework Web Python CherryPy (http://www.cherrypy.org/) la URL de
tu aplicacin corresponda al nombre del mtodo donde resida tu cdigo. Esto puede parecer un atajo conveniente en
el corto plazo, pero puede tornarse inmanejable a largo plazo.
Por ejemplo, consideremos la funcin de vista que escribimos antes, la cul nos mostraba la fecha y la hora actual.
Si quieres cambiar la URL de tu aplicacin -- digamos, mover desde
cambio en la URLconf, sin preocuparte acerca de la implementacin subyacente de la funcin. Similarmente, si quieres
cambiar la funcin de vista -- alterando la lgica de alguna manera -- puedes hacerlo sin afectar la URL a la que
est asociada tu funcin de vista. Adems, si quisiramos exponer la funcionalidad de fecha actual en varias URL
podramos hacerlo editando el URLconf con cuidado, sin tener que tocar una sola lnea de cdigo de la vista.
Eso es el acoplamiento dbil en accin. Continuaremos exponiendo ejemplos de esta importante losofa de desarrollo
a lo largo del libro.
3.5.
Errores 404
En las URLconf anteriores, hemos denido un solo patrn URL: el que maneja la peticin para la URL
/time.
19
20
3.6.
En la primer vista de ejemplo, el contenido de la pgina -- la fecha/hora actual -- eran dinmicas, pero la URL
(/time) era esttica. En la mayora de las aplicaciones Web, sin embargo, la URL contiene parmetros que inuyen
en la salida de la pgina.
Vamos a crear una segunda vista que nos muestre la fecha y hora actual con un adelanto de ciertas horas. El
objetivo es montar un sitio en la que la pgina
/time/plus/2/
la pgina
/time/plus/1/
/time/plus/3/
muestre la
urlpatterns = patterns('',
(r'^time/$', current_datetime),
(r'^time/plus/1/$', one_hour_ahead),
(r'^time/plus/2/$', two_hours_ahead),
(r'^time/plus/3/$', three_hours_ahead),
(r'^time/plus/4//$', four_hours_ahead),
)
Claramente, esta lnea de pensamiento es incorrecta. No slo porque producir redundancia entre las funciones de
vista, sino tambin la aplicacin estar limitada a admitir slo el rango horario denido -- uno, dos, tres o cuatro horas.
Si, de repente, quisiramos crear una pgina que mostrara la hora cinco horas adelantada, tendramos que crear una
vista distinta y una lnea URLconf, perpetuando la duplicacin y la demencia. Aqu necesitamos algo de abstraccin.
3.6.1.
Si tienes experiencia en otra plataforma de diseo Web, como PHP o Java, es posible que ests pensado, Oye,
usemos un parmetro cadena de consulta!, algo como
parmetro
hours
/time/plus?hours=3,
?).
Con Django puedes hacer eso (pero te diremos cmo ms adelante, si es que realmente quieres saberlo), pero una
de las losofas del ncleo de Django es que las URLs deben ser bonitas. La URL
ms simple, ms legible, ms fcil de dictarse a alguien y . . . justamente ms bonita que su homloga forma de cadena
de consulta. Las URLs bonitas son un signo de calidad en las aplicaciones Web.
El sistema de URLconf que usa Django estimula a generar URLs bonitas, haciendo ms fcil el usarlas que el no
usarlas.
3.6.2.
hours_ahead,
antes, un patrn URL es una expresin regular; de aqu, es que usamos el patrn de expresin regular
\d+
para que
Ahora que lo pienso, podemos limitar el lapso mximo de horas en 99. Eso signica que queremos tener nmeros de
uno o dos dgitos en la sintaxis de las expresiones regulares, con lo que nos quedara as
\d{1,2}:
(r'^time/plus/\d{1,2}/$', hours_ahead),
Nota
Cuando construimos aplicaciones Web, siempre es importante considerar el caso ms descabellado
posible de entrada, y decidir si la aplicacin admitir o no esa entrada. Aqu hemos limitado a
los exagerados reconociendo lapsos de hasta 99 horas. Y, por cierto, Los Limitadores exagerados,
aunque largo, sera un nombre fantstico para una banda musical.
revisin 757 del 28 de julio de 2008
21
Ahora designaremos el comodn para la URL, necesitamos una forma de pasar esa informacin a la funcin de
vista, as podremos usar una sola funcin de vista para cualquier adelanto de hora. Lo haremos colocando parntesis
alrededor de los datos en el patrn URL que querramos guardar. En el caso del ejemplo, queremos guardar cualquier
nmero que se anotar en la URL, entonces pongamos parntesis alrededor de
\d{1,2}:
(r'^time/plus/(\d{1,2})/$', hours_ahead),
Si ests familiarizado con las expresiones regulares, te sentirs como en casa aqu; estamos usando parntesis para
current_datetime,
hours_ahead.
hours_ahead es muy similar a current_datetime, vista que escribimos antes, slo que con una diferencia: tomar
views.py lo siguiente:
'21'.
pre que sea un identicador vlido para Python. El nombre de la variable no importa; todo
lo que importa es lo que contiene el segundo parmetro de la funcin (luego de
request).
Es posible tambin usar una palabra clave, en lugar de posicin, como argumentos en la
URLconf. Eso lo veremos en detalle en el Captulo 8.
revisin 757 del 28 de julio de 2008
22
int()
sobre
offset.
en este ejemplo no debemos preocuparnos de atrapar la excepcin, porque tenemos la certeza que
la variable
offset
ser una cadena de caracteres conformada slo por dgitos. Sabemos esto, por el
(\d{1,2})--
otra ventaja de tener un URLconf: nos provee un primer nivel de validacin de entrada.
La siguiente lnea de la funcin muestra la razn por la que se llam a la funcin
En esta lnea, calculamos la hora actual ms las hora que tiene
la variable
dt.
La funcin
datetime.timedelta
offset,
int()
con
offset.
almacenando el resultado en
hours
sea un entero.
A continuacin, construimos la salida HTML de esta funcin de vista, tal como lo hicimos en la vista
current_datetime.
Python con dos valores, no slo uno. Por lo tanto, hay dos smbolos %s en la cadena de caracteres y
(offset, dt).
Finalmente, retornamos el HttpResponse del HTML -- de nuevo, tal como hicimos en la vista current_datetime.
la tupla de valores a insertar sera:
Con esta funcin de vista y la URLconf escrita, ejecuta el servidor de desarrollo de Django (si no est co-
car que el patrn en la URLconf slo acepta nmero de uno o dos dgitos, Django debera mostrar un error en este caso
como Page not found, tal como vimos en la seccin Errores 404 anteriormente. La URL
(sin horas designadas) debera tambin mostrar un error 404.
Si ests siguiendo el libro y programando al mismo tiempo, notars que el archivo
vistas. (Omitimos la vista
current_datetime
http://127.0.0.1:8000/time/plus/
views.py
3.7.
Tommonos un momento para admirar la bonita aplicacin web que hemos creado hasta ahora . . . y ahora
rompmosla! Introduzcamos deliberadamente un error de Python en el archivo
= int(offset)
de la vista
hours_ahead:
3.8. QU SIGUE?
23
El punto de este ejemplo fue demostrar la pgina de error de Django. Dediquemos un momento a explorar esta
pgina y descubrir las distintas piezas de informacin que nos brinda.
Aqu comentamos algunas cosas a destacar:
En la parte superior de la pgina se muestra la informacin clave de la excepcin: el tipo y cualquier
parmetro de la excepcin (el mensaje
"unsupported type"
ms interactivo. Por cada marco de la pila, Django muestra el nombre del archivo, el nombre de la
funcin/mtodo, el nmero de lnea, y el cdigo fuente de esa lnea.
Haz click en la lnea de cdigo (en gris oscuro) para ver varias lneas anteriores y posteriores a la lnea
errnea, lo que nos brinda un poco de contexto.
Haz click en Locals vars debajo de cualquier marco de la pila para ver la tabla de todas las variables
locales y sus valores, en ese marco y en la posicin exacta de cdigo en el cual fue lanzada la excepcin.
Esta informacin de depuracin es invaluable.
Nota el texto Switch to copy-and-paste view debajo de la cabecera Traceback . Haz click en esas
palabras, y el
*traceback* cambiar a una versin que te permitir fcilmente copiar y pegar. Usando
esto para cuando necesitemos compartir el traceback de la excepcin con otros para obtener soporte
tcnico -- como los amables colegas que encontraremos en el canal de IRC o la lista de correo de
Django.
A continuacin, la seccin Request information incluye una gran cantidad de informacin sobre la
peticin Web que provoc el error: informacin GET y POST, valores de las cookies y meta informacin
como las cabeceras CGI. El
Apndice E`_`_, cubre en detalle los ajustes de conguracin disponibles. Por ahora, slo mira los
ajustes para tener una idea de la informacin disponible.
Inline literal start-string without end-string.
La pgina de error de Django es capaz de mostrar ms informacin en ciertos casos especiales, como por ejemplo,
en el caso de error de sintaxis en las plantillas. Lo abordaremos ms tarde, cuando discutamos el sistema de plantillas
de Django. Por ahora, quita el comentario en la lnea
offset = int(offset)
normalmente de nuevo.
assert False
variables locales y el estado del programa. (Hay maneras ms avanzadas de depurar las vista en Django, lo explicaremos
ms adelante, pero esto es la forma ms rpida y fcil).
Finalmente, es obvio que la mayor parte de la informacin es delicada -- expone las entraas del cdigo fuente de
Python, como tambin de la conguracin de Django -- y sera una estupidez mostrarla al pblico en Internet. Una
persona con malas intenciones podra usar esto para intentar aplicar ingeniera inversa en la aplicacin Web y hacer
cosas maliciosas. Por esta razn, la pgina de error es mostrada slo cuando el proyecto est en modo depuracin.
Explicaremos cmo desactivar este modo ms adelante. Por ahora, hay que tener en claro que todos los proyectos
de Django estn en modo depuracin automticamente cuando son creados. (Suena familiar? Los errores Page not
found, descriptos en la seccin Errores 404, trabajan de manera similar.)
3.8.
Qu sigue?
Hasta ahora hemos producido las vistas mediante cdigo HTML dentro del cdigo Python. Desafortunadamente,
esto es casi siempre es una mala idea. Pero por suerte, con Django podemos hacer esto con un potente motor de
plantillas que nos permite separar el diseo de las pginas del cdigo fuente subyacente. Nos sumergiremos en el motor
de plantillas de Django en el
`prximo captulo`_
24
Captulo 4
4.1.
Una plantilla de Django es una cadena de texto que pretende separar la presentacin de un documento de sus
datos. Una plantilla dene rellenos y diversos bits de lgica bsica (esto es, etiquetas de plantillas) que regulan como
el documento debe ser mostrado. Normalmente, las plantillas son usadas para producir HTML, pero las plantillas de
Django son igualmente capaces de generar cualquier formato basado en texto.
Vamos a sumergirnos con una simple plantilla de ejemplo. Esta plantilla describe una pgina HTML que agradece
a una persona por un pedido de la empresa. Piensa en esto como un formulario de una carta:
<html>
<head><title>Ordering notice</title></head>
<body>
<p>Dear {{ person_name }},</p>
<p>Thanks for placing an order from {{ company }}. It's scheduled to
ship on {{ ship_date|date:"F j, Y" }}.</p>
<p>Here are the items you've ordered:</p>
<ul>
{ % for item in item_list %}
<li>{{ item }}</li>
{ % endfor %}
</ul>
revisin 757 del 28 de julio de 2008
26
{ % if ordered_warranty %}
<p>Your warranty information will be included in the packaging.</p>
{ % endif %}
<p>Sincerely,<br />{{ company }}</p>
</body>
</html>
Esta plantilla es un HTML bsico con algunas variables y etiquetas de plantillas agregadas. Vamos paso a paso a
travs de este:
Cualquier texto encerrado por un par de llaves (por ej.
{{ person_name }})
signica insertar el valor de la variable con el nombre tomado. Cmo especicamos el valor de las
variables?. Vamos a llegar a eso en un momento.
Cualquier texto que est rodeado por llaves y signos de porcentaje (por ej.
{ % if ordered_warranty %})
es una etiqueta de plantilla. La denicin de etiqueta es bastante extensa: una etiqueta slo le indica
al sistema de plantilla haz algo.
Este ejemplo de plantilla contiene dos etiquetas: la etiqueta
etiqueta
for)
Una etiqueta
y la etiqueta
for
{ % if ordered_warranty %}
(una
(una etiqueta
acta como un simple constructor de bucle, dejndote recorrer sobre cada uno de
if,
ordered_warranty
True. Si lo hace, el sistema de plantillas mostrar todo entre { % if ordered_warranty %} y
{ % endif %}. Si no, el sistema de plantillas no mostrar esto. El sistema de plantillas tambin admite
{ % else %} y otras varias clusulas lgicas.
Finalmente, el segundo prrafo de esta plantilla tiene un ejemplo de un ltro, con el cual puedes alterar
la exposicin de una variable. En este ejemplo,
la variable
date
ship_date
por el ltro
date,
tomando el ltro
pasando
El ltro
formatea fechas en el formato tomado, especicado por ese argumento. Los ltros se conceden
mediante el uso de un caracter pipe (|), como una referencia a las tuberas de Unix.
Cada plantilla de Django tiene acceso a varias etiquetas y ltros incorporados, algunas de ellas sern tratadas en
la seccin que sigue. El Apndice F contiene la lista completa de etiquetas y ltros, y sta es una buena idea para
familiarizarse con esta lista, de modo que sepas qu es posible. Tambin es posible crear tus propios ltros y etiquetas,
los cuales cubriremos en el
4.2.
`Captulo 10`_.
Para usar el sistema de plantillas en el cdigo Python, slo sigue estos dos pasos:
1. Crea un objeto
Template
Este retorna una plantilla totalmente renderizada como una cadena de caracteres, con todas las
variables y etiquetas de bloques evaluadas de acuerdo al contexto.
Las siguientes secciones describen cada uno de los pasos con mayor detalle.
4.2.1.
django.template,
27
Puedes reconocer estos ejemplos por el triple signo mayor-que (>>>), el cul designa el prompt
del intrprete. Si ests copiando los ejemplos del libro, no copies estos signos mayor-que.
Las sentencias multilneas en el intrprete interactivo son rellenadas con tres puntos (...), por
ejemplo:
0xb7d5f24c ser
Template.
distinto cada vez, y realmente no importa; es la simple forma en que Python identica un
objeto de
en el Apndice E.
Cuando creas un objeto
Template,
optimizada, listo para renderizar. Pero si tu cdigo de plantilla incluye errores de sintaxis, la llamada a
causar una excepcin
TemplateSyntaxError:
TemplateSyntaxError
Template()
28
4.2.2.
un conjunto de variables y sus valores asociados. Una plantilla usar estas variables para poblar y evaluar estas etiquetas
de bloque.
Un contexto es representado en Django por la clase
Context,
django.template.
Su constructor toma un argumento opcional: un diccionario mapeando nombres de variables con valores. La llamada
al mtodo
>>>
>>>
>>>
>>>
'My
render()
del objeto
Template
`Captulo 10`_.
Context
Context
Los nombres de las variables deben comenzar con una letra (A-Z o a-z) y pueden contener dgitos, guiones bajos,
y puntos. (Los puntos son un caso especial al que llegaremos en un momento). Los nombres de variables son sensible
a maysculas-minsculas.
Este es un ejemplo de compilacin y renderizacin de una plantilla, usando una plantilla de muestra comienzo de
este captulo:
raw_template.
comillas para designar la cadena de caracteres, debido a que envuelven varias lneas; en el cdigo
Python, las cadenas de caracteres designadas con una sola comilla marca que no puede envolver varias
lneas.
Luego, creamos un objeto plantilla,
t,
pasndole
raw_template
al constructor de la clase
Template.
Importamos el mdulo
29
en la prxima sentencia.
el cual mapea nombres de variables con valores. Aqu, por ejemplo, especicamos que la
texto. Este retorna la plantilla renderizada -- esto es, reemplaza las variables de la plantilla con los
valores actuales de las variables, y ejecuta cualquier bloque de etiquetas.
Nota que el prrafo de garanta fue mostrado porque la variable
Tambin nota que la fecha
j, Y.
April 2, 2009,
ordered_warranty
evalu a
True.
F
date
a la brevedad).
Si eres nuevo en Python, quizs te asombre porqu la salida incluye los caracteres de nueva lnea ('\n')
en vez de mostrar los saltos de lnea. Esto sucede porque es una sutileza del intrprete interactivo de
Python: la llamada a
t.render(c)
omisin, muestra una representacin de esta, en vez de imprimir el valor de la cadena. Si quieres ver
la cadena de caracteres con los saltos de lneas como verdaderos saltos de lneas en vez de caracteres
'\n',
usa la sentencia
Estos son los fundamentos de usar el sistema de plantillas de Django: slo escribe una plantilla, crea un objeto
Template,
4.2.3.
crea un
Context,
y llama al mtodo
render().
Template,
Template
render()
# Bad
for name in ('John', 'Julie', 'Pat'):
t = Template('Hello, {{ name }}')
print t.render(Context({'name': name}))
# Good
t = Template('Hello, {{ name }}')
for name in ('John', 'Julie', 'Pat'):
print t.render(Context({'name': name}))
El anlisis sintctico de las plantillas de Django es bastante rpido. Detrs de escena, la mayora de los analizadores
pasan con una simple llamada a una expresin regular corta. En contraste con el motor de plantillas de XML, que
incurren en la actividad general de un analizador XML, tienden a ser rdenes de magnitud ms lentos que el motor
de renderizado de Django.
4.2.4.
En los ejemplos hasta el momento, pasamos simples valores en los contextos--en su mayora cadena de caracteres, ms un
datetime.date.
La clave para atravesar estructuras de datos complejas en las plantillas de Django ese el carcter punto (.). Usa
un punto para acceder a las claves de un diccionario, atributos, ndices, o mtodos de un objeto.
Esto es mejor ilustrarlos con algunos ejemplos. Por ejemplo, supone que pasas un diccionario de Python a una
plantilla. Para acceder al valor de ese diccionario por su clave, usa el punto:
revisin 757 del 28 de julio de 2008
30
datetime.date
year, month
day,
Django:
upper() y isdigit(), y puedes llamar a estos en las plantillas de Django usando la misma
sintaxis de punto:
TemplateSyntaxError.
{{ items.-1 }}
causar una
31
Listas de Python
Las listas de Python comienzan en cero, entonces el primer elemento es el 0, el segundo es el 1 y
as sucesivamente.
La bsqueda del punto puede resumirse como esto: cuando un sistema de plantillas encuentra un punto en una
variable, este intenta la siguiente bsqueda en este orden:
foo["bar"])
foo.bar)
Llamada de mtodo (por ej. foo.bar())
ndice de lista (por ej. foo[bar])
Diccionario (por ej.
Atributo (por ej.
}}, el cual
(upper()):
{{ person.name.upper
class SilentAssertionError(AssertionError):
silent_variable_failure = True
class PersonClass4:
def first_name(self):
raise SilentAssertionError
p = PersonClass4()
t.render(Context({"person": p}))
name is ."
La llamada a un mtodo funcionar slo si el mtodo no requiere argumentos. En otro caso, el sistema
se mover a la prxima bsqueda de tipo (ndice de lista).
Evidentemente, algunos mtodos tienen efectos secundarios, por lo que sera absurdo, en el mejor de
los casos, y posiblemente un agujero de seguridad, permitir que el sistema de plantillas tenga acceso
a ellos.
Una plantilla no
32
def delete(self):
# Delete the account
delete.alters_data = True
El sistema de plantillas no debera ejecutar cualquier mtodo marcado de este modo. En otras palabras,
si una plantilla incluye
fallar silenciosamente.
4.2.5.
`Captulo 10`_.
4.3.
Como hemos mencionamos, el sistema de plantillas se distribuye con etiquetas y ltros incorporados. Las secciones
que siguen proveen un resumen de la mayora de las etiquetas y ltros.
4.3.1.
Etiquetas
if/else
La etiqueta
{ % if %} evala una variable, y si esta es true (esto es, existe, no est vaca, y no es un valor Boolean
{ % if %} y { % endif %}, por ejemplo:
{ % if today_is_weekend %}
<p>Welcome to the weekend!</p>
{ % endif %}
revisin 757 del 28 de julio de 2008
La etiqueta
{ % else %}
33
es opcional:
{ % if today_is_weekend %}
<p>Welcome to the weekend!</p>
{ % else %}
<p>Get back to work.</p>
{ % endif %}
Las verdades de Python
En Python, la lista vaca ([]), tuplas (()), diccionario ({}), string (''), cero (0), y el objeto
especia
La etiqueta
None
{ % if %}
son
False
acepta
and, or,
not
True.
{ % if %}
and
or
or
{ % if %}
and
{ % if athlete_list %}
{ % if coach_list or cheerleader_list %}
We have athletes, and either coaches or cheerleaders!
{ % endif %}
{ % endif %}
Usar varias veces el mismo operador lgico estn bien, pero no puedes combinar diferentes operadores. Por ejemplo,
esto es vlido:
{ % elif %}.
Usa etiquetas
{ % if %}
{ % if athlete_list %}
<p>Here are the athletes: {{ athlete_list }}.</p>
{ % else %}
<p>No athletes are available.</p>
revisin 757 del 28 de julio de 2008
34
{ % if coach_list %}
<p>Here are the coaches: {{ coach_list }}.</p>
{ % endif %}
{ % endif %}
Asegrate de cerrar cada
for
La etiqueta
{ % for %}
de Python, la sintaxis es
permite iterar sobre cada uno de los elementos de una secuencia. Como en la sentencia
for X in Y,
dnde
for
es el nombre de la
variable que se usar para cada uno de los ciclos del bucle. Cada vez que atravesamos el bucle, el sistema de plantillas
renderizar todo entre
{ % for %}
{ % endfor %}.
Por ejemplo, puedes usar lo siguiente para mostrar una lista de atletas tomadas de la variable
athlete_list:
<ul>
{ % for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{ % endfor %}
</ul>
Agrega
reversed
{ % for %}:
{ % for %}
asigna la variable
forloop
forloop.counter
ha entrado en el bucle. Esta es indexada a partir de 1, por lo que la primera vez que se ingresa al
igual al nmero de elementos que hay en la secuencia. La ltima vez que se atraviese el bucle, a
elementos que hay en la secuencia menos 1. La ltima vez que se atraviese el bucle, el valor de esta
ser
0.
forloop.first
True
35
{ % for link in links %}{{ link }}{ % if not forloop.last %} | { % endif %}{ % endfor %}
El cdigo de la plantilla de arriba puede mostrar algo parecido a esto:
de
Aqu un ejemplo:
{ % for %},
forloop.parentloop.
forloop.parentloop
forloop.
forloop
{ % for %}.
ifequal/ifnotequal
El sistema de plantillas de Django a propsito no es un lenguaje de programacin completo y por lo tanto no
permite ejecutar sentencias arbitrarias de Python. (Ms sobre esta idea en la seccin Filosofa y limitaciones). Sin
embargo, es bastante comn que una plantilla requiera comparar dos valores y mostrar algo si ellos son iguales --
endifequal %}
si el valor es igual.
user
currentuser
{ % ifequal %}
de la plantilla:
{%
36
Como
{ % if %},
la etiqueta
{ % ifequal %}
admite un opcional
{ % else %}:
ifequal %}.
{%
{%
{%
{%
{%
ifequal
ifequal
ifequal
ifequal
variable
variable
variable
variable
1 %}
1.23 %}
'foo' %}
"foo" %}
Cualquier otro tipo de variables, tales como diccionarios de Python, listas, o booleanos, no pueden ser comparados
en
{ % ifequal %}.
{ % if %}
en vez de
{ % ifequal %}.
Comentarios
Al igual que en HTML o en un lenguaje de programacin como Python, el lenguaje de plantillas de Django permite
comentarios. Para designar un comentario, usa
{# #}:
{# This is a comment #}
Este comentario no ser mostrado cuando la plantilla sea renderizada.
Un comentario no puede abarcar mltiples lneas. Esta limitacin mejora la performance del analizador sintctico
de plantillas. En la siguiente plantilla, la salida del renderizado mostrara exactamente lo mismo que la plantilla (esto
es, la etiqueta comentario no ser tomada como comentario):
Filtros
Como explicamos anteriormente en este captulo, los ltros de plantillas son formas simples de alterar el valor de
una variable antes de mostrarla. Los ltros se parecen a esto:
{{ name|lower }}
Esto muestra el valor de
{{ name }}
lower,
Los ltros pueden estar en cadena -- eso es, la salida del uno de los ltros puede ser aplicada al prximo. Aqu un
modismo comn para escapar contenido del texto, y entonces convertir los saltos de lneas en etiquetas
<p>:
{{ my_text|escape|linebreaks }}
Algunos ltros toman argumentos. Un ltro con argumento se ve de este modo:
{{ bio|truncatewords:"30" }}
Esto muestra las primeras 30 palabras de la variable
dobles.
Los siguientes son algunos de los ltros ms importantes; el Apndice F cubre el resto.
addslashes:
Agrega una con contra-barra antes de cualquier contra-barra, comilla simple o comilla
date:
Formatea un objeto
date
37
datetime
ejemplo:
{{ pub_date|date:"F j, Y" }}
El formato de los strings est denido en el Apndice F.
escape:
Escapa ampersands(&), comillas, y corchetes del string tomado. Esto es usado para desin-
fectar datos suministrados por el usuario y asegurar que los datos son vlidos para XML y XHTML.
Especcamente,
escape
Convierte
Convierte
Convierte
Convierte
Convierte
&
<
>
"
'
en
en
en
&
<
>
(comilla doble) en
"
'
(comilla simple) en
length: Retorna la longitud del valor. Puedes usar este con una lista o con un string, o con cualquier
objeto Python que sepa como determinar su longitud (o sea cualquier objeto que tenga el mtodo
__len__()).
4.4.
Filosofa y Limitaciones
Ahora que tienes una idea del lenguaje de plantillas de Django, debemos sealar algunas de sus limitaciones
intencionales, junto con algunas losofas detrs de la forma en que este funciona.
Ms que cualquier otro componente de la aplicacin web, las opiniones de los programadores sobre el sistema
de plantillas vara extremadamente. El hecho de que Python slo implemente decenas, sino cientos, de lenguajes de
plantillas de cdigo abierto lo dice todo. Cada uno fue creado probablemente porque su desarrollador estima que todos
los existentes son inadecuados. (De hecho, se dice que es un rito para los desarrolladores de Python escribir su propio
lenguaje de plantillas! Si todava no lo has hecho, tenlo en cuenta. Es un ejercicio divertido).
Con eso en la cabeza, debes estar interesado en saber que Django no requiere que uses su lenguaje de plantillas.
Pero Django pretende ser un completo framework que provee todas las piezas necesarias para que el desarrollo web
sea productivo, quizs a veces es ms conveniente usar el sistema de plantillas de Django que otras bibliotecas de
plantillas de Python, pero no es un requerimiento estricto en ningn sentido. Como vers en la prxima seccin Uso
de plantillas en las vistas, es muy fcil usar otro lenguaje de plantillas con Django.
An as, es claro que tenemos una fuerte preferencia por el sistema de plantillas de Django. El sistema de plantillas
tiene races en la forma en que el desarrollo web se realiza en World Online y la experiencia combinada de los creadores
de Django. stas con algunas de esas losofas:
La lgica de negocios debe ser separada de la presentacin lgica. Vemos al sistema de plantillas como
una herramienta que controla la presentacin y la lgica relacionado a esta -- y eso es todo. El sistema
de plantillas no debera admitir funcionalidad que vaya ms all de este concepto bsico.
Por esta razn, es imposible llamar a cdigo Python directamente dentro de las plantillas de Django.
Todo programador est fundamentalmente limitado al alcance de lo que una etiqueta puede hacer.
Es posible escribir etiquetas personalizadas que hagan cosas arbitrarias, pero las etiquetas de Django
intencionalmente no permiten ejecutar cdigo arbitrario de Python.
Los diseadores se supone que se sienten ms cmodos con el cdigo HTML. El sistema de plantillas
no est diseado para que las plantillas necesariamente sean mostradas de forma agradable en los
editores WYSIWYG
que la sintaxis sea tan clara como lo es. Django espera las plantillas de los autores para estar cmodo
editando HTML directamente.
38
Se supone que los diseadores no son programadores Python. El sistema de plantillas de los autores
reconoce que las plantillas de las pginas web son en al mayora de los casos escritos por diseadores,
no por programadores, y por esto no debera asumir ningn conocimiento de Python.
Sin embargo, el sistema tambin pretende acomodar pequeos grupos en los cuales las plantillas sean
creadas por programadores de Python. Esto ofrece otro camino para extender la sintaxis del sistema
escribiendo cdigo Python puro. (Ms de esto en el
`Captulo 10`_).
El objetivo no es inventar un lenguaje de programacin. El objetivo es ofrecer slo la suciente funcionalidad de programacin, tales como ramicacin e iteracin, que son esenciales para hacer presentaciones relacionadas a decisiones.
Como resultado de esta losofa, el lenguaje de plantillas de Django tiene las siguientes limitaciones:
Una plantilla no puede asignar una variable o cambiar el valor de esta. Esto es posible escribiendo una
etiqueta personalizada para cumplir con esta meta (ve el
de Django no lo permite.
Una plantilla no puede llamar cdigo Python crudo. No hay forma de ingresar en modo Python o
usar sentencias puras de Python. De nuevo, esto es posible creando plantillas personalizadas, pero la
pila de etiquetas de Django no lo permiten.
4.5.
Has aprendido el uso bsico del sistema de plantillas; ahora vamos a usar este conocimiento para crear una vista.
Recordemos la vista
current_datetime
en
mysite.views,
esto:
/home/djangouser/templates/mytemplate.html:
39
fp = open('/home/djangouser/templates/mytemplate.html')
t = Template(fp.read())
fp.close()
html = t.render(Context({'current_date': now}))
return HttpResponse(html)
Esta aproximacin, sin embargo, es poco elegante por estas razones:
No maneja el caso en que no encuentre el archivo. Si el archivo
accesible para lectura, la llamada a
open()
mytemplate.html
IOError.
no existe o no es
levantar la excepcin
Involucra la ruta de tu plantilla. Si vas a usar esta tcnica para cada una de las funciones de las vistas,
estars duplicando rutas de plantillas. Sin mencionar que esto implica teclear mucho ms!
Incluye una cantidad aburrida de cdigo repetitivo. Tienes mejores cosas para hacer en vez de escribir
open(), fp.read()
fp.close()
Para solucionar estos problemas, usamos cargadores de plantillas y directorios de plantillas, los cuales son descriptos
en las secciones que siguen.
4.6.
Cargadores de plantillas
tu proyecto de Django). Es un simple mdulo de Python con variables, una por cada conguracin.
Cuando ejecutaste
django-admin.py startproject mysite en el Captulo 2, el script cre un archivo de consettings.py. chale un vistazo al contenido del archivo. Este contiene
DEBUG = True
TIME_ZONE = 'America/Chicago'
USE_I18N = True
ROOT_URLCONF = 'mysite.urls'
stas se explican por s solas; las conguraciones y sus respectivos valores son simples variables de Python. Como
el archivo de conguracin es slo un mdulo plano de Python, puedes hacer cosas dinmicas como vericar el valor
de una variable antes de congurar otra. (Esto tambin signica que debes evitar errores de sintaxis de Python en los
archivos de conguracin).
Cubriremos el archivo de conguracin en profundidad en el Apndice E, pero por ahora, veamos la variable de
conguracin
TEMPLATE_DIRS.
Esta variable le indica al mecanismo de carga de plantillas dnde buscar las plantillas.
Por omisin, sta es una tupla vaca. Elige un directorio en el que desees guardar tus plantillas y agrega este a
TEMPLATE_DIRS,
as:
TEMPLATE_DIRS = (
'/home/django/mysite/templates',
)
Hay algunas cosas para notar:
Puedes especicar cualquier directorio que quieras, siempre y cuando la cuenta de usuario en el cual
se ejecuta el servidor web tengan acceso al directorio y su contenido. Si no puedes pensar en un
lugar apropiado para poner las plantillas, te recomendamos crear un directorio
del proyecto de Django (esto es, dentro del directorio
mysite
templates
dentro
TEMPLATE_DIRS
40
TEMPLATE_DIRS = [
'/home/django/mysite/templates'
]
Una tupla es un poco ms correcta semnticamente que una lista (las tuplas no pueden cambiar
luego de ser creadas, y nada podra cambiar las conguraciones una vez que fueron ledas), nosotros
recomendamos usar tuplas para la variable
TEMPLATE_DIRS.
Si ests en Windows, incluye tu letra de unidad y usa el estilo de Unix para las barras en vez de barras
invertidas, como sigue:
TEMPLATE_DIRS = (
'C:/www/django/templates',
)
Es ms sencillo usar rutas absolutas (esto es, las rutas de directorios comienzan desde la raz del
sistema de archivos). Si quieres sen un poco ms exible e independiente, tambin, puedes tomar el
hecho de que el archivo de conguracin de Django es slo cdigo de Python y construir la variable
TEMPLATE_DIRS dinmicamente,
import os.path
por ejemplo:
TEMPLATE_DIRS = (
os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
)
Este ejemplo usa la variable de Python mgica __file__, la cual es automticamente asignada
al
TEMPLATE_DIRS congurada, el prximo paso es cambiar el cdigo de vista que usa la funcionalidad
current_datetime,
de carga de plantillas de Django, para no incluir la ruta a la plantilla. Volvamos a nuestra vista
vamos a cambiar esta como sigue:
Para ver que cmo se ve eso, ejecutar el servidor de desarrollo de Django otra vez, como en el Captulo 3, ejecutando
python manage.py runserver en el directorio de tu proyecto de Django. Luego, escribe en tu navegador la pgina
que activa la vista current_datetime (o sea, http://127.0.0.1:8000/time/). Asumiendo que tu variable de conguracin DEBUG est asignada a True y todava no has creado la plantilla current_datetime.html, deberas ver una
pgina de error de Django resaltando el error TemplateDoesNotExist.
Esta pgina de error es similar a la que explicamos en el Captulo 3, con una pieza adicional de informacin de
depuracin: una seccin Postmortem del cargador de plantillas. Esta seccin te indica qu plantilla intent cargar
Django acompaado de una razn para cada intento fallido (por ej. File does not exist). Esta informacin es invaluable
cuando hacemos depuracin de errores de carga de plantillas.
Como probablemente puedas distinguir de los mensajes de error de la Figura 4-1, Django intent buscar una plantilla
TEMPLATE_DIRS con el nombre de la plantilla pasada a get_template(). EntonTEMPLATE_DIRS contiene '/home/django/templates', Django buscar '/home/django/templates/current_datet
TEMPLATE_DIRS contiene ms que un directorio, cada uno de estos es examinado hasta que se encuentre la plantilla
current_datetime.html
Figura 4.1: La pgina de error que se muestra cuando una plantilla no se encuentra
41
42
4.6.1.
render_to_response()
Context,
y retornar un objeto
HttpResponse
con el
resultado de la plantilla renderizada, Django provee un atajo que te deja hacer estas cosas en una lnea de cdigo.
HttpResponse
manualmente.
current_datetime
reescrito utilizando
render_to_response():
En la funcin
current_datetime,
de esto, im-
render_to_response(). Como
retornar ese valor
simplemente
en la vista.
El primer argumento de
4.6.2.
El truco locals()
current_datetime:
def current_datetime(request):
now = datetime.datetime.now()
return render_to_response('current_datetime.html', {'current_date': now})
Muchas veces, como en este ejemplo, buscars t mismo calcular algunos valores, guardando ellos en variables (por
ej.
now
en el cdigo anterior), y pasando estas a la plantilla. Particularmente los programadores perezosos notarn
que es ligeramente redundante tener esos nombres en variables temporales y tener nombres para las variables de la
plantilla. No slo que esto es redundante, sino que tambin hay que teclear ms.
Entonces si eres uno de esos programadores perezosos y quieres ahorrar cdigo particularmente conciso, puedes
tomar la ventaja de la funcin built-in de Python llamada
locals().
nombres de variables locales con sus valores. De esta manera, la vista anterior podra reescribirse como sigue:
def current_datetime(request):
current_date = datetime.datetime.now()
return render_to_response('current_datetime.html', locals())
Aqu, en vez de especicar manualmente el diccionario al contexto como antes, pasamos el valor de
locals(),
el cual incluye todas las variables denidas hasta ese punto en la ejecucin de la funcin. Como una consecuencia,
locals()
con lo cual quizs conste de ms variables de las cuales quieres tener acceso en la plantilla. En el ejemplo anterior,
locals()
tambin incluir
request.
locals()
4.6.3.
43
Subdirectorios en get_template()
Puede ser un poco inmanejable guardar todas las plantillas en un solo directorio. Quizs quieras guardar las
plantillas en subdirectorios del directorio de tus plantillas, y esto est bien. De hecho, recomendamos hacerlo; algunas
de las caractersticas ms avanzadas de Django (como las vistas genricas del sistema, las cuales veremos en el Captulo
9) esperan esta distribucin de las plantillas como una convencin por omisin.
Guardar las plantillas en subdirectorios de tu directorio de plantilla es fcil. En tus llamadas a
get_template(),
slo incluye el nombre del subdirectorio y una barra antes del nombre de la plantilla, as:
t = get_template('dateapp/current_datetime.html')
Debido a que
primer argumento de
No hay lmites para la profundidad del rbol de subdirectorios. Sintete libre de usar tantos como quieras.
Nota
Los usuario de Windows, asegrense de usar barras comunes en vez de barras invertidas.
get_template()
4.6.4.
La etiqueta de plantilla
include
Ahora que vimos el mecanismo para cargar plantillas, podemos introducir una plantilla built-in que tiene una
ventaja para esto:
{ % include %}.
esta etiqueta debera ser el nombre de la plantilla a incluir, y el nombre de la plantilla puede ser una variable string
hard-coded (entre comillas), entre simples o dobles comillas. En cualquier momento que tengas el mismo cdigo en
varias etiquetas, considera utilizar un
{ % include %}
nav.html.
{ % include 'nav.html' %}
{ % include "nav.html" %}
Este ejemplo incluye el contenido de la plantilla
includes/nav.html:
{ % include 'includes/nav.html' %}
Este ejemplo incluye el contenido de la plantilla cuyo nombre se encuentra en la variable
template_name:
{ % include template_name %}
get_template(), el nombre del archivo de la plantilla es determinado agregando el directorio de plantillas
TEMPLATE_DIRS para el nombre de plantilla solicitado.
Como en
tomado de
Las plantillas incluidas son evaluadas con el contexto de la plantilla en la cual est incluida.
Si una plantilla no encuentra el nombre tomado, Django har una de estas dos cosas:
Si
Si
4.7.
DEBUG
DEBUG
es
es
de error de Django.
lugar de la etiqueta.
Herencia de plantillas
Nuestras plantillas de ejemplo hasta el momento han sido fragmentos de HTML, pero en el mundo real, usars el
sistema de plantillas de Django para crear pginas HTML enteras. Esto conduce a un problema comn del desarrollo
web: Cmo reducimos la duplicacin y redundancia de las reas comunes de las pginas, como por ejemplo, los paneles
de navegacin?
Una forma clsica de solucionar este problema es usar includes, insertando dentro de las pginas HTML a incluir
una pgina dentro de otra. Es ms, Django admite esta aproximacin, con la etiqueta
{ % include %}
anteriormente
descripta. Pero la mejor forma de solucionar este problema con Django es usar una estrategia ms elegante llamada
herencia de plantillas.
En esencia, la herencia de plantillas te deja construir una plantilla base esqueleto que contenga todas las partes
comunes de tu sitio y denir bloques que los hijos puedan sobreescribir.
Veamos un ejemplo de esto creando una plantilla completa para nuestra vista
archivo
current_datetime.html:
current_datetime,
editando el
44
hours_ahead
del Captulo 3? Si queremos hacer nuevamente una agradable, vlida, y completa plantilla HTML,
header.html:
footer.html:
<hr>
<p>Thanks for visiting my site.</p>
</body>
</html>
Con una estrategia basada en includes, la cabecera y la parte de abajo son fciles. Es el medio el que queda
desordenado. En este ejemplo, ambas pginas contienen un ttulo -ese ttulo no puede encajar dentro de
en la cabecera, tendramos que
queremos llegar?
El sistema de herencia de Django soluciona estos problemas. Lo puedes pensar a esto como la versin contraria a
la del lado del servidor. En vez de denir los pedazos que son comunes, denes los pedazos que son diferentes.
El primer paso es denir una plantilla base -- un esquelete de tu pgina que las plantillas hijas llenaran luego.
Aqu hay una platilla para nuestro ejemplo actual:
45
<html lang="en">
<head>
<title>{ % block title %}{ % endblock %}</title>
</head>
<body>
<h1>My helpful timestamp site</h1>
{ % block content %}{ % endblock %}
{ % block footer %}
<hr>
<p>Thanks for visiting my site.</p>
{ % endblock %}
</body>
</html>
Esta plantilla, que llamamos
base.html,
las pginas del sitio. Es trabajo de las plantillas hijas sobreescribir, agregar, dejar vaco el contenido de los bloques.
(Si ests lo siguiendo desde casa, guarda este archivo en tu directorio de plantillas).
Usamos una etiqueta de plantilla aqu que no hemos visto antes: la etiqueta
block %}
{ % block %}.
{%
le indican al motor de plantillas que una plantilla hijo quizs sobreescriba esa porcin de la plantilla.
Ahora que tenemos una plantilla base, podemos modicar nuestra plantilla existente
current_datetime.html para
usar esto:
{ % extends "base.html" %}
{ % block title %}The current time{ % endblock %}
{ % block content %}
<p>It is now {{ current_date }}.</p>
{ % endblock %}
hours_ahead del Captulo 3. (Si lo ests
hours_ahead para usar el sistema de plantilla). As sera el resultado:
Como estamos en este tema, vamos a crear una plantilla para la vista
siguiendo junto con el cdigo, te dejamos cambiar
{ % extends "base.html" %}
{ % block title %}Future time{ % endblock %}
{ % block content %}
<p>In {{ hour_offset }} hour(s), it will be {{ next_time }}.</p>
{ % endblock %}
No es hermoso? Cada plantilla contiene slo el cdigo que es nico para esa plantilla. No necesita redundancia. Si
necesitas hacer un cambio grande en el diseo del sitio, slo cambia
el efecto inmediatamente.
Veamos cmo trabaja. Cuando cargamos una plantilla
base.html,
que esta plantilla es la hija de otra. El motor inmediatamente carga la plantilla padre --en este
La herencia no afecta el funcionamiento del contexto, y puedes usar tantos niveles de herencia como necesites. Una
forma comn de utilizar la herencia es el siguiente enfoque de tres niveles:
1. Crear una plantilla
base.html
estilo/diseo.
revisin 757 del 28 de julio de 2008
46
3. Crear una plantilla individual para cada tipo de pgina, tales como pginas de formulario o
galera de fotos. Estas plantillas heredan de la plantilla de la seccin apropiada.
Esta aproximacin maximiza la reutilizacin de cdigo y hace fcil el agregado de elementos para compartir reas,
como puede ser un navegador de seccin.
Aqu hay algunos consejos para el trabajo con herencia de plantillas:
Si usas
{ % extends %}
en la plantilla, esta debe ser la primer etiqueta de esa plantilla. En otro caso,
la herencia no funcionar.
Generalmente, cuanto ms etiquetas
tillas hijas no tienen que denir todos los bloques del padre, entonces puedes rellenar un nmero
razonable de bloques por omisin, y luego denir slo lo que necesiten las plantillas hijas. Es mejor
tener ms conexiones que menos.
Si encuentras cdigo duplicado en un nmero de plantillas, esto probablemente signique que debes
mover ese cdigo a un
{ % block %}
en la plantilla padre.
{{ block.super
}} har este truco. Esto es til si quieres agregar contenido del bloque padre en vez de sobreescribirlo
Si necesitas obtener el contenido de un bloque desde la plantilla padre, la variable
completamente.
No puedes denir mltiples etiquetas
{ % block %}
limitacin existe porque una etiqueta bloque trabaja en ambas direcciones. Esto es, una etiqueta
bloque no slo provee un agujero a llenar, sino que tambin dene el contenido que llenar ese agujero
en el padre. Si hay dos nombres similares de etiquetas
{ % block %}
{ % extends %}
una variable, si no sabes el nombre de la plantilla padre hasta la ejecucin. Esto te permite hacer
cosas divertidas, dinmicas.
4.8.
Qu sigue?
Los sitios web ms modernos son manejados con una base de datos : el contenido de la pgina web est guardado
en una base de datos relacional. Esto permite una clara separacin de los datos y la lgica (de la misma manera que
las vistas y las etiquetas permiten una separacin de la lgica y la vista).
El
`prximo captulo`_ cubre las herramientas que Django brinda para interactuar con la base de datos.
2 N.
3 N.
4 N.
5 N.
Captulo 5
arbitraria, y luego retornar una respuesta. En el ejemplo, nuestra lgica arbitraria era calcular la fecha y hora actual.
En las aplicaciones web modernas, la lgica arbitraria a menudo implica interactuar con una base de datos. Detrs de
escena, un sitio web impulsado por una base de datos se conecta a un servidor de base de datos, recupera algunos datos
de esta, y los muestra con un formato agradable en una pgina web. O, del mismo modo, el sitio puede proporcionar
funcionalidad que permita a los visitantes del sitio poblar la base de datos por su propia cuenta.
Muchos sitios web ms complejos proporcionan alguna combinacin de las dos. Amazon.com, por ejemplo, es un
gran ejemplo de un sitio que maneja una base de datos. Cada pgina de un producto es esencialmente una consulta
a la base de datos de productos de Amazon formateada en HTML, y cuando envas una opinin de cliente (customer
5.1.
As como en el Captulo 3 detallamos la manera tonta de producir una salida con la vista (codicando en duro )
el texto directamente dentro de la vista), hay una manera tonta de recuperar datos desde la base de datos en una
vista. Esto es simple: slo usa una biblioteca de Python existente para ejecutar una consulta SQL y haz algo con los
resultados.
En este ejemplo de vista, usamos la biblioteca
para conectarnos a una base de datos de MySQL, recuperar algunos registros, y alimentar con ellos una plantilla para
mostrar una pgina web:
48
Estamos codicando en duro (hard-coding ) los parmetros de la conexin a la base de datos. Lo ideal
sera que esos parmetros se guardarsen en la conguracin de Django.
Tenemos que escribir una cantidad de cdigo estereotpico: crear una conexin, un cursor, ejecutar una
sentencia, y cerrar la conexin. Lo ideal sera que todo lo que tuviramos que hacer fuera especicar
los resultados que queremos.
Nos ata a MySQL. Si, en el camino, cambiamos de MySQL a PostgreSQL, tenemos que usar un
adaptador de base de datos diferente (por ej.
psycopg
en vez de
MySQLdb),
5.2.
Antes de profundizar en ms cdigo, tommonos un momento para considerar el diseo global de una aplicacin
Web Django impulsada por bases de datos.
Como mencionamos en los captulos anteriores, Django fue diseado para promover el acoplamiento dbil y la
estricta separacin entre las piezas de una aplicacin. Si sigues esta losofa, es fcil hacer cambios en un lugar
particular de la aplicacin sin afectar otras piezas. En las funciones de vista, por ejemplo, discutimos la importancia
de separar la lgica de negocios de la lgica de presentacin usando un sistema de plantillas. Con la capa de la base
de datos, aplicamos esa misma losofa para el acceso lgico a los datos.
Estas tres piezas juntas -- la lgica de acceso a la base de datos, la lgica de negocios, y la lgica de presentacin
-- comprenden un concepto que a veces es llamado el patrn de arquitectura de software Modelo-Vista-Controlador
(MVC). En este patrn, el Modelo hace referencia al acceso a la capa de datos, la Vista se reere a la parte del
sistema que selecciona qu mostrar y cmo mostrarlo, y el Controlador implica la parte del sistema que decide qu
vista usar, dependiendo de la entrada del usuario, accediendo al modelo si es necesario.
Por qu el acrnimo?
El objetivo de denir en forma explcita patrones como MVC es principalmente simplicar la
comunicacin entre los desarrolladores. En lugar de tener que decir a tus compaeros de trabajo,
Vamos a hacer una abstraccin del acceso a la base de datos, luego vamos a tener una capa que
se encarga de mostrar los datos, y vamos a poner una capa en el medio para que regule esto,
puedes sacar provecho de un vocabulario compartido y decir, Vamos a usar un patrn MVC aqu.
Django sigue el patrn MVC tan al pie de la letra que puede ser llamado un framework MVC. Someramente, la M,
V y C se separan en Django de la siguiente manera:
M, la porcin de acceso a la base de datos, es manejada por la capa de la base de datos de Django, la
cual describiremos en este captulo.
V, la porcin que selecciona qu datos mostrar y cmo mostrarlos, es manejada por la vista y las
plantillas.
C, la porcin que delega a la vista dependiendo de la entrada del usuario, es manejada por el framework
mismo siguiendo tu URLconf y llamando a la funcin apropiada de Python para la URL obtenida.
Debido a que la C es manejada por el mismo framework y la parte ms emocionante se produce en los modelos,
las plantillas y las vistas, Django es conocido como un Framework MTV. En el patrn de diseo MTV,
49
M signica Model (Modelo), la capa de acceso a la base de datos. Esta capa contiene toda la
informacin sobre los datos: cmo acceder a estos, cmo validarlos, cul es el comportamiento que
tiene, y las relaciones entre los datos.
T signica Template (Plantilla), la capa de presentacin. Esta capa contiene las decisiones relacionadas a la presentacin: como algunas cosas son mostradas sobre una pgina web o otro tipo de
documento.
V signica View (Vista), la capa de la lgica de negocios. Esta capa contiene la lgica que accede al
modelo y la delega a la plantilla apropiada: puedes pensar en esto como un puente entre el modelos
y las plantillas.
Si ests familiarizado con otros frameworks de desarrollo web MVC, como Ruby on Rails, quizs consideres que
las vistas de Django pueden ser el controlador y las plantillas de Django pueden ser la vista. Esto es una confusin
desafortunada a raz de las diferentes interpretaciones de MVC. En la interpretacin de Django de MVC, la vista
describe los datos que son presentados al usuario; no necesariamente el cmo se mostrarn, pero si cules datos son
presentados. En contraste, Ruby on Rails y frameworks similares sugieren que el trabajo del controlador incluya la
decisin de cuales datos son presentados al usuario, mientras que la vista sea estrictamente el cmo sern presentados
y no cules.
Ninguna de las interpretaciones es ms correcta que otras. Lo importante es entender los conceptos subyacentes.
5.3.
Con toda esta losofa en mente, vamos a comenzar a explorar la capa de la base de datos de Django. Primero,
necesitamos tener en cuenta algunas conguraciones iniciales: necesitamos indicarle a Django qu servidor de base de
datos usar y cmo conectarse con el mismo.
Asumimos que haz congurado un servidor de base de datos, lo has activado, y has creado una base de datos en
este (por ej. usando la sentencia
CREATE DATABASE).
base de datos, porque SQLite usa un archivo autnomo sobre el sistema de archivos para guardar los datos.
Como con
DATABASE_ENGINE = ''
DATABASE_NAME = ''
DATABASE_USER = ''
DATABASE_PASSWORD = ''
DATABASE_HOST = ''
DATABASE_PORT = ''
Aqu hay un resumen de cada propiedad.
DATABASE_ENGINE le indica a Django qu base de datos utilizar. Si usas una base de datos con Django,
DATABASE_ENGINE debe congurarse con un string de los mostrados en la Tabla 5-1.
Cuadro 5.1: Conguracin de motores de base de datos
Conguracin
Base de datos
postgresql
PostgreSQL
postgresql_psycopg2
PostgreSQL
mysql
MySQL
sqlite3
SQLite
Adaptador requerido
pysqlite, http://www.djangoproject.com/
r/python-sqlite/.
adodbapi version 2.0.1+, http://www.djangoproject.
com/r/python-ado/.
cx_Oracle,
http://www.djangoproject.com/r/
python-oracle/
.
28 de julio de 2008
contrario,
ado_mssql
oracle
Oracle
revisin 757 del
50
Nota que cualquiera sea la base de datos que uses, necesitars descargar e instalar el adaptador
apropiado. Cada uno de estos est disponible libremente en la web; slo sigue el enlace en la columna
Adaptador requerido en la Tabla 5-1.
DATABASE_NAME
pecica la ruta completo del sistema de archivos hacia el archivo de la base de datos (por ej.
'/home/django/mydata.db').
DATABASE_USER
le indica a Django cual es el nombre de usuario a usar cuando se conecte con tu base
DATABASE_PASSWORD le
de datos. Si ests utilizando SQLite o tienes una contrasea vaca, deja este en blanco.
DATABASE_HOST
base de datos est sobre la misma computadora que la instalacin de Django (o sea localhost), deja
este en blanco. Si ests usando SQLite, deja este en blanco.
MySQL es un caso especial aqu. Si este valor comienza con una barra ('/') y ests usando MySQL,
MySQL se conectar al socket especicado por medio de un socket Unix, por ejemplo:
DATABASE_HOST = '/var/run/mysql'
Si ests utilizando MySQL y este valor no comienza con una barra, entonces este valor es asumido
como el host.
DATABASE_PORT
utilizando SQLite, deja este en blanco. En otro caso, si dejas este en blanco, el adaptador de base de
datos subyacente usar el puerto por omisin acorde al servidor de base de datos. En la mayora de
los casos, el puerto por omisin est bien, por lo tanto puedes dejar este en blanco.
Una vez que hayas ingresado estas conguraciones, comprubalas. Primero, desde el directorio del proyecto que
creaste en el Captulo 2, ejecuta el comando
Notars que comienza un intrprete interactivo de Python. Las apariencias pueden engaar. Hay una diferencia
usar antes de comenzar el shell. Este es un requerimiento clave para hacer consultas a la base de datos: Django necesita
saber cuales son los archivos de conguraciones a usar para obtener la informacin de la conexin a la base de datos.
python manage.py shell simplemente asume que tu archivo de conguracin est en el mismo
manage.py. Hay otras maneras de indicarle a Django qu mdulo de conguracin usar, pero este subtcubriremos luego. Por ahora, usa python manage.py shell cuando necesites hacer modicaciones especcas
Detrs de escena,
directorio que
tulo lo
a Django.
Una vez que hayas entrado al shell, escribe estos comando para probar la conguracin de tu base de datos:
Mensaje de error
Solucin
Congura la variable
DATABASE_ENGINE
variable
DJAN-
GO_SETTINGS_MODULE is undened.
Error
loading
_____
module:
No
module
_____.
Ejecuta el comando
de
named
python.
en vez
psycopg o MySQLdb).
DATABASE_ENGINE con un mo-
Congura la variable
Cambia la variable
DATABASE_NAME
CREATE DATABASE
revisin 757 del 28 de julio de 2008
51
Mensaje de error
Solucin
Cambia la variable
DATABASE_USER
Asegrate de que
5.4.
Tu primera aplicacin
Ahora que vericamos que la conexin est funcionando, es hora de crear una Aplicacin de Django -- una coleccin
de archivos de cdigo fuente, incluyendo modelos y vistas, que conviven en un solo paquete de Python y representen
una aplicacin completa de Django.
Vale la pena explicar la terminologa aqu, porque esto es algo que suele hacer tropezar a los principiantes. Ya
hemos creado un proyecto, en el Captulo 2, entonces, cul es la diferencia entre un proyecto y una aplicacin ? La
diferencia es la que existe entre la conguracin y el cdigo:
Un proyecto es una instancia de un cierto conjunto de aplicaciones de Django, ms las conguraciones
de esas aplicaciones.
Tcnicamente, el nico requerimiento de un proyecto es que este suministre un archivo de conguracin, el cual dene la informacin hacia la conexin a la base de datos, la lista de las aplicaciones
instaladas, la variable
TEMPLATE_DIRS,
y as sucesivamente.
Una aplicacin es un conjunto portable de una funcionalidad de Django, tpicamente incluye modelos
y vistas, que conviven en un solo paquete de Python.
Por ejemplo, Django incluye un nmero de aplicaciones, tales como un sistema de comentarios y una
interfaz de administracin automtica. Una cosa clave para notar sobre estas aplicaciones es que son
portables y reusables en mltiples proyectos.
Hay pocas reglas estrictas sobre cmo encajar el cdigo Django en este esquema; es exible. Si ests construyendo
un sitio web simple, quizs uses una sola aplicacin. Si ests construyendo un sitio web complejo con varias piezas que
no se relacionan entre s, tales como un sistema de comercio electrnico o un foro, probablemente quieras dividir esto
en aplicaciones para que te sea posible reusar estas individualmente en un futuro.
Es ms, no necesariamente debes crear aplicaciones en absoluto, como lo hace evidente la funcin de la vista del
ejemplo que creamos antes en este libro. En estos casos, simplemente creamos un archivo llamado
views.py, llenamos
este con una funcin de vista, y apuntamos nuestra URLconf a esa funcin. No se necesitan aplicaciones.
No obstante, existe un requisito respecto a la convencin de la aplicacin: si ests usando la capa de base de datos
de Django (modelos), debes crear una aplicacin de Django. Los modelos deben vivir dentro de aplicaciones.
Dentro del directorio del proyecto
mysite que creaste en el Captulo 2, escribe este comando para crear una nueva
vistazo al contenido:
books/
__init__.py
models.py
views.py
Esos archivos contendrn los modelos y las vistas para esta aplicacin.
models.py y views.py en tu editor de texto favorito. Ambos archivos estn vacos, excepto
models.py. Este es el espacio disponible para ser creativo con tu aplicacin de Django.
Echa un vistazo a
la importacin en
por
52
5.5.
Como discutimos en los captulos anteriores, la M de MTV hace referencia al Modelo. Un modelo de Django
es una descripcin de los datos en la base de datos, representada como cdigo de Python. Esta es tu capa de datos -- lo
equivalente de tu sentencia SQL
CREATE TABLE -- excepto que estn en Python en vez de SQL, e incluye ms que slo
denicin de columnas de la base de datos. Django usa un modelo para ejecutar cdigo SQL detrs de las escenas y
retornar estructuras de datos convenientes en Python representando las las de tus tablas de la base de datos. Django
tambin usa modelos para representar conceptos de alto nivel que no necesariamente pueden ser manejados por SQL.
Si ests familiarizado con base de datos, inmediatamente podra pensar, No es redundante denir modelos de
datos en Python y en SQL? Django trabaja de este modo por varias razones:
La introspeccin requiere
de acceso a los datos, Django necesita conocer de alguna forma la capa de la base de datos, y hay
dos formas de lograr esto. La primera sera describir explcitamente los datos en Python, y la segunda
sera la introspeccin de la base de datos en tiempo de ejecucin para determinar el modelo de la base
de datos.
La segunda forma parece clara, porque los metadatos sobre tus tablas vive en un nico lugar, pero
introduce algunos problemas. Primero, introspeccionar una base de datos en tiempo de ejecucin
obviamente requiere overhead. Si el framework tuviera que introspeccionar la base de datos cada vez
que se procese una peticin, o incluso cuando el servidor web sea inicializado, esto podra provocar
un nivel de overhead inaceptable. (Mientras algunos creen que el nivel de overhead es aceptable,
los desarrolladores de Django apuntan a quitar del framework tanto overhead como sea posible, y
esta aproximacin hace que Django sea ms rpido que los frameworks competidores de alto nivel en
mediciones de desempeo). Segundo, algunas bases de datos, notablemente viejas versiones de MySQL,
no guardan suciente metadatos para asegurarse una completa introspeccin.
Escribir Python es divertido, y dejar todo en Python limita el nmero de veces que tu cerebro tiene
que realizar un cambio de contexto. Si te mantienes en un solo entorno/mentalidad de programacin
tanto tiempo como sea posible, ayuda para la productividad. Teniendo que escribir SQL, luego Python,
y luego SQL otra vez es perjudicial.
Tener modelos de datos guardados como cdigo en vez de en tu base de datos hace fcil dejar tus
modelos bajo un control de versiones. De esta forma, puedes fcilmente dejar rastro de los cambios a
tu capa de modelos.
SQL permite slo un cierto nivel de metadatos acerca de un
de base de datos, por ejemplo, no provee un tipo de datos especializado para representar una direccin
web o de email. Los modelos de Django s. La ventaja de un tipo de datos de alto nivel es la alta
productividad y la reusabilidad de cdigo.
SQL es inconsistente a travs de distintas plataformas. Si ests redistribuyendo una aplicacin web,
por ejemplo, es mucho ms pragmtico distribuir un mdulo de Python que describa tu capa de datos
que separar conjuntos de sentencias
CREATE TABLE
Una contra de esta aproximacin, sin embargo, es que es posible que el cdigo Python quede fuera de sincrona
respecto a lo que hay actualmente en la base. Si haces cambios en un modelo Django, necesitars hacer los mismos
cambios dentro de tu base de datos para mantenerla consistente con el modelo. Detallaremos algunas estrategias para
manejar este problema ms adelante en este captulo.
Finalmente, Django incluye una utilidad que puede generar modelos haciendo introspeccin sobre una base de datos
existente. Esto es til para comenzar a trabajar rpidamente sobre datos heredados.
5.6.
Tu primer modelo
Como ejemplo continuo en este captulo y el siguiente, nos enfocaremos en una conguracin de datos bsica sobre
libro/autor/editor. Usamos esto como ejemplo porque las relaciones conceptuales entre libros, autores y editores son
bien conocidas, y es una conguracin de datos comnmente utilizada en libros de texto introductorios de SQL. Por
otra parte, ests leyendo un libro que fue escrito por autores y producido por un editor!
Supondremos los siguientes conceptos, campos y relaciones:
Un autor tiene un ttulo (ej.: Sr. o Sra.), nombre, apellido, direccin de correo electrnico y una foto
tipo carnet.
Un editor tiene un nombre, una direccin, una ciudad, un estado o provincia, un pas y un sitio Web.
revisin 757 del 28 de julio de 2008
53
Un libro tiene un ttulo y una fecha de publicacin. Tambin tiene uno o ms autores (una relacin
muchos-a-muchos con autores) y un nico editor (una relacin uno a muchos -- tambin conocida
como clave fornea -- con editores).
El primer paso para utilizar esta conguracin de base de datos con Django es expresarla como cdigo Python. En
el archivo
models.py
startapp,
ingresa lo siguiente:
django.db.models.Model.
La clase antecesora,
Model,
contiene toda la maquinaria necesaria para hacer que estos objetos sean capaces de interactuar con la base de datos -y que hace que nuestros modelos slo sean responsables de denir sus campos, en una sintaxis compacta y agradable.
Lo creas o no, ste es todo el cdigo que necesitamos para tener acceso bsico a los datos con Django.
Cada modelo generalmente corresponde a una tabla nica de la base de datos, y cada atributo de un modelo
generalmente corresponde a una columna en esa tabla. El nombre de atributo corresponde al nombre de columna, y
el tipo de campo (ej.:
modelo
Publisher
CharField)
el
CREATE TABLE
Book
tiene un
ManyToManyField llamado authors. Esto signica que un libro tiene uno o ms autores, pero
Book no tiene una columna authors. En su lugar, Django crea una tabla adicional -- una
id.
Es un requerimiento el que cada modelo Django tenga una clave primaria de columna simple.
54
5.7.
Instalando el modelo
Ya escribimos el cdigo; creemos ahora las tablas en la base de datos. Para hacerlo, el primer paso es activar estos
books
INSTALLED_APPS. INSTALLED_APPS
settings.py
le indica a Django qu aplicaciones estn activadas para un proyecto determinado. Por omisin, se ve como esto:
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
)
Temporalmente, comenta estos cuatro strings poniendo un carcter (#) al principio. (Estn incluidos por omisin
porque es frecuente usarlas, pero las activaremos y las discutiremos ms adelante) Cuando termines, modica las
conguraciones por omisin de
MIDDLEWARE_CLASSES
de algunas
de manera
MIDDLEWARE_CLASSES = (
#
'django.middleware.common.CommonMiddleware',
#
'django.contrib.sessions.middleware.SessionMiddleware',
#
'django.contrib.auth.middleware.AuthenticationMiddleware',
#
'django.middleware.doc.XViewMiddleware',
)
TEMPLATE_CONTEXT_PROCESSORS = ()
#...
INSTALLED_APPS = (
#'django.contrib.auth',
#'django.contrib.contenttypes',
#'django.contrib.sessions',
#'django.contrib.sites',
'mysite.books',
)
(Como aqu estamos tratando con una tupla de un solo elemento, no olvides la coma nal. De paso, los autores de
este libro preeren poner una coma despus de cada elemento de una tupla, aunque la tupla tenga slo un elemento.
Esto evita el problema de olvidar comas, y no hay penalizacin por el use de esa coma extra)
'mysite.books' se reere a la aplicacin books en la que estamos trabajando. Cada aplicacin en INSTALLED_APPS
es representada por su ruta Python completa -- esto es, la ruta de paquetes, separados por puntos, que lleva al paquete
de la aplicacin.
Ahora que la aplicacin Django ha sido activada en el archivo de conguracin, podemos crear las tablas en nuestra
base de datos. Primero, validemos los modelos ejecutando este comando:
El comando
mensaje
books
Tiende a
CREATE TABLE
para
55
BEGIN;
CREATE TABLE "books_publisher" (
"id" serial NOT NULL PRIMARY KEY,
"name" varchar(30) NOT NULL,
"address" varchar(50) NOT NULL,
"city" varchar(60) NOT NULL,
"state_province" varchar(30) NOT NULL,
"country" varchar(50) NOT NULL,
"website" varchar(200) NOT NULL
);
CREATE TABLE "books_book" (
"id" serial NOT NULL PRIMARY KEY,
"title" varchar(100) NOT NULL,
"publisher_id" integer NOT NULL REFERENCES "books_publisher" ("id"),
"publication_date" date NOT NULL
);
CREATE TABLE "books_author" (
"id" serial NOT NULL PRIMARY KEY,
"salutation" varchar(10) NOT NULL,
"first_name" varchar(30) NOT NULL,
"last_name" varchar(40) NOT NULL,
"email" varchar(75) NOT NULL,
"headshot" varchar(100) NOT NULL
);
CREATE TABLE "books_book_authors" (
"id" serial NOT NULL PRIMARY KEY,
"book_id" integer NOT NULL REFERENCES "books_book" ("id"),
"author_id" integer NOT NULL REFERENCES "books_author" ("id"),
UNIQUE ("book_id", "author_id")
);
CREATE INDEX books_book_publisher_id ON "books_book" ("publisher_id");
COMMIT;
Observa lo siguiente:
Los nombres de tabla se generan automticamente combinando el nombre de la aplicacin (books) y
id.
"_id"
CREATE TABLE
REFERENCES
manera que Django maneja automticamente los tipos de campo especcos de cada base de datos,
como
auto_increment
(MySQL),
serial
(PostgreSQL), o
Lo mismo sucede con el uso de las comillas simples o dobles en los nombres de columna. La salida del
ejemplo est en la sintaxis de PostgreSQL.
El comando
sqlall
no crea ni toca de ninguna forma tu base de datos -- slo imprime una salida en la pantalla
para que puedas ver qu SQL ejecutara Django si le pidieras que lo hiciera. Si quieres, puedes copiar y pegar este
fragmento de SQL en tu cliente de base de datos, o usa los pipes de Unix para pasarlo directamente. De todas formas,
Django provee una manera ms fcil de conrmar el envo del SQL a la base de datos. Ejecuta el comando
esta manera:
syncdb
de
56
syncdb
es una simple sincronizacin de tus modelos hacia tu base de datos. El mismo examina todos
para ver si las tablas apropiadas ya existen, y las crea si no existen. Observa que
python manage.py syncdb de nuevo, nada sucede, porque no has agregado ningn modelo a la aplibooks ni has incorporado ninguna aplicacin en INSTALLED_APPS. Ergo, siempre es seguro ejecutar python
manage.py syncdb -- no har desaparecer cosas.
Si ejecutas
cacin
Si ests interesado, toma un momento para bucear en el cliente de lnea de comandos de tu servidor de bases de
psql para
python manage.py dbshell, que deducir qu cliente de linea de comando
DATABASE_SERVER. Esto ltimo es casi siempre ms conveniente.
datos y ver las tablas que cre Django. Puedes ejecutar manualmente el cliente de lnea de comandos (ej.:
PostgreSQL) o puedes ejecutar el comando
ejecutar, dependiendo de tu conguracin
5.8.
Una vez que has creado un modelo, Django provee automticamente una API Python de alto nivel para trabajar
con estos modelos. Prueba ejecutando
y escribiendo lo siguiente:
INSERT.
Publisher
save()
SELECT.
Naturalmente, puedes hacer mucho con la API de base de datos de Django -- pero primero, tengamos cuidado de
una pequea incomodidad.
5.9.
Cuando imprimimos la lista de editores, todo lo que obtuvimos fue esta salida poco til que haca difcil distinguir
los objetos
Publisher:
57
ms fcil de entender:
__str__()
cuando usas el intrprete interactivo, sino tambin porque Django usa la salida de
__str__()
en muchos lugares
__str__()
Django describe ms que la conguracin de la tabla de la base de datos; tambin describe toda funcionalidad que el
objeto sepa hacer.
5.10.
__str__()
Ya has visto cmo se hace: para insertar una la en tu base de datos, primero crea una instancia de tu modelo
usando argumentos por nombre, como:
58
>>> p = Publisher(name='Apress',
...
address='2855 Telegraph Ave.',
...
city='Berkeley',
...
state_province='CA',
...
country='U.S.A.',
...
website='http://www.apress.com/')
Este acto de instanciar una clase modelo no toca la base de datos.
Para guardar el registro en la base de datos (esto es, para realizar la sentencia SQL
save()
INSERT),
llama al mtodo
del objeto:
>>> p.save()
En SQL, esto puede ser traducido directamente en lo siguiente:
Publisher
id,
la llamada inicial a
ms: calcula el valor de la clave primaria para el registro y lo establece como el valor del atributo
>>> p.id
52
# esto ser diferente segn tus datos
save() guardarn el registro
UPDATE en lugar de un INSERT):
save()
5.11.
Seleccionar objetos
La creacin y actualizacin de datos seguro es divertida, pero tambin es intil sin una forma de tamizar los datos.
Ya hemos visto una forma de examinar todos los datos de un determinado modelo:
>>> Publisher.objects.all()
[<Publisher: Addison-Wesley>, <Publisher: O'Reilly>, <Publisher: Apress Publishing>]
Eso se traslada a esto en SQL:
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher;
Nota
Nota que Django no usa
SELECT *
SELECT *
puede
ser lento, y (ms importante) listar los campos sigue el principio del Zen de Python: Explcito es
mejor que implcito.
Para ms sobre el Zen de Python, intenta escribiendo
import this
en el prompt de Python.
59
Publisher.objects.all():
Publisher.
objects.
son discutidos en el Apndice B. Por ahora, todo lo que necesitas saber es que los administradores se
encargan de todas las operaciones a nivel de tablas sobre los datos incluidos, y lo ms importante,
las consultas.
Todos los modelos automticamente obtienen un administrador
objects;
all(). Este es un mtodo del administrador objects que retorna todas las las
de la base de datos. Aunque este objeto se parece a una lista, es actualmente un QuerySet -- un
objeto que representa algn conjunto de las de la base de datos. El Apndice C describe QuerySets
en detalle. Para el resto de este captulo, slo trataremos estos como listas emuladas.
Cualquier bsqueda en base de datos va a seguir esta pauta general -- llamaremos mtodos del administrador
adjunto al modelo en el cual queremos hacer nuestra consulta.
5.11.1.
Filtrar datos
Aunque obtener todos los objetos es algo que ciertamente tiene su utilidad, la mayora de las veces lo que vamos a
necesitar es manejarnos slo con un subconjunto de los datos. Para ello usaremos el mtodo
filter():
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher
WHERE name = 'Apress Publishing';
Puedes pasarle a
filter()
se traduce a lo siguiente:
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher
WHERE country = 'U.S.A.' AND state_province = 'CA';
Notar que por omisin la bsqueda usa el operador SQL
tipos de bsquedas:
>>> Publisher.objects.filter(name__contains="press")
[<Publisher: Apress Publishing>]
Notar el doble guin bajo entre
name
contains.
Del mismo modo que Python, Django usa el doble guin bajo
LIKE:
__contains
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher
WHERE name LIKE ' %press %';
icontains (LIKE no sensible a diferencias de mayscustartswith y endswith, y range (consultas SQL BETWEEN). El Apndice C describe en detalle todos
60
5.11.2.
get():
>>> Publisher.objects.get(country="U.S.A.")
Traceback (most recent call last):
...
AssertionError: get() returned more than one Publisher -- it returned 2!
Una consulta que no retorne objeto alguno tambin causar una excepcin:
>>> Publisher.objects.get(name="Penguin")
Traceback (most recent call last):
...
DoesNotExist: Publisher matching query does not exist.
5.11.3.
Ordenando datos
A medida que juegas con los ejemplos anteriores, podras descubrir que los objetos so devueltos en lo que parece
ser un orden aleatorio. No ests imaginndote cosas, hasta ahora no le hemos indicado a la base de datos cmo ordenar
sus resultados, de manera que simplemente estamos recibiendo datos con algn orden arbitrario seleccionado por la
base de datos.
Eso es, obviamente, un poco
*silly* (tonto), no querramos que una pgina Web que muestra una lista de editores
>>> Publisher.objects.order_by("name")
[<Publisher: Apress Publishing>, <Publisher: Addison-Wesley>, <Publisher: O'Reilly>]
Esto no se ve muy diferente del ejemplo de
all()
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher
ORDER BY name;
Podemos ordenar por cualquier campo que deseemos:
>>> Publisher.objects.order_by("address")
[<Publisher: O'Reilly>, <Publisher: Apress Publishing>, <Publisher: Addison-Wesley>]
>>> Publisher.objects.order_by("state_province")
[<Publisher: Apress Publishing>, <Publisher: Addison-Wesley>, <Publisher: O'Reilly>]
y por mltiples campos:
(el smbolo
menos):
>>> Publisher.objects.order_by("-name")
[<Publisher: O'Reilly>, <Publisher: Apress Publishing>, <Publisher: Addison-Wesley>]
Aunque esta exibilidad es til, usar
order_by()
del tiempo tendrs un campo particular por el que usualmente desears ordenar. Es esos casos Django te permite
anexar al modelo un ordenamiento por omisin para el mismo:
61
class Publisher(models.Model):
name = models.CharField(maxlength=30)
address = models.CharField(maxlength=50)
city = models.CharField(maxlength=60)
state_province = models.CharField(maxlength=30)
country = models.CharField(maxlength=50)
website = models.URLField()
def __str__(self):
return self.name
class Meta:
ordering = ["name"]
ordering = ["name"] le indica a Django que a menos que
order_by(), todos los editores debern ser ordenados por su nombre.
Este fragmento
diante
class Meta
adicionales acerca de un modelo. Es completamente opcional, pero puede realizar algunas cosas
muy tiles. Examina el Apndice B para conocer las opciones que puede poner bajo
5.11.4.
Meta.
Encadenando bsquedas
Has visto cmo puedes ltrar datos y has visto cmo ordenarlos. En ocasiones, por supuesto, vas a desear realizar
ambas cosas. En esos casos simplemente encadenas las bsquedas entre s:
>>> Publisher.objects.filter(country="U.S.A.").order_by("-name")
[<Publisher: O'Reilly>, <Publisher: Apress Publishing>, <Publisher: Addison-Wesley>]
Como podras esperar, esto se traduce a una consulta SQL conteniendo tanto un
WHERE
como un
ORDER BY:
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher
WHERE country = 'U.S.A'
ORDER BY name DESC;
Puedes encadenar consultas en forma consecutiva tantas veces como desees. No existe un lmite para esto.
5.11.5.
Rebanando datos
Otra necesidad comn es buscar slo un nmero jo de las. Imagina que tienes miles de editores en tu base de
datos, pero quieres mostrar slo el primero. Puedes hacer eso usando la sintaxis estndar de Python para el rebanado
de listas:
>>> Publisher.objects.all()[0]
<Publisher: Addison-Wesley>
Esto se traduce, someramente, a:
SELECT
id, name, address, city, state_province, country, website
FROM book_publisher
ORDER BY name
LIMIT 1;
Y ms...
Hemos slo araado la supercie del manejo de modelos, pero deberas ya conocer lo suciente
para entender todos los ejemplos del resto del libro. Cuando ests listo para aprender los detalles
completos detrs de las bsquedas de objetos, chale una mirada al Apndice C.
62
5.12.
Eliminando objetos
delete()
de tu objeto:
>>> p = Publisher.objects.get(name="Addison-Wesley")
>>> p.delete()
>>> Publisher.objects.all()
[<Publisher: Apress Publishing>, <Publisher: O'Reilly>]
Puedes tambin borrar objetos al por mayor llamando a
delete()
Entonces, si descubres que has cometido un error, puedes simplemente volver a conmutar el estado
de la bandera.
5.13.
syncdb previamente en este captulo, hicimos notar que syncdb simplemente crea
tablas que todava no existen en tu base de datos -- no sincroniza cambios en modelos ni borra modelos. Si agregas o
modicas un campo de un modelo o si eliminas un modelo, ser necesario que realices el cambio en tu base de datos
en forma manual. Esta seccin explica cmo hacerlo.
Cuando ests realizando cambios de esquema, es importante tener presente algunas caractersticas de la capa de
base de datos de Django:
Django se quejar estrepitosamente si un modelo contiene un campo que todava no ha sido creado en
la tabla de la base de datos. Esto causar un error la primera vez que uses la API de base de datos de
Django para consultar la tabla en cuestin (esto es, ocurrir en tiempo de ejecucin y no en tiempo
de compilacin).
A Django no le importa si una tabla de base de datos contiene columnas que no estn denidas en el
modelo.
A Django no le importa si una base de datos contiene una tabla que no est representada por un
modelo.
El realizar cambios al esquema de una base de datos es cuestin de cambiar las distintas piezas -- el cdigo Python
y la base de datos en s misma -- en el orden correcto.
5.13.1.
Agregando campos
Cuando se agrega un campo a una tabla/modelo en un entorno de produccin, el truco es sacar ventaja del hecho
que a Django no le importa si una tabla contiene columnas que no estn denidas en el modelo. La estrategia es
agregar la columna en la base de datos y luego actualizar el modelo Django para que incluya el nuevo campo.
Sin embargo, tenemos aqu un pequeo problema del huevo y la gallina, porque para poder saber cmo debe
expresarse la nueva columna en SQL, necesitas ver la salida producida por el comando
el cual requiere que el campo exista en el modelo. (Notar que no es un requerimiento el que crees tu columna con
exactamente el mismo SQL que usara Django, pero es una buena idea el hacerlo para estar seguros de que todo est
en sincrona).
La solucin al problema del huevo y la gallina es usar un entorno de desarrollo en lugar de realizar los cambios en
un servidor de produccin. (Ests usando un entorno de pruebas/desarrollo, no es cierto?). Este es el detalle de los
pasos a seguir.
Primero, realiza los siguientes pasos en el entorno de desarrollo (o sea, no en el servidor de produccin):
revisin 757 del 28 de julio de 2008
63
CREATE TABLE
para el mo-
dbshell).
ALTER TABLE
psql
mysql,
o puedes usar
manage.py
manage.py shell
campo haya sido agregado correctamente importando el modelo y seleccionando desde la tabla
(por ej.
MyModel.objects.all()[:5]).
ALTER TABLE
svn update
si usas Subversion) en el
servidor de produccin.
4. Reinicia el servidor Web para que los cambios en el cdigo surtan efecto.
Por ejemplo, hagamos un repaso de los que haramos si agregramos un campo
previamente en este captulo. Primero, alteraramos el modelo en nuestro entorno de desarrollo para que se viera as:
class Book(models.Model):
title = models.CharField(maxlength=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
num_pages = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.title
(Nota: Revisa el apartado Agregando columnas NOT NULL para conocer detalles importantes acerca de porqu
hemos incluido
blank=True
null=True).
manage.py sqlall books para ver la sentencia CREATE TABLE. La misma se vera
psql
64
blank=True
null=True.
num_pages
columna de una base de datos contendr inicialmente valores NULL desde el momento que la
crees.
Sin embargo, es tambin posible agregar columnas que no puedan contener valores NULL. Para
hacer esto, tienes que crear la columna como
algunos valor(es) por omisin, y luego modicar la columna para activar el modicador
Por ejemplo:
BEGIN;
ALTER TABLE books_book ADD COLUMN num_pages integer;
UPDATE books_book SET num_pages=0;
ALTER TABLE books_book ALTER COLUMN num_pages SET NOT NULL;
COMMIT;
Si sigues este camino, recuerda que debes quitar
Luego de la sentencia
ALTER TABLE,
blank=True
null=True
de tu modelo.
ALTER TABLE
5.13.2.
Eliminando campos
Eliminar un campo de un modelo es mucho ms fcil que agregar uno. Para borrar un campo, slo sigue los
siguientes pasos:
1. Elimina el campo de tu modelo y reinicia el servidor Web.
2. Elimina la columna de tu base de datos, usando un comando como este:
Debido a que los campos many-to-many son diferentes a los campos normales, el proceso de borrado es diferente:
1. Elimina el campo
ManyToManyField
Eliminando modelos
Eliminar completamente un modelo es tan fcil como el eliminar un campo. Para borrar un modelo, sigue los
siguientes pasos:
1. Elimina el modelo de tu archivo
models.py
5.14. QU SIGUE?
5.14.
65
Qu sigue?
Una vez que has denido tus modelos, el paso siguiente es el poblar tu base de datos con datos. Podras tener datos
legados, en cuyo caso el Captulo 16 te aconsejar acerca de cmo integrar bases de datos heredadas. Podras delegar
en los usuario del sitio la provisin de los datos, en cuyo caso el Captulo 7 te ensear cmo procesar datos enviados
por los usuarios mediante formularios.
Pero en algunos casos, t o tu equipo podran necesitar ingresar datos en forma manual, en cuyo caso sera de
ayuda el disponer de una interfaz basada en Web para el ingreso y el manejo de los datos. El
`prximo captulo`_
est dedicado a la interfaz de administracin de Django, la cual existe precisamente por esa razn.
Duplicate explicit target name: prximo captulo.
66
Captulo 6
6.1.
Pensamos que la interfaz de administracin es la caracterstica ms atractiva de Django -- y la mayora de Djangonautas estn de acuerdo -- pero como no todo el mundo lo necesita, es una pieza opcional. Esto signica que hay
que dar tres pasos para activar la interfaz de administracin:
1. Agrega meta-datos de administracin a tus modelos.
No todos los modelos pueden (o deberan) ser editables por los usuarios administradores, por lo
que necesitas marcar los modelos que deberan tener una interfaz de administracin. Esto lo
hacemos aadiendo al modelo una clase interna
Admin
Meta, si es
Book del
que hay
captulo
anterior, usamos:
class Book(models.Model):
title = models.CharField(maxlength=100)
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
num_pages = models.IntegerField(blank=True, null=True)
def __str__(self):
return self.title
La
class Admin:
pass
declaracin de Admin
est vaca.
revisin 757 del 28 de julio de 2008
Admin
68
Si ests siguiendo este ejemplo escribiendo tu propio cdigo, probablemente sea buena idea agregar ahora declaraciones de
2. Instalar la aplicacin
Admin
a las clases
Publisher
Author.
de tu archivo de conguracin
"django.contrib.sessions", "django.contrib.auth",
admin depende
de ellas. Tambin descomenta todas las lneas de MIDDLEWARE_CLASSES congurando la tupla,
y borra la denicin de TEMPLATE_CONTEXT_PROCESSOR para permitir que tome los valores por
"django.contrib.contenttypes"
defecto.
4. Ejecuta
Nota
Es probable que la primera vez que ejecutaste
syncdb
con
"django.contrib.auth"
en INSTA-
django/contrib/auth/bin/create_superuser.py
rio administrador. En caso contrario no sers capaz de identicarte para entrar a la interfaz de
administracin.
5. Agrega el patrn de URL en tu
el patrn de la URL de administracin ya debera estar ah, pero comentado. De cualquier forma,
los patrones de URL deberan terminar siendo algo as:
esto:
Validating models...
0 errors found.
Django version 0.97, using settings 'mysite.settings'
Development server is running at http://127.0.0.1:8000/
Quit the server with CONTROL-C.
Ahora puedes visitar la URL que te brinda Django (http://127.0.0.1:8000/admin/ en el ejemplo precedente),
identicarte, y jugar un poco.
6.2.
La interfaz de administracin est diseada para ser usada por usuarios no tcnicos, y como tal debera ser lo
sucientemente clara como para explicarse por s misma. An as, se brindan unas pocas notas sobre sus caractersticas.
Lo primero que vers es una pgina de identicacin, como se muestra en la Figura 6-1.
Usars el nombre de usuario y la clave que conguraste cuando agregaste tu superusuario. Una vez identicado,
vers que puedes gestionar usuarios, grupos y permisos (veremos ms sobre esto en breve).
Cada objeto al que se le di una declaracin
la Figura 6-2
6 y
Los enlaces para agregar y modicar objetos llevan a dos pginas a las que nos referiremos como
formularios de edicin
7 de objetos:
listas de cambio
Las listas de cambio son esencialmente pginas de ndices de objetos en el sistema, como se muestra en la Figura
6-3.
Hay varias opciones que pueden controlar los campos que aparecen en esas listas y la aparicin de caractersticas
extra como campos de bsqueda e accesos directo a ltros predenidos. Ms adelante hablaremos sobre esto.
Los formularios de edicin se usan para modicar objetos existente y crear nuevos (mira la Figura 6-4). Cada
campo denido en tu modelo aparece aqu, y notars que campos de tipos diferentes tienen diferentes controles. (Por
ejemplo, los campos de fecha/hora tienen controles tipo calendario, las claves forneas usan cajas de seleccin, etc.)
69
70
71
72
73
Te dars cuenta que la interfaz de administracin tambin controla por ti la validez de los datos ingresado. Intenta
dejar un campo requerido en blanco o poner una fecha invlida en un campo de fecha, y vers esos avisos de esos
errores cuando intentes guardar el objeto, como se muestra en la Figura 6-5.
Cuando editas un objeto existente, vers el botn Historia en la esquina superior derecha de la ventana. Cada
cambio realizado a travs de la interfaz de administracin es registrado, y puedes examinar este registro haciendo click
en este botn (mira la Figura 6-6).
Cuando eliminas un objeto existente, la interfaz de administracin solicita una conrmacin para prevenir costosos
errores. La eliminacin de un objeto se desencadena en cascada, y la pgina de conrmacin de eliminacin del objeto
muestra todos los objetos relacionados que se eliminarn con l (mira la Figura 6-7).
6.2.1.
Desde que ests identicado como un superusuario, tienes acceso a crear, editar y eliminar cualquier objeto. Sin
embargo, la interfaz de administracin tiene un sistema de permisos de usuario que puedes usar para darle a otros
usuarios acceso limitado a las partes de la interfaz que ellos necesitan.
Puedes editar estos usuarios y permisos a travs de la interfaz de administracin, como si fuese cualquier otro
objeto. Los vnculos a los modelos
usuario
tienen el los campos estndar nombre de usuario, contrasea, direccin de correo, y nombre
real que puedes esperar, seguidos de un conjunto de campos que denen lo que el usuario tiene permitido hacer en la
interfaz de administracin. Primero, hay un conjunto de tres opciones seleccionables:
La opcin Es sta indica que el usuario est habilitado a ingresar a la interfaz de administracin
(por ejemplo, indica que el usuario es considerado un miembro del sta en tu organizacin). Como
el mismo sistema de usuarios puede usarse para controlar el acceso al sitio pblico (es decir, sitios
restringidos no administrativos. Mira el Captulo 12.), esta opcin diferencia entre usuarios pblicos
y administradores.
La opcin Activo dene si el usuario est activo en todo sentido. Si est desactivada, el usuario no
tendr acceso a ninguna URL que requiera identicacin.
La opcin es superusuario da al usuario completo e irrestricto acceso a todos los elementos de la
interfaz de administracin, y sus permisos regulares son ignorados.
Los administradores normales -- esto es, activos, no superusuarios y miembros del sta -- tienen accesos que
dependen del conjunto de permisos concedidos. Cada objeto editable a travs de la interfaz de administracin tiene
tres permisos: un permiso de crear
permisos a un usuario habilitas que este acceda a realizar la accin que el permiso describe.
Nota
El acceso a editar usuarios y permisos tambin es controlado por el sistema de permisos. Si le das
a alguien el permiso de editar usuarios, estar en condiciones de editar sus propios permisos, que
probablemente no es lo que queras!
Tambin puedes asignar usuarios a grupos. Un grupo es simplemente un conjunto de permisos a aplicar a todos los
usuarios de ese grupo. Los grupos son tiles para otorgar idnticos permisos a un gran nmero de usuarios.
6.3.
Puedes personalizar el aspecto y la forma en que la interfaz de administracin se comporta de varias maneras. En
esta seccin slo vamos a cubrir algunas de ellas relacionadas con nuestro modelo
Libro.
El Captulo 17 descubre la
__str__
Esto funciona bien slo para algunos libros, pero si tuviramos cientos o miles de libros, se volvera tan difcil como
encontrar una aguja en un pajar. Sin embargo, fcilmente podremos agregar algunas columnas, funciones de bsqueda
y ltros y a esta interfaz. Cambia la declaracin de
Admin
como sigue:
class Book(models.Model):
title = models.CharField(maxlength=100)
revisin 757 del 28 de julio de 2008
74
75
76
77
authors = models.ManyToManyField(Author)
publisher = models.ForeignKey(Publisher)
publication_date = models.DateField()
class Admin:
list_display = ('title', 'publisher', 'publication_date')
list_filter = ('publisher', 'publication_date')
ordering = ('-publication_date',)
search_fields = ('title',)
Estas cuatro lneas de cdigo cambian dramticamente la interfaz de nuestra lista, como se muestra en la gura
6-8.
Cada una de estas lneas indica a la interfaz de administracin que construya diferentes piezas de la interfaz:
La opcin
list_display controla que columnas aparecen en la tabla de la lista. Por defecto, la lista de
cambios muestra una sola columna que contiene la representacin en cadena de caracteres del objeto.
Aqu podemos cambiar eso para mostrar el ttulo, el editor y la fecha de publicacin.
La opcin
list_filter
crea una barra de ltrado del lado derecho de la lista. Estaremos habilitados
a ltrar por fecha (que te permite ver slo los libros publicados la ltima semana, mes, etc.) y por
editor.
Puedes indicarle a la interfaz de administracin que ltre por cualquier campo, pero las claves forneas,
fechas, booleanos, y campos con un atributo de opciones
choices
ordering
ministracin. Es simplemente una lista de campos con los cuales ordenar el resultado; anteponiendo
un signo menos a un campo se obtiene el orden reverso. En este ejemplo, ordenamos por fecha de
publicacin con los ms recientes al principio.
Finalmente, la opcin
Usando estas opciones (y las otras descriptas en el captulo 17) puedes, con slo algunas lneas de cdigo, hacer
una interfaz de edicin de datos realmente potente y lista para produccin.
6.4.
Claramente, tener la frase Administracin de Django en la cabecera de cada pgina de administracin es ridculo.
Es slo un texto de relleno que es fcil de cambiar, usando el sistema de plantillas de Django. El sitio de administracin
de Django est propulsado por el mismo Django, sus interfaces usan el sistema de plantillas propio de Django. (El
sistema de plantillas de Django fue presentado en el Captulo 4.)
Como explicamos en el Captulo 4, la conguracin de
cuando se cargan plantillas Django. Para personalizar las plantillas del sitio de administracin, simplemente copia el
conjunto relevante de plantillas de la distribucin Django en uno de los directorios apuntados por
TEMPLATE_DIRS.
El sitio de administracin muestra Administracin de Django en la cabecera porque esto es lo que se incluye en la
de Django,
base_site.html: copia esta desde el directorio original a tu directorio personalizado y haz los
TEMPLATE_DIRS
defecto de la interfaz de administracin. La respuesta es que, por defecto, Django automticamente busca plantillas
dentro del subdirectorio
templates/ de cada paquete de aplicacin como alternativa. Mira el captulo 10 para obtener
78
6.5.
79
En una nota similar, puedes tener la intencin de personalizar la apariencia (el look & feel ) de la pgina principal
del administrador. Por defecto, aqu se muestran todas las aplicaciones, de acuerdo a la conguracin que tenga
INSTALLED_APPS,
ordenados por el nombre de la aplicacin. Quizs quieras, por ejemplo, cambiar el orden para hacer
ms fcil ubicar determinada aplicacin que ests buscando. Despus de todo, la pgina inicial es probablemente la
ms importante de la interfaz de administracin, y debera ser fcil utilizarla.
La plantilla para personalizarla es
tillas propio como en el ejemplo previo). Edita el archivo, y vers que usa una etiqueta llamada
as app_list %}. Esta etiqueta devuelve todas las aplicaciones Django instaladas. En vez de usar esta etiqueta, puedes
incluir vnculos explcitos a objetos especcos de la manera que creas ms conveniente. Si cdigo explcito en una
plantilla no te satisface, puedes ver el
etiquetas de plantillas.
Django ofrece otro acceso directo en este apartado. Ejecuta el comando
para obtener un pedazo de cdigo de plantilla para incluir en la pgina ndice del administrador. Es un punto de partida
bastante til.
Para detalles completos sobre la personalizacin del sitio de administracin de Django, mira el Captulo 17.
6.6.
Pensamos que la interfaz de administracin de Django es bastante espectacular. De hecho, diramos que es una
de sus killer feautures, o sea, una de sus caractersticas sobresalientes. Sin embargo, a menudo nos preguntan sobre
casos de uso para la interfaz de administracin (Cundo debemos usarlo y por qu?). A lo largo de los aos, hemos
descubierto algunos patrones donde pensamos que usar la interfaz de administracin resulta til.
Obviamente, es muy til para modicar datos (se vea venir). Si tenemos cualquier tipo de tarea de introduccin
de datos, el administrador es difcil de superar. Sospechamos que la gran mayora de lectores de este libro tiene una
horda de tareas de este tipo.
La interfaz de administracin de Django brilla especialmente cuando usuarios no tcnicos necesitan ser capaces de
ingresar datos; ese es el propsito detrs de esta caracterstica, despus de todo. En el peridico donde Django fue
creado originalmente, el desarrollo una caracterstica tpica online -- un reporte especial sobre la calidad del agua del
acueducto municipal, pongamos -- implicaba algo as:
El periodista responsable del artculo se rene con uno de los desarrolladores y discuten sobre la
informacin disponible.
El desarrollador disea un modelo basado en esta informacin y luego abre la interfaz de administracin
para el periodista.
Mientras el periodista ingresa datos a Django, el programador puede enfocarse en desarrollar la interfaz
accesible pblicamente (la parte divertida!).
En otras palabras, la razn de ser de la interfaz de administracin de Django es facilitar el trabajo simultneo de
productores de contenido y programadores.
Sin embargo, ms all de estas tareas de entrada de datos obvias, encontramos que la interfaz de administracin
es til en algunos otros casos:
Inspeccionar modelos de datos : La primer cosa que hacemos cuando hemos denido un nuevo modelo
es llamarlo desde la interfaz de administracin e ingresar algunos datos de relleno. Esto es usual para
encontrar errores de modelado; tener una una interfaz grca al modelo revela problemas rpidamente.
Gestin de datos adquiridos : Hay una pequea entrada de datos asociada a un sitio como
http://chicagocrime.or
puesto que la mayora de los datos provienen de una fuente automtica. No obstante, cuando surgen
problemas con los datos automticos, es til poder entrar y editarlos fcilmente.
6.7.
Qu sigue?
Hasta ahora hemos creado algunos modelos y congurado una interfaz de primera clase para modicar datos.
En el
`prximo captulo`_, nos meteremos en el verdadero guiso del desarrollo Web: creacin y procesamiento de
formularios.
80
6 N.
7 N.
8 N.
9 N.
10 N.
del T.:
del T.:
Can change
del T.: Can delete
del T.:
Can add
Captulo 7
Procesamiento de formularios
Autor invitado: Simon Willison
Si has estado siguiendo el captulo anterior, ya deberas tener un sitio completamente funcional, aunque un poco
simple. En este captulo trataremos con la prxima pieza del juego: cmo construir vistas que obtienen entradas desde
los usuarios.
Comenzaremos haciendo un simple formulario de bsqueda a mano, viendo cmo manejar los datos suministrados
al navegador. Y a partir de ah, pasaremos al uso del framework de formularios que trae Django.
7.1.
Bsquedas
En la Web todo se trata de bsquedas. Dos de los casos de xito ms grandes, Google y Yahoo, han construido
sus empresas multimillonarias alrededor de las bsquedas. Casi todos los sitios observan un gran porcentaje de trco
viniendo desde y hacia sus pginas de bsqueda. A menudo, la diferencia entre el xito y el fracaso de un sitio, lo
determina la calidad de su bsqueda. As que sera mejor que agreguemos un poco de bsqueda a nuestro pequeo
sitio de libros, no?
Comenzaremos agregando la vista para la bsqueda a nuestro URLconf (mysite.urls). Recuerda que esto se hace
(patrones).
request.GET.
datos del GET desde Django; Los datos del POST se acceden de manera similar, a travs de un objeto llamado
request.POST.
Estos objetos se comportan exactamente como los diccionarios estndar de Python, y tienen adems
82
/books/search/
http://www.w3.org/2001/tag/doc/whenToUseGet.html
si quieres
aprender ms.
As que la lnea:
mismo que posee cualquier diccionario de Python. Lo estamos usando aqu para ser precavidos: no es seguro asumir
que
''
request.GET
'q',
as que usamos
get('q', '')
KeyError.
request.GET['q'],
no
Q? Los objetos Q se utilizan para ir construyendo consultas complejas -- en este caso, estamos
Q consisten
buscando los libros que coincidan en el ttulo o en el nombre con la consulta. Tcnicamente, estos objetos
de un QuerySet, y puede leer ms sobre esto en el apndice C.
En estas consultas,
icontains
LIKE
Dado que estamos buscando en campos de muchos-a-muchos, es posible que un libro se obtenga ms de una vez
(por ej: un libro que tiene dos autores, y los nombres de ambos concuerdan con la consulta). Al agregar
en el ltrado, se eliminan los resultados duplicados.
Todava no hay una plantilla para esta vista. Esto lo solucionar:
.distinct()
83
A esta altura, lo que esto hace debera ser obvio. Sin embargo, hay unas pocas sutilezas que vale la pena resaltar:
action es
en el formulario, esto signica la URL actual. Esta es una buena prctica estndar: no
utilices vistas distintas para la pgina que contiene el formulario y para la pgina con los resultados;
usa una pgina nica para las dos cosas.
Volvemos a insertar el texto de la consulta en el
query
book,
escape
cualquier bsqueda potencialmente maliciosa sea descartada antes de que se inserte en la pgina
Es vital hacer esto con todo el contenido suministrado por el usuario! De otra forma el sitio se abre a
ataques de cross-site scripting (XSS). El
7.2.
El formulario perfecto
Los formularios pueden ser a menudo una causa importante de frustracin para los usuarios de tu sitio. Consideremos
el comportamiento de un hipottico formulario perfecto:
Debera pedirle al usuario cierta informacin, obviamente. La accesibilidad y la usabilidad importan
aqu. As que es importante el uso inteligente del elemento
<label>
de HTML, y tambin lo es
7.3.
La mejor forma de construir un sitio que la gente ame es atendiendo a sus comentarios. Muchos sitios parecen
olvidar esto; ocultan los detalles de su contacto en FAQs, y parecen dicultar lo ms posible el encuentro con las
personas.
Cuando tu sitio tiene millones de usuarios, esto puede ser una estrategia razonable. En cambio, cuando intentas
formarte una audiencia, deberas pedir comentarios cada vez que se presente la oportunidad. Escribamos entonces un
simple formulario para comentarios, y usmoslo para ilustrar al framework de Django en plena accin.
Comenzaremos agregando
(r'^contact/$', 'mysite.books.views.contact')
nuestro formulario. Los formularios en Django se crean de una manera similar a los modelos: declarativamente, empleando una clase de Python. He aqu la clase para nuestro simple formulario. Por convencin, lo insertaremos en un
nuevo archivo
forms.py
84
a cambiar, y
estar seguros de que los ejemplos de este libro funcionen lo ms ampliamente posible, todos harn
referencia a
django.newforms.
para los campos. Una lista completa de stas ltimas se encuentra disponible en la documentacin de Django, en
http://www.djangoproject.com/documentation/0.96/newforms/.
Nuestro ContactForm consiste de tres campos: un tpico, que se
que es un campo de caracteres; y un emisor, que es un campo de correo electrnico y es opcional (porque incluso los
comentarios annimos pueden ser tiles). Hay una cantidad de otros tipos de campos disponibles, y puedes escribir
nuevos tipos si ninguno cubre tus necesidades.
El objeto formulario sabe cmo hacer una cantidad de cosas tiles por s mismo. Puede validar una coleccin de
datos, puede generar sus propios widgets de HTML, puede construir un conjunto de mensajes de error tiles. Y si
ests en perezoso, puede incluso dibujar el formulario completo por ti. Incluyamos esto en una vista y vemoslo en
accin. En
from
from
from
from
views.py:
django.db.models import Q
django.shortcuts import render_to_response
models import Book
forms import ContactForm
def search(request):
query = request.GET.get('q', '')
if query:
qset = (
Q(title__icontains=query) |
Q(authors__first_name__icontains=query) |
Q(authors__last_name__icontains=query)
)
results = Book.objects.filter(qset).distinct()
else:
results = []
return render_to_response("books/search.html", {
"results": results,
"query": query
})
85
def contact(request):
form = ContactForm()
return render_to_response('contact.html', {'form': form})
y en
contact.html:
al
render_to_response. as_table
as_ul
as_p).
<tr>
<th><label for="id_topic">Topic:</label></th>
<td>
<select name="topic" id="id_topic">
<option value="general">General enquiry</option>
<option value="bug">Bug report</option>
<option value="suggestion">Suggestion</option>
</select>
</td>
</tr>
<tr>
<th><label for="id_message">Message:</label></th>
<td><input type="text" name="message" id="id_message" /></td>
</tr>
<tr>
<th><label for="id_sender">Sender:</label></th>
<td><input type="text" name="sender" id="id_sender" /></td>
</tr>
Observa que las etiquetas
<table> y <form> no se han incluido; debes denirlas por tu cuenta en la plantilla. Esto
te da control sobre el comportamiento del formulario al ser suministrado. Los elementos label s se incluyen, y proveen
a los formularios de accesibilidad desde fbrica.
Nuestro formulario actualmente utiliza un widget
<input type="text">
queremos restringir a nuestros usuarios a una sola lnea de texto, as que la cambiaremos por un widget
<textarea>:
class ContactForm(forms.Form):
topic = forms.ChoiceField(choices=TOPIC_CHOICES)
message = forms.CharField(widget=forms.Textarea())
sender = forms.EmailField(required=False)
El framework de formularios divide la lgica de presentacin para cada campo, en un conjunto de widgets. Cada
tipo de campo tiene un widget por defecto, pero puedes sobreescribirlo fcilmente, o proporcionar uno nuevo de tu
creacin.
Por el momento, si se suministra el formulario, no sucede nada. Agreguemos nuestras reglas de validacin:
86
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
else:
form = ContactForm()
return render_to_response('contact.html', {'form': form})
Una instancia de formulario puede estar en uno de dos estados: bound (vinculado) o unbound (no vinculado). Una
instancia bound se construye con un diccionario (o un objeto que funcione como un diccionario) y sabe cmo validar y
volver a representar sus datos. Un formulario unbound no tiene datos asociados y simplemente sabe cmo representarse
a s mismo.
Intenta hacer clic en Submit en el formulario vaco. La pgina se volver a cargar, mostrando un error de validacin
que informa que nuestro campo de mensaje es obligatorio.
Intenta tambin ingresar una direccin de correo electrnico invlida. El
EmailField
initial:
message = forms.CharField(widget=forms.Textarea(),
initial="Replace with your feedback")
7.4.
Una vez que el usuario ha llenado el formulario al punto de que pasa nuestras reglas de validacin, necesitamos
hacer algo til con los datos. En este caso, deseamos construir un correo electrnico que contenga los comentarios del
usuario, y enviarlo. Para esto, usaremos el paquete de correo electrnico de Django.
Pero antes, necesitamos saber si los datos son en verdad vlidos, y si lo son, necesitamos una forma de accederlos.
El framework de formularios hace ms que validar los datos, tambin los convierte a tipos de datos de Python.
IntegerField o
DateTimeField, el framework de formularios se encarga de que se devuelvan como un valor entero de Python, o como
un objeto datetime, respectivamente.
Para saber si un formulario est vinculado (bound ) a datos vlidos, llamamos al mtodo is_valid():
Nuestro formulario para comentarios slo trata con texto, pero si estamos usando campos como
form = ContactForm(request.POST)
if form.is_valid():
# Process form data
Ahora necesitamos acceder a los datos. Podramos sacarlos directamente del
request.POST,
pero si lo hiciramos,
no nos estaramos beneciando de la conversin de tipos que realiza el framework de formularios. En cambio, usamos
form.clean_data:
if form.is_valid():
topic = form.clean_data['topic']
message = form.clean_data['message']
sender = form.clean_data.get('sender', '[email protected]')
# ...
Observa que dado que
sender
Finalmente, necesitamos registrar los comentarios del usuario. La manera ms fcil de hacerlo es enviando un correo
electrnico al administrador del sitio. Podemos hacerlo empleando la funcin:
87
send_mail
tiene cuatro argumentos obligatorios: el asunto y el cuerpo del mensaje, la direccin del
send_mail
EmailMessage
de Django. Esta clase provee caractersticas avanzadas como adjuntos, mensajes multiparte, y un control completo
sobre los encabezados del mensaje.
Una vez enviado el mensaje con los comentarios, redirigiremos a nuestro usuario a una pgina esttica de conrmacin. La funcin de la vista nalizada se ve as:
from
from
from
from
def contact(request):
if request.method == 'POST':
form = ContactForm(request.POST)
if form.is_valid():
topic = form.clean_data['topic']
message = form.clean_data['message']
sender = form.clean_data.get('sender', '[email protected]')
send_mail(
'Feedback from your site, topic: %s' % topic,
message, sender,
['[email protected]']
)
return HttpResponseRedirect('/contact/thanks/')
else:
form = ContactForm()
return render_to_response('contact.html', {'form': form})
Redirigir luego del POST
Si un usuario selecciona actualizar sobre una pgina que muestra una consulta POST, la consulta
se repetir. Esto probablemente lleve a un comportamiento no deseado, por ejemplo, que el registro
se agregue dos veces a la base de datos. Redirigir luego del POST es un patrn til que puede
ayudar a prevenir este escenario. As que luego de que se haya procesado el POST con xito,
redirige al usuario a otra pgina en lugar de retornar HTML directamente.
7.5.
Imagina que hemos lanzado al pblico a nuestro formulario de comentarios, y los correos electrnicos han empezado
a llegar. Nos encontramos con un problema: algunos mensajes vienen con slo una o dos palabras, es poco probable
que tengan algo interesante. Decidimos adoptar una nueva pliza de validacin: cuatro palabras o ms, por favor.
Hay varias formas de insertar nuestras propias validaciones en un formulario de Django. Si vamos a usar nuestra regla
una y otra vez, podemos crear un nuevo tipo de campo. Sin embargo, la mayora de las validaciones que agreguemos
sern de un solo uso, y pueden agregarse directamente a la clase del formulario.
En este caso, necesitamos validacin adicional sobre el campo
clean_message
message,
a nuestro formulario:
class ContactForm(forms.Form):
revisin 757 del 28 de julio de 2008
88
topic = forms.ChoiceField(choices=TOPIC_CHOICES)
message = forms.CharField(widget=forms.Textarea())
sender = forms.EmailField(required=False)
def clean_message(self):
message = self.clean_data.get('message', '')
num_words = len(message.split())
if num_words < 4:
raise forms.ValidationError("Not enough words!")
return message
Este nuevo mtodo ser llamado despus del validador que tiene el campo por defecto (en este caso, el validador de
CharField obligatorio). Dado que los datos del campo ya han sido procesados parcialmente, necesitamos obtenerlos
desde el diccionario clean_data del formulario.
Usamos una combinacin de len() y split() para contar la cantidad de palabras. Si el usuario ha ingresado muy
pocas palabras, lanzamos un error ValidationError. El texto que lleva esta excepcin se mostrar al usuario como
un
7.6.
None
<ul>
errorlist
<style type="text/css">
ul.errorlist {
margin: 0;
padding: 0;
}
.errorlist li {
background-color: red;
color: white;
display: block;
font-size: 10px;
margin: 0 0 3px;
padding: 4px 5px;
}
</style>
Si bien es conveniente que el HTML del formulario sea generado por nosotros, en muchos casos la disposicin
por defecto no quedara bien en nuestra aplicacin.
{{ form.as_table }}
usar mientras desarrollamos nuestra aplicacin, pero todo lo que concierne a la forma en que nuestro formulario es
representado puede ser sobreescrito, casi siempre desde la plantilla misma.
Cada widget de un campo (<input
type="text">, <select>, <textarea>, o similares) puede generarse indivi{{ form.fieldname }}. Cualquier error asociado con un campo est disponible como {{
form.fieldname.errors }}. Podemos usar estas variables para construir nuestra propia plantilla para el formulario:
dualmente accediendo a
89
{{ form.message }}
</div>
<div class="fieldWrapper">
{{ form.sender.errors }}
<label for="id_sender">Your email (optional):</label>
{{ form.sender }}
</div>
<p><input type="submit" value="Submit"></p>
</form>
{{ form.message.errors }}
se muestra como un
<ul class="errorlist">
cadena de caracteres en blanco si el campo es vlido ( o si el formulario no est vinculado). Tambin podemos tratar a
la variable
form.message.errors como a un booleano o incluso iterar sobre la misma como en una lista, por ejemplo:
<div>
7.7.
Construyamos algo un poquito ms interesante: un formulario que suministre los datos de un nuevo publicista a
nuestra aplicacin de libros del Captulo 5.
Una regla de oro que es importante en el desarrollo de software, a la que Django intenta adherirse, es: no te
repitas (del ingls Don't Repeat Yourself, abreviado DRY). Andy Hunt y Dave Thomas la denen como sigue, en The
Pragmatic Programmer :
Cada pieza de conocimiento debe tener una representacin nica, no ambigua, y de autoridad, dentro de
un sistema.
Nuestro modelo de la clase
Publisher dice que un publicista tiene un nombre, un domicilio, una ciudad, un estado o
provincia, un pas, y un sitio web. Si duplicamos esta informacin en la denicin del formulario, estaramos quebrando
la regla anterior. En cambio, podemos usar este til atajo:
form_for_model():
90
El archivo
add_publisher.html es casi idntico a nuestra plantilla contact.html original, as que la omitimos. Re(r'^add_publisher/$', 'mysite.books.views.add_publisher').
Ah se muestra un atajo ms. Dado que los formularios derivados de modelos se emplean a menudo para guardar
nuevas instancias del modelo en la base de datos, la clase del formulario creada por
conveniente mtodo
save().
form_for_model
incluye un
Este mtodo trata con el uso comn; pero puedes ignorarlo si deseas hacer algo ms que
form_for_instance() es un mtodo que est relacionado con el anterior, y puede crear formularios preinicializados
7.8.
Qu sigue?
Este captulo concluye con el material introductorio de este libro. Los prximos trece captulos tratan con varios
tpicos avanzados, incluyendo la generacin de contenido que no es HTML (Captulo 11), seguridad (`Captulo
19`_),
Captulo 8
8.1.
Trucos de URLconf
No hay nada de especial con las URLconfs -- como cualquier otra cosa en Django, son slo cdigo Python --.
Puedes aprovecharte de esto de varias maneras, como se describe las secciones que siguen.
8.1.1.
views
92
mysite.views.current_datetime.)
'mysite.views.current_datetime'
--
Al usar esta tcnica ya no es necesario importar las funciones vista; Django importa automticamente la funcin
vista apropiada la primera vez que sea necesaria, segn el string que describe el nombre y la ruta de la funcin vista.
Otro atajo que puedes tomar al usar la tcnica del string es sacar factor comn de prejos view. En nuestro ejemplo
'mysite.views',
patterns(), as:
de funciones
8.1.2.
En la prctica, si usas la tcnica del string, probablemente termines mezclando vistas hasta el punto en que las
vistas de tu URLconf no tengan un prejo comn. Sin embargo, todava puedes sacar provecho del atajo del prejo de
las vistas para remover esta duplicacin. Simplemente junta los objetos
patterns(),
Antes:
as:
93
Despus:
8.1.3.
Hablando de construir
urlpatterns de forma dinmica, quizs quieras aprovechar esta tcnica para alterar el com-
portamiento de tu URLconf mientras ests en el modo depuracin de Django. Para hacer eso simplemente comprueba
el valor de la conguracin
DEBUG
8.1.4.
/debuginfo/
DEBUG
tiene el valor
True.
Hasta ahora en todos nuestros ejemplos URLconf hemos usado, grupos de expresiones regulares sin nombre -- es
decir, ponemos parntesis en las partes de la URL que queremos capturar y Django le pasa ese texto capturado a la
funcin vista como un argumento posicional. En un uso ms avanzado, es posible usar grupos de expresiones regulares
con nombre para capturar partes de la URL y pasarlos como argumentos clave a una vista.
94
sell('Socks', '$2.50', 6)
Para llamarla con argumentos de palabra clave, se especican los nombres de los argumentos junto
con sus valores. Las siguientes sentencias son equivalentes:
(?P<nombre>patrn),
donde
nombre
patrn
/articles/2006/03/
equivalente a esto:
revisin 757 del 28 de julio de 2008
95
month_archive.
Si
estuviramos usando grupos con nombre, cambiar el orden de los parmetros capturados en la URL no tendra ningn
efecto sobre la vista.
Por supuesto, los benecios de los grupos con nombre tienen el costo de la falta de brevedad; algunos desarrolladores
opinan que la sintaxis de los grupos con nombre es fea y larga. An as, otra ventaja de los grupos con nombres es
la facilidad de lectura, especialmente para las personas que no estn ntimamente relacionadas con las expresiones
regulares o con tu aplicacin Django en particular. Es ms fcil ver lo que est pasando, a primera vista, en una
URLconf que usa grupos con nombre.
8.1.5.
Una advertencia al usar grupos con nombre en una URLconf es que un simple patrn URLconf no puede contener
grupos con nombre y sin nombre. Si haces eso, Django no generar ningn mensaje de error, pero probablemente
descubras que tus URLs no se estn disparando de la forma esperada. Aqu est especcamente el algoritmo que sigue
el parser URLconf, con respecto a grupos con nombre vs. grupos sin nombre en una expresin regular:
Si existe algn argumento con nombre, usar esos, ignorando los argumentos sin nombre.
Adems, pasar todos los argumentos sin nombre como argumentos posicionales.
En ambos casos, pasar cualquier opcin extra como argumentos de palabra clave. Ver la prxima
seccin para ms informacin.
8.1.6.
A veces te encontrars escribiendo funciones vista que son bastante similares, con tan slo algunas pequeas
diferencias. Por ejemplo, digamos que tienes dos vistas cuyo contenido es idntico excepto por la plantilla que utilizan:
# urls.py
from django.conf.urls.defaults import *
from mysite import views
urlpatterns = patterns('',
(r'^foo/$', views.foo_view),
(r'^bar/$', views.bar_view),
)
# views.py
from django.shortcuts import render_to_response
from mysite.models import MyModel
def foo_view(request):
m_list = MyModel.objects.filter(is_new=True)
return render_to_response('template1.html', {'m_list': m_list})
def bar_view(request):
m_list = MyModel.objects.filter(is_new=True)
return render_to_response('template2.html', {'m_list': m_list})
Con este cdigo nos estamos repitiendo y eso no es elegante. Al comienzo, podras pensar en reducir la redundancia
usando la misma vista para ambas URLs, poniendo parntesis alrededor de la URL para capturarla y comprobando
la URL dentro de la vista para determinar la plantilla, como mostramos a continuacin:
revisin 757 del 28 de julio de 2008
96
# urls.py
from django.conf.urls.defaults import *
from mysite import views
urlpatterns = patterns('',
(r'^(foo)/$', views.foobar_view),
(r'^(bar)/$', views.foobar_view),
)
# views.py
from django.shortcuts import render_to_response
from mysite.models import MyModel
def foobar_view(request, url):
m_list = MyModel.objects.filter(is_new=True)
if url == 'foo':
template_name = 'template1.html'
elif url == 'bar':
template_name = 'template2.html'
return render_to_response(template_name, {'m_list': m_list})
Sin embargo, el problema con esa solucin es que acopla fuertemente tus URLs y tu cdigo Si decides renombrar
/foo/
/fooey/,
La solucin elegante involucra un parmetro URLconf opcional. Cada patrn en una URLconf puede incluir un
tercer tem: un diccionario de argumentos de palabra clave para pasarle a la funcin vista.
Con esto en mente podemos reescribir nuestro ejemplo anterior as:
# urls.py
from django.conf.urls.defaults import *
from mysite import views
urlpatterns = patterns('',
(r'^foo/$', views.foobar_view, {'template_name': 'template1.html'}),
(r'^bar/$', views.foobar_view, {'template_name': 'template2.html'}),
)
# views.py
from django.shortcuts import render_to_response
from mysite.models import MyModel
def foobar_view(request, template_name):
m_list = MyModel.objects.filter(is_new=True)
return render_to_response(template_name, {'m_list': m_list})
Como puedes ver, la URLconf en este ejemplo especica
template_name
97
Por ejemplo, podras tener una aplicacin que muestra algunos datos para un da particular, con URLs tales como:
/mydata/jan/01/
/mydata/jan/02/
/mydata/jan/03/
# ...
/mydata/dec/30/
/mydata/dec/31/
Esto es lo sucientemente simple de manejar -- puedes capturar los mismos en una URLconf como esta (usando
sintaxis de grupos con nombre):
urlpatterns = patterns('',
(r'^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$', views.my_view),
)
Y la
my_view
/mydata/jan/06/.
urlpatterns = patterns('',
(r'^mydata/birthday/$', views.my_view, {'month': 'jan', 'day': '06'}),
(r'^mydata/(?P<month>\w{3})/(?P<day>\d\d)/$', views.my_view),
)
El detalle genial aqu es que no necesitas cambiar tu funcin vista para nada. A la funcin vista slo le incumbe el
obtener los parmetros
month
day
extra.
def say_hello(person_name):
print 'Hello, %s' % person_name
def say_goodbye(person_name):
print 'Goodbye, %s' % person_name
podemos extraer el saludo para convertirlo en un parmetro:
Event
BlogEntry,
descubre
que ambas son casos especcos de Una vista que muestra una lista de objetos, donde el tipo de objeto es variable.
Usemos este cdigo como ejemplo:
# urls.py
from django.conf.urls.defaults import *
from mysite import views
urlpatterns = patterns('',
(r'^events/$', views.event_list),
revisin 757 del 28 de julio de 2008
98
(r'^blog/entries/$', views.entry_list),
# views.py
from django.shortcuts import render_to_response
from mysite.models import Event, BlogEntry
def event_list(request):
obj_list = Event.objects.all()
return render_to_response('mysite/event_list.html', {'event_list': obj_list})
def entry_list(request):
obj_list = BlogEntry.objects.all()
return render_to_response('mysite/blogentry_list.html', {'entry_list': obj_list})
Ambas vistas hacen esencialmente lo mismo: muestran una lista de objetos. Refactoricemos el cdigo para extraer
el tipo de objetos que muestran:
# urls.py
from django.conf.urls.defaults import *
from mysite import models, views
urlpatterns = patterns('',
(r'^events/$', views.object_list, {'model': models.Event}),
(r'^blog/entries/$', views.object_list, {'model': models.BlogEntry}),
)
# views.py
from django.shortcuts import render_to_response
def object_list(request, model):
obj_list = model.objects.all()
template_name = 'mysite/ %s_list.html' % model.__name__.lower()
return render_to_response(template_name, {'object_list': obj_list})
Con esos pequeos cambios tenemos, de repente, una vista reusable e independiente del modelo. De ahora en
adelante, cada vez que necesitemos una lista que muestre una listado de objetos, podemos simplemente reusar esta
vista
object_list
en lugar de escribir cdigo de vista. A continuacin, un par de notas acerca de lo que hicimos:
model.
El diccionario de
opciones extra de ULconf puede pasar cualquier tipo de objetos Python -- no slo strings.
La lnea
model.objects.all()
pato, y habla como un pato, podemos tratarlo como un pato. Nota que el cdigo no conoce de qu
tipo de objeto se trata
momentos como este, cuando no conocemos el tipo de clase hasta el momento de la ejecucin. Por
ejemplo, el
__name__
de la clase
BlogEntry
es la cadena
BlogEntry.
En una sutil diferencia entre este ejemplo y el ejemplo previo, estamos pasando a la plantilla el
blogentry_list
Debido a que los sitios Web impulsados por bases de datos tienen varios patrones comunes, Django incluye un
conjunto de vistas genricas que usan justamente esta tcnica para ahorrarte tiempo. Nos ocupamos de las vistas
genricas incluidas con Django en el prximo captulo.
99
3,
/mydata/2/
Los lectores atentos notarn que en este caso es una prdida de tiempo y de tipeo capturar
id
en la expresin
regular, porque su valor ser siempre descartado en favor del valor proveniente del diccionario. Esto es correcto; lo
traemos a colacin slo para ayudarte a evitar el cometer ese error.
8.1.7.
Otro truco cmodo es el de especicar parmetros por omisin para los argumentos de una vista. Esto le indica a
la vista qu valor usar para un parmetro por omisin si es que no se especica ninguno.
Veamos un ejemplo:
# urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^blog/$', views.page),
(r'^blog/page(?P<num>\d+)/$', views.page),
)
# views.py
def page(request, num="1"):
# Output the appropriate page of blog entries, according to num.
# ...
views.page -- pero el primer patrn no captura nada
page() usar su argumento por omisin para num, "1". Si el
num que se haya capturado mediante la expresin regular.
Aqu, ambos patrones de URL apuntan a la misma vista -de la URL. Si el primer patrn es disparado, la funcin
segundo patrn es disparado,
page()
usar el valor de
Es comn usar esta tcnica en combinacin con opciones de conguracin, como explicamos previamente. Este
ejemplo implementa una pequea mejora al ejemplo de la seccin Pasando opciones de conguracin a una vista:
provee un valor por omisin para
template_name:
100
8.1.8.
En algunas ocasiones tendrs un patrn en tu URLconf que maneja un gran nmero de URLs, pero necesitars
realizar un manejo especial en una de ellas. En este caso, saca provecho de la forma lineal en la que son procesadas la
URLconfs y coloca el caso especial primero.
Por ejemplo, las pginas agregar un objeto en el sitio de administracin de Django estn representadas por la
siguiente lnea de URLconf:
urlpatterns = patterns('',
# ...
('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'),
# ...
)
Esto se disparar con URLs como
de un objeto usuario (/auth/user/add/) es un caso especial -- la misma no muestra todos los campos del formulario,
muestra dos campos de contrasea, etc. Podramos resolver este problema tratando esto como un caso especial en la
vista, de esta manera:
urlpatterns = patterns('',
# ...
('^auth/user/add/$', 'django.contrib.admin.views.auth.user_add_stage'),
('^([^/]+)/([^/]+)/add/$', 'django.contrib.admin.views.main.add_stage'),
# ...
)
Con esto, una peticin de
/auth/user/add/
user_add_stage.
coincide con el segundo patrn, coincide primero con el patrn ubicado ms arriba. (Esto es lgica de corto circuito).
8.1.9.
Cada argumento capturado es enviado a la vista como una cadena Python, sin importar qu tipo de coincidencia
se haya producido con la expresin regular. Por ejemplo en esta lnea de URLconf:
(r'^articles/(?P<year>\d{4})/$', views.year_archive),
el argumento
year
de
views.year.archive()
\d{4}
slo coincidir
datetime.date
101
# urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^articles/(\d{4})/(\d{2})/(\d{2})/$', views.day_archive),
)
# views.py
import datetime
def day_archive(request, year, month, day)
# The following statement raises a TypeError!
date = datetime.date(year, month, day)
En cambio
day_archive
int()
lanza un
ValueError
pero estamos evitando ese error en este caso porque la expresin regular en nuestra URLconf ya se ha asegurado que
slo se pasen a la funcin vista cadenas que contengan dgitos.
8.1.10.
Cuando llega una peticin, Django intenta comparar los patrones de la URLconf con la URL solicitada como una
cadena Python normal (no como una cadena Unicode). Esto no incluye los parmetros de
GET
POST
o el nombre del
dominio. Tampoco incluye la barra inicial porque toda URL tiene una barra inicial.
para
palabras, todos los mtodos sern encaminados hacia la misma funcin para la misma URL. Es responsabilidad de
una funcin vista el manejar de maneras distintas en base al mtodo de la peticin.
8.2.
Si tu intencin es que tu cdigo sea usando en mltiples sitios implementados con Django, debes considerar el
organizar tus URLconfs en una manera que permita el uso de inclusiones.
Tu URLconf puede, en cualquier punto, incluir otros mdulos URLconf. Esto se trata, en esencia, de enraizar
un conjunto de URLs debajo de otras. Por ejemplo, esta URLconf incluye otras URLconfs:
include()
$
include(),
no tiene un
(carcter que coincide con un n de cadena) pero si incluye una barra al nal. Cuando Django encuentra
elimina todo el fragmento de la URL que ya ha coincidido hasta ese momento y enva la cadena restante a la URLconf
incluida para su procesamiento subsecuente.
Continuando con este ejemplo, esta es la URLconf
mysite.blog.urls:
102
urlpatterns = patterns('',
(r'^(\d\d\d\d)/$', 'mysite.blog.views.year_detail'),
(r'^(\d\d\d\d)/(\d\d)/$', 'mysite.blog.views.month_detail'),
)
Con esas dos URLconfs, veremos aqu cmo seran manejadas algunas peticiones de ejemplo:
8.2.1.
mysite.views.about en la primera
include() con patrones no include().
URLconf, de-
Una URLconf incluida recibe todo parmetro que se haya capturado desde las URLconf padres, por ejemplo:
# root urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
)
# foo/urls/blog.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^$', 'foo.views.blog_index'),
(r'^archive/$', 'foo.views.blog_archive'),
)
En este ejemplo, la variable capturada
username()
8.2.2.
include()
de URLconf a una vista normal -- como un diccionario. Cuando haces esto, las opciones extra sern pasadas a todas
las lneas en la URLconf incluida.
Por ejemplo, los siguientes dos conjuntos de URLconfs son funcionalmente idnticos.
Conjunto uno:
# urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^blog/', include('inner'), {'blogid': 3}),
)
revisin 757 del 28 de julio de 2008
8.3. QU SIGUE?
103
# inner.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^archive/$', 'mysite.views.archive'),
(r'^about/$', 'mysite.views.about'),
(r'^rss/$', 'mysite.views.rss'),
)
Conjunto dos:
# urls.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^blog/', include('inner')),
)
# inner.py
from django.conf.urls.defaults import *
urlpatterns = patterns('',
(r'^archive/$', 'mysite.views.archive', {'blogid': 3}),
(r'^about/$', 'mysite.views.about', {'blogid': 3}),
(r'^rss/$', 'mysite.views.rss', {'blogid': 3}),
)
Como en el caso de los parmetros capturados (sobre los cuales se explic en la seccin anterior), las opciones extra
se pasarn siempre a todas las lneas en la URLconf incluida, sin importar de si la vista de la lnea realmente acepta
esas opciones como vlidas. Por eta razn esta tcnica es til slo si ests seguro que todas las vistas en la URLconf
incluida acepta las opciones extra que ests pasando.
8.3.
Qu sigue?
Uno de los principales objetivos de Django es reducir la cantidad de cdigo que los desarrolladores deben escribir
y en este captulo hemos sugerido formas en las cuales se puede reducir el cdigo de tus vistas y URLconfs.
El prximo paso lgico en la reduccin de cdigo es eliminar completamente la necesidad de escribir vistas. Ese es
el tpico del
`prximo captulo`_.
104
Captulo 9
Vistas genricas
De nuevo aparece aqu un tema recurrente en este libro: en el peor de los casos, el desarrollo Web es aburrido y
montono. Hasta aqu, hemos cubierto cmo Django trata de alejar parte de esa monotona en las capas del modelo y
las plantillas, pero los desarrolladores Web tambin experimentan este aburrimiento al nivel de las vistas.
Las vistas genricas de Django fueron desarrolladas para aliviar ese dolor. stas recogen ciertos estilos y patrones
comunes encontrados en el desarrollo de vistas y los abstraen, de modo que puedas escribir rpidamente vistas comunes
de datos sin que tengas que escribir mucho cdigo. De hecho, casi todos los ejemplos de vistas en los captulos
precedentes pueden ser reescritos con la ayuda de vistas genricas.
El Captulo 8 reri brevemente sobre cmo haras para crear una vista genrica. Para repasar, podemos reconocer
ciertas tareas comunes, como mostrar una lista de objetos, y escribir cdigo que muestra una lista de cualquier objeto.
Por lo tanto el modelo en cuestin puede ser pasado como un argumento extra a la URLconf.
Django viene con vistas genricas para hacer lo siguiente:
Realizar tareas sencillas comunes: redirigir a una pgina diferente y renderizar una plantilla dada.
Mostrar pginas de listado y detalle para un solo objeto. Las vistas
event_list
entry_list
del
Captulo 8 son ejemplos de vistas de listado. Una pgina de evento simple es un ejemplo de lo que
llamamos vista detallada.
Presentar objetos basados en fechas en pginas de archivo de tipo da/mes/ao, su detalle asociado,
y las pginas ms recientes. Los archivos por da, mes, ao del Weblog de Django (http://www.
djangoproject.com/weblog/) estn construidos con ellas, como lo estaran los tpicos archivos de un
peridico.
Permitir a los usuarios crear, actualizar y borrar objetos -- con o sin autorizacin.
Agrupadas, estas vistas proveen interfaces fciles para realizar las tareas ms comunes que encuentran los desarrolladores.
9.1.
Todas estas vistas se usan creando diccionarios de conguracin en tus archivos URLconf y pasando estos diccionarios como el tercer miembro de la tupla URLconf para un patrn dado.
Por ejemplo, sta es una URLconf simple que podras usar para presentar una pgina esttica about (acerca de):
direct_to_template
106
Ya que esta vista genrica -- y todas las otras -- es una funcin de vista regular como cualquier otra, podemos
reusarla dentro de nuestras propias vistas. Como ejemplo, extendamos nuestro ejemplo about para mapear URLs
de la forma
about_pages:
direct_to_template como cualquier otra funcin. Ya que esta devuelve una HttpResponse,
podemos retornarlo as como est. La nica ligera dicultad aqu es ocuparse de las plantillas perdidas. No queremos
que una plantilla inexistente cause un error de servidor, por lo tanto atrapamos las excepciones
TemplateDoesNotExist
page).
11 (discutida en detalle en el
page es
page
\w
Pero es
`Captulo 19`_).
slo acepta letras y nmeros. Por lo tanto, cualquier caracter malicioso (puntos
y barras, en este caso) sern rechazadas por el URL resolver antes de alcanzar la vista en s.
9.2.
La vista genrica
direct_to_template
cuando se trata de presentar vistas del contenido de tu base de datos. Ya que es una tarea tan comn, Django viene con
un puado de vistas genricas incluidas que hacen la generacin de vistas de listado y detalle de objetos increblemente
fcil.
Demos un vistazo a una de estas vistas genricas: la vista object list. Usaremos el objeto
5:
class Publisher(models.Model):
name = models.CharField(maxlength=30)
address = models.CharField(maxlength=50)
city = models.CharField(maxlength=60)
state_province = models.CharField(maxlength=30)
revisin 757 del 28 de julio de 2008
107
country = models.CharField(maxlength=50)
website = models.URLField()
def __str__(self):
return self.name
class Meta:
ordering = ["-name"]
class Admin:
pass
Para construir una pgina listado de todos los books, usaremos la URLconf bajo estas lneas:
en el diccionario de argumentos extra, pero en la ausencia de una plantilla explcita Django inferir una del nombre del
objeto. En este caso, la plantilla inferida ser
de la aplicacin que dene el modelo, mientras que la parte publisher es slo la versin en minsculas del nombre
del modelo.
Esta plantilla ser renderizada en un contexto que contiene una variable llamada
object_list
la cual contiene
todos los objetos book. Una plantilla muy simple podra verse como la siguiente:
{ % extends "base.html" %}
{ % block content %}
<h2>Publishers</h2>
<ul>
{ % for publisher in object_list %}
<li>{{ publisher.name }}</li>
{ % endfor %}
</ul>
{ % endblock %}
Eso es realmente todo en lo referente al tema. Todas las geniales caractersticas de las vistas genricas provienen
de cambiar el diccionario info pasado a la vista genrica. El Apndice D documenta todas las vistas genricas y
todas sus opciones en detalle; el resto de este captulo considerar algunas de las maneras comunes en que t puedes
personalizar y extender las vistas genricas.
9.3.
No hay duda de que usar las vistas genricas puede acelerar el desarrollo sustancialmente. En la mayora de los
proyectos, sin embargo, llega un momento en el que las vistas genricas no son sucientes. De hecho, la pregunta ms
comn que se hacen los nuevos desarrolladores de Django es cmo hacer que las vistas genricas manejen un rango
ms amplio de situaciones.
Afortunadamente, en casi cada uno de estos casos, hay maneras de simplemente extender las vistas genricas para
manejar un conjunto ms amplio de casos de uso. Estas situaciones usualmente recaen en un puado de patrones que
se tratan en las secciones que siguen.
revisin 757 del 28 de julio de 2008
108
9.3.1.
Tal vez hayas notado que el ejemplo de la plantilla publisher list almacena todos los books en una variable llamada
object_list.
Aunque que esto funciona bien, no es una forma amistosa para los autores de plantillas: ellos slo
tienen que saber aqu que estn trabajando con books. Un nombre mejor para esa variable sera
el contenido de esa variable es bastante obvio.
Podemos cambiar el nombre de esa variable fcilmente con el argumento
publisher_list;
template_object_name:
publisher_info = {
"queryset" : Publisher.objects.all(),
"template_object_name" : "publisher",
}
urlpatterns = patterns('',
(r'^publishers/$', list_detail.object_list, publisher_info)
)
Proveer un
template_object_name
til es siempre una buena idea. Tus compaeros de trabajo que disean las
plantillas te lo agradecern.
9.3.2.
A menudo simplemente necesitas presentar alguna informacin extra aparte de la proporcionada por la vista
genrica. Por ejemplo, piensa en mostrar una lista de todos los otros publisher en cada pgina de detalle de un
publisher. La vista genrica
object_detail
de objetos extra que sern agregados al contexto de la plantilla. Por lo tanto, para proporcionar la lista de todos los
publishers en la vista de detalles, usamos un diccionario info como el que sigue:
publisher_info = {
"queryset" : Publisher.objects.all(),
"template_object_name" : "publisher",
"extra_context" : {"book_list" : Book.objects.all()}
}
Esto llenara una variable
{{ book_list }} en el contexto de la plantilla. Este patrn puede ser usado para pasar
Publisher.objects.all()
extra_context
en la URLconf, slo se evaluar una vez (cuando la URLconf se cargue por primera vez).
Una vez que agregues o elimines publishers, notars que la vista genrica no reeja estos cambios hasta que reinicias el
servidor Web (mira Almacenamiento en cach y QuerySets en el Apndice C para mayor informacin sobre cundo
los QuerySets son almacenados en la cache y evaluados).
Nota
Este problema no se aplica al argumento
queryset
que ese QuerySet en particular nunca debe ser almacenado en la cach, la vista genrica se hace
cargo de limpiar la cach cuando cada vista es renderizada.
12 en
extra_context
extra_context ser evaluado
def get_books():
return Book.objects.all()
publisher_info = {
"queryset" : Publisher.objects.all(),
"template_object_name" : "publisher",
"extra_context" : {"book_list" : get_books}
}
revisin 757 del 28 de julio de 2008
109
o puedes usar una versin menos obvia pero ms corta que se basa en el hecho de que
Publisher.objects.all
es
en s un callable:
publisher_info = {
"queryset" : Publisher.objects.all(),
"template_object_name" : "publisher",
"extra_context" : {"book_list" : Book.objects.all}
}
Nota la falta de parntesis despus de
9.3.3.
de objetos mostrar (mira Seleccionando objetos en el Captulo 5 para una introduccin a los QuerySets, y mira el
Apndice C para los detalles completos).
Para tomar un ejemplo simple, tal vez querramos ordenar una lista de books por fecha de publicacin, con el ms
reciente primero.
book_info = {
"queryset" : Book.objects.all().order_by("-publication_date"),
}
urlpatterns = patterns('',
(r'^publishers/$', list_detail.object_list, publisher_info),
(r'^books/$', list_detail.object_list, book_info),
)
Este es un muy lindo y simple ejemplo, pero ilustra bien la idea. Por supuesto, t usualmente querrs hacer ms
que slo reordenar objetos. Si quieres presentar una lista de books de un publisher particular, puedes usar la misma
tcnica:
apress_books = {
"queryset": Book.objects.filter(publisher__name="Apress Publishing"),
"template_name" : "books/apress_list.html"
}
urlpatterns = patterns('',
(r'^publishers/$', list_detail.object_list, publisher_info),
(r'^books/apress/$', list_detail.object_list, apress_books),
)
Nota que adems de un
queryset
lo hiciramos, la vista genrica usara la misma plantilla que la lista de objetos genrica
queremos.
Tambin nota que sta no es una forma muy elegante de hacer publisher-specic books. Si queremos agregar otra
pgina publisher, necesitamos otro puado de lneas en la URLconf, y ms de unos pocos publishers no ser razonable.
Enfrentaremos este problema en la siguiente seccin.
Nota
Si obtienes un error 404 cuando solicitas
/books/apress/,
realidad tienes un Publisher con el nombre 'Apress Publishing'. Las vistas genricas tienen un
parmetro
9.3.4.
allow_empty
Otra necesidad comn es ltrar los objetos que se muestran en una pgina listado por alguna clave en la URLconf.
15 el nombre del publisher en la URLconf, pero qu pasa si queremos escribir una vista
16 la vista genrica object_list
que muestre todos los books por algn publisher arbitrario?. Podemos encapsular
Anteriormente codicamos
para evitar escribir mucho cdigo a mano. Como siempre, empezamos escribiendo una URLconf.
revisin 757 del 28 de julio de 2008
110
urlpatterns = patterns('',
(r'^publishers/$', list_detail.object_list, publisher_info),
(r'^books/(w+)/$', books_by_publisher),
)
A continuacin, escribiremos la vista
books_by_publisher:
HttpResponse.
Por lo tanto, es increblemente fcil encapsular una pequea funcin sobre una vista genrica que
realiza trabajo adicional antes (o despus; mira la siguiente seccin) de pasarle el control a la vista genrica.
Nota
Nota que en el ejemplo anterior pasamos el publisher que se est mostrando actualmente en el
extra_context.
9.3.5.
El ltimo patrn comn que veremos involucra realizar algn trabajo extra antes o despus de llamar a la vista
genrica.
Imagina que tenemos un campo
last_accessed
en nuestro objeto
registro de la ltima vez que alguien vio ese author. La vista genrica
sobre este campo, pero una vez ms fcilmente podramos escribir una vista personalizada para mantener ese campo
actualizado.
Primero, necesitamos agregar una pequea parte de detalle sobre el author en la URLconf para que apunte a una
vista personalizada:
import datetime
from mysite.books.models import Author
revisin 757 del 28 de julio de 2008
9.4. QU SIGUE?
111
Author
books/author_detail.html.
last_accessed
a tu
Podemos usar un mtodo similar para alterar la respuesta devuelta por la vista genrica. Si quisiramos proporcionar
una versin en texto plano
17 que se pueda descargar desde la lista de autores, podramos usar una vista como esta:
def author_list_plaintext(request):
response = list_detail.object_list(
request,
queryset = Author.objects.all(),
mimetype = "text/plain",
template_name = "books/author_list.txt"
)
response["Content-Disposition"] = "attachment; filename=authors.txt"
return response
HttpResponse que pueden ser tratados como
Content-Disposition, por otro lado, instruye al
9.4.
Qu sigue?
En este captulo hemos examinado slo un par de las vistas genricas que incluye Django, pero las ideas generales
presentadas aqu deberan aplicarse a cualquier vista genrica. El Apndice D cubre todas las vistas disponibles en
detalle, y es de lectura obligada si quieres sacar el mayor provecho de esta caracterstica.
En el
mostrando todas las maneras geniales en que pueden ser extendidas. Hasta ahora, hemos tratado el sistema de plantillas
meramente como una herramienta esttica que puedes usar para renderizar tu contenido.
Duplicate explicit target name: prximo captulo.
11 N.
12 N.
13 N.
14 N.
15 N.
16 N.
17 N.
112
Captulo 10
10.1.
if
for),
o un loop
{%
y %}:
{ % if is_logged_in %}
Thanks for logging in!
{ % else %}
Please log in.
{ % endif %}
Una variable es un smbolo dentro de una plantilla que emite un valor.
Las etiquetas de variable deben ser rodeadas por
{{
}}:
10.2.
Procesadores de contexto
Cuando una plantilla debe ser renderizada, necesita un contexto. Usualmente este contexto es una instancia de
django.template.Context,
django.template.RequestContext
114
llas, construimos el contexto y renderizamos las plantillas. Simplemente por claridad, estamos demostrando todos los
pasos necesarios.
Cada vista pasa las mismas tres variables --
app, user
ip_address
RequestContext
y los
procesadores de contexto fueron creado para resolver este problema. Los procesadores
de contexto te permiten especicar un nmero de variables que son incluidas automticamente en cada contexto -- sin
la necesidad de tener que hacerlo manualmente en cada llamada a
RequestContext
en lugar de
Context
render_to_response().
115
La forma de nivel ms bajo de usar procesadores de contexto es crear algunos de ellos y pasarlos a
RequestContext.
A continuacin mostramos como el ejemplo anterior puede lograrse utilizando procesadores de contexto:
HttpRequest
custom_proc.
lo que hace.
Hemos cambiado las cuatro vistas para que usen
RequestContext
HttpRequest
dos
pri-
Cada vista an posee la exibilidad como para introducir una o ms variables en el contexto de la
plantilla si es necesario. En este ejemplo, la variable de plantilla
Context
116
render_to_response(),
render_to_response(). Esto lo logramos
bajo nivel de los procesadores de contexto, en los ejemplos anteriores no hemos utilizado
pero es posible -- y preferible -- utilizar los procesadores de contexto junto a
mediante el argumento
context_instance
de la siguiente manera:
processors
constantemente.
Por esta razn, Django admite el uso de procesadores de contexto globales. El parmetro de conguracin
designa cuales sern los procesadores de contexto que debern ser aplicados siempre a
RequestContext.
TEMPLATE_CONTEXT_PROC
Esto elimina
la necesidad de especicar
TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.debug',
'django.core.context_processors.i18n',
'django.core.context_processors.media',
)
Este parmetro de conguracin es una tupla de funciones que utilizan la misma interfaz que nuestra funcin
custom_proc
HttpRequest
vuelven un diccionario de items que sern incluidos en el contexto de la plantilla. Ten en cuenta que los valores en
TEMPLATE_CONTEXT_PROCESSORS son especicados como strings, lo cual signica que estos procesadores debern
en algn lugar dentro de tu PYTHONPATH (para poder referirse a ellos desde el archivo de conguracin)
revisin 757 del 28 de julio de 2008
estar
117
Estos procesadores de contexto son aplicados en orden, es decir, si uno de estos procesadores aade una variable
al contexto y un segundo procesador aade otra variable con el mismo nombre, entonces la segunda sobre-escribir a
la primera.
Django provee un numero de procesadores de contexto simples, entre ellos los que estn activos por defecto.
10.2.1.
Si
django.core.context_processors.auth
TEMPLATE_CONTEXT_PROCESSORS contiene este procesador, cada RequestContext contendr las siguientes varia-
bles:
user:
Una instancia de
actualmente
messages:
Una lista de mensajes (como string ) para el usuario actualmente autenticado. Detrs del
todo colecta los mensajes del usuario, y luego los borra de la base de datos.
10.2.2.
django.core.context_processors.debug
debug:
RequestContext
TEMPLATE_CONTEXT_PROCESSORS
con-
False).
DEBUG (True
sql_queries:
sultas SQL que se generaron durante la peticin (request ) y cunto duraron. La lista est ordenada
respecto a cundo fue ejecutada cada consulta.
Como la informacin de depuracin es sensible, este procesador de contexto slo agregar las variables al contexto
si las dos siguientes condiciones son verdaderas.
El parmetro de conguracin
DEBUG
es True
10.2.3.
INTERNAL_IPS.
django.core.context_processors.i18n
LANGUAGES:
RequestContext
LANGUAGE_CODE: request.LANGUAGE_CODE
LANGUAGE_CODE.
LANGUAGES.
guracin
10.2.4.
django.core.context_processors.request
HttpRequest.
10.2.5.
RequestContext
request,
la cual es el actual
118
TEMPLATE_CONTEXT_PROCESSORS
estar dispo-
nible en cada plantilla cuya conguracin est dictada por ese archivo de conguracin, as que trata
de seleccionar nombres de variables con pocas probabilidades de entrar en conicto con nombre de
variables que tus plantillas pudieran usar en forma independiente. Como los nombres de variables son
sensibles a maysculas/minsculas no es una mala idea usar maysculas para las variables provistas
por un procesador.
No importa dnde residan en el sistema de archivos, mientras se hallen en tu ruta de Python de manera
que puedas incluirlos en tu variable de conguracin
10.3.
En general las plantillas se almacenan en archivos en el sistema de archivos, pero puedes usar cargadores de plantillas
personalizados (custom ) para cargar plantillas desde otros orgenes.
Django tiene dos maneras de cargar plantillas:
la plantilla compilada
no existe, se generar
TEMPLATE_DIRS para cargar las plantillas. Sin embargo, internamente las mismas delegan la tarea pesada a un cargador
de plantillas.
Algunos de los cargadores estn, por omisin, desactivados pero puedes activarlos editando la variable de conguracin
TEMPLATE_LOADERS. TEMPLATE_LOADERS
cargador de plantillas. Estos son los cargadores de plantillas incluidos con Django:
django.template.loaders.filesystem.load_template_source: Este cargador carga plantillas desde el sistema de archivos, de acuerdo a TEMPLATE_DIRS. Por omisin est activo.
django.template.loaders.app_directories.load_template_source:
templates.
INSTALLED_APPS,
el
el mismo.
Esto signica que puedes almacenar plantillas en tus aplicaciones individuales, facilitando la distri-
INSTALLED_APPS contiene
get_template('foo.html') buscar planti-
('myproject.polls', 'myproject.music')
entonces
/path/to/myproject/polls/templates/foo.html
/path/to/myproject/music/templates/foo.html
Notar que el cargador realiza una optimizacin cuando es importado por primera vez: hace caching
de una lista de cuales de los paquetes en
INSTALLED_APPS
tienen un sub-directorio
templates.
TEMPLATE_DIRS.
Usar cada uno de los cargadores hasta que uno de los mismos tenga xito en la bsqueda de la plantilla.
10.4.
119
Ahora que entiendes un poco ms acerca del funcionamiento interno del sistema de plantillas, echemos una mirada
a cmo extender el sistema con cdigo propio.
La mayor parte de la personalizacin de plantillas se da en forma de etiquetas y/o ltros. Aunque el lenguaje de
plantillas de Django incluye muchos, probablemente ensamblars tus propias bibliotecas de etiquetas y ltros que se
adapten a tus propias necesidades. Afortunadamente, es muy fcil denir tu propia funcionalidad.
10.4.1.
Ya sea que ests escribiendo etiquetas o ltros personalizados, la primera tarea a realizar es crear una
biblioteca
para plantillas -- un pequeo fragmento de infraestructura con el cual Django puede interactuar.
La creacin de una biblioteca para plantillas es un proceso de dos pasos:
Primero, decidir qu aplicacin Django alojar la biblioteca. Si has creado una aplicacin va
startapp
manage.py
puedes colocarla all, o puedes crear otra aplicacin con el solo n de alojar la biblioteca.
Sin importar cual de las dos rutas tomes, asegrate de agregar la aplicacin a tu variable de conguracin
INSTALLED_APPS.
books/
__init__.py
models.py
templatetags/
views.py
Crea dos archivos vacos en el directorio
templatetags:
un archivo
__init__.py
(para indicarle a
Python que se trata de un paquete que contiene cdigo Python) y un archivo que contendr tus
deniciones personalizadas de etiquetas/ltros. El nombre del segundo archivo es el que usars para
cargar las etiquetas ms tarde. Por ejemplo, si tus etiquetas/ltros personalizadas estn en un archivo
llamado
poll_extras.py,
{ % load poll_extras %}
La etiqueta
{ % load %}
INSTALLED_APPS
y slo permite la
carga de bibliotecas para plantillas desde aplicaciones Django que estn instaladas. Se trata de una
caracterstica de seguridad; te permite tener en cierto equipo el cdigo Python de varias bibliotecas
para plantillas sin tener que activar el acceso a todas ellas para cada instalacin de Django.
Si escribes una biblioteca para plantillas que no se encuentra atada a ningn modelo/vista particular es vlido y
normal el tener un paquete de aplicacin Django que slo contiene un paquete
lo referente a cuntos mdulos puedes poner en el paquete
load %}
templatetags.
templatetags.
No existen lmites en
{%
cargar etiquetas/ltros para el nombre del mdulo Python provisto, no el nombre de la aplicacin.
Una vez que has creado ese mdulo Python, slo tendrs que escribir un poquito de cdigo Python, dependiendo
de si ests escribiendo ltros o etiquetas.
Para ser una biblioteca de etiquetas vlida, el mdulo debe contener una variable a nivel del mdulo llamada
register que sea una instancia de template.Library. Esta instancia de template.Library es la estructura de datos
en la cual son registradas todas las etiquetas y ltros. As que inserta en la zona superior de tu mdulo, lo siguiente:
django/template/defaultfilters.py
django/template/defaulttags.py, respectivamente. Algunas aplicaciones en
django.contrib tambin contienen bibliotecas para plantillas.
tas incluidos con Django. Puedes encontrarlos en
register,
120
10.4.2.
Los ltros personalizados son slo funciones Python que reciben uno o dos argumentos:
El valor de la variable (entrada)
El valor del argumento, el cual puede tener un valor por omisin o puede ser obviado.
Por ejemplo, en el ltro
"bar".
Las funciones ltro deben siempre retornar algo. No deben arrojar excepciones, y deben fallar silenciosamente.
Si existe un error, las mismas deben retornar la entrada original o una cadena vaca, dependiendo de qu sea ms
apropiado.
Esta es un ejemplo de denicin de un ltro:
{{ somevariable|cut:"0" }}
La mayora de los ltros no reciben argumentos. En ese caso, basta con que no incluyas el argumento en tu funcin:
Library,
register.filter('cut', cut)
register.filter('lower', lower)
El mtodo
Library.filter()
register.filter()
como un decorador:
@register.filter(name='cut')
def cut(value, arg):
return value.replace(arg, '')
@register.filter
def lower(value):
return value.lower()
Si no provees el argumento
name, como en el segundo ejemplo, Django usar el nombre de la funcin como nombre
del ltro.
Veamos entonces el ejemplo completo de una biblioteca para plantillas, que provee el ltro
cut:
10.4.3.
121
Las etiquetas son ms complejas que los ltros porque las etiquetas pueden implementar prcticamente cualquier
funcionalidad.
El Captulo 4 describe cmo el sistema de plantillas funciona como un proceso de dos etapas: compilacin y
renderizado. Para denir una etiqueta de plantilla personalizada, necesitas indicarle a Django cmo manejar ambas
etapas cuando llega a tu etiqueta.
Cuando Django compila una plantilla, divide el texto crudo de la plantilla en nodos. Cada nodo es una instancia
django.template.Node y tiene un
lista de objetos Node.
Cuando llamas a render() en una
de
mtodo
render().
render()
en cada
Node()
de su lista
de nodos, con el contexto proporcionado. Los resultados son todos concatenados juntos para formar la salida de la
plantilla. Por ende, para denir una etiqueta de plantilla personalizada debes especicar cmo se debe convertir la
etiqueta en crudo en un
Node
render()
del nodo.
En las secciones que siguen, explicaremos todos los pasos necesarios para escribir una etiqueta propia.
Node
{ % current_time %} que visualice la fecha/hora actuales con un formato destrftime (ver http://www.djangoproject.com/r/pyt
Es una buena idea denir la sintaxis de la etiqueta previamente. En nuestro caso, supongamos que la etiqueta deber
ser usada de la siguiente manera:
{ % now %}
defecto hace exactamente lo mismo con una sintaxis ms simple. Slo mostramos esta etiqueta a
modo de ejemplo.
Para evaluar esta funcin, se deber obtener el parmetro y crear el objeto
Node:
django.template.TemplateSyntaxError
con
token.split_contents()[0]
siempre contendr el
122
el nodo necesita saber sobre esta etiqueta. En este caso, slo pasa el argumento
CurrentTimeNode:
Node
render().
import datetime
class CurrentTimeNode(template.Node):
def __init__(self, format_string):
self.format_string = format_string
def render(self, context):
now = datetime.datetime.now()
return now.strftime(self.format_string)
Estas dos funciones (__init__ y
render) se relacionan directamente con los dos pasos para el proceso de la plantilla
(compilacin y renderizado). La funcin de inicializacin slo necesitar almacenar el string con el formato deseado,
el trabajo real sucede dentro de la funcin
render()
Del mismo modo que los ltros de plantilla, estas funciones de renderizacin deberan fallar silenciosamente en
lugar de generar errores. En el nico momento en el cual se le es permitido a las etiquetas de plantilla generar errores
es en tiempo de compilacin.
Registrando la etiqueta
Finalmente, debers registrar la etiqueta con tu objeto
Library
tas es muy similar a registrar nuevos ltros (como explicamos previamente). Slo debers instanciar un objeto
template.Library
y llamar a su mtodo
tag().
Por ejemplo:
register.tag('current_time', do_current_time)
El mtodo
tag()
register.tag
como un
@register.tag(name="current_time")
def do_current_time(parser, token):
# ...
@register.tag
def shout(parser, token):
# ...
Si omitimos el argumento
name, as como en el segundo ejemplo, Django usar el nombre de la funcin como nombre
de la etiqueta.
123
context
current_time,
render()
CurrentTimeNode
disponible en el mtodo
class CurrentTimeNode2(template.Node):
def __init__(self, format_string):
self.format_string = format_string
def render(self, context):
now = datetime.datetime.now()
context['current_time'] = now.strftime(self.format_string)
return ''
render() siempre debe devolver un string.
render() debe al menos devolver un string vaco.
CurrentTimeNode2:
{ % current_time %}
el nombre de la variable
{{ current_time }}
current_node
Una solucin ms limpia, es poder recibir el nombre de la variable en la etiqueta de plantilla as:
import re
class CurrentTimeNode3(template.Node):
def __init__(self, format_string, var_name):
self.format_string = format_string
self.var_name = var_name
def render(self, context):
now = datetime.datetime.now()
context[self.var_name] = now.strftime(self.format_string)
return ''
def do_current_time(parser, token):
# This version uses a regular expression to parse tag contents.
try:
# Splitting by None == splitting by spaces.
tag_name, arg = token.contents.split(None, 1)
except ValueError:
msg = ' %r tag requires arguments' % token.contents[0]
raise template.TemplateSyntaxError(msg)
m = re.search(r'(.*?) as (\w+)', arg)
if m:
fmt, var_name = m.groups()
else:
msg = ' %r tag had invalid arguments' % tag_name
raise template.TemplateSyntaxError(msg)
if not (fmt[0] == fmt[-1] and fmt[0] in ('"', "'")):
revisin 757 del 28 de julio de 2008
Node
de esta manera:
124
do_current_time()
CurrentTimeNode3.
for %},
parser.parse() en tu funcin
estndar { % coment %}:
{ % if %}, { %
de compilacin.
Nodo
nodelist es una lista con todos los nodos entre { % comment %} y { % endcomment %},
{ % comment %} y { % endcomment %}.
parser.parse() es llamado el parser an no ha consumido la etiqueta { % endcomment %}, es
cdigo se necesita llamar explcitamente a parser.delete_first_token() para prevenir que esta
{ % comment %}
{%
do_comment()
{ % endupper %}:
{ % comment %}
{ % upper %},
{ % endcomment %},
pero tambin es
{ % upper %}
This will appear in uppercase, {{ your_name }}.
{ % endupper %}
Como en el ejemplo previo, utilizaremos
@register.tag
def do_upper(parser, token):
nodelist = parser.parse(('endupper',))
parser.delete_first_token()
return UpperNode(nodelist)
class UpperNode(template.Node):
def __init__(self, nodelist):
self.nodelist = nodelist
def render(self, context):
output = self.nodelist.render(context)
return output.upper()
125
self.nodelist.render(context)
Node en la lista de nodos.
render()
en cada
en
UpperNode.render().
El mismo simple-
Para ms ejemplos de renderizado complejo, examina el cdigo fuente para las etiquetas
ifequal %}
{ % ifchanged %}.
10.4.4.
Puedes encontrarlas en
Muchas etiquetas de plantilla reciben un nico argumento--una cadena o una referencia a una variable de plantilla-y retornan una cadena luego de hacer algn procesamiento basado solamente en el argumento de entrada e informacin
externa. Por ejemplo la etiqueta
current_time que escribimos antes es de este tipo. Le pasamos una cadena de formato,
render
django.template.Library,
y el resto de las piezas necesarias que mencionamos previamente y lo registra con el sistema de
plantillas.
Nuestra funcin
current_time
def current_time(format_string):
return datetime.datetime.now().strftime(format_string)
register.simple_tag(current_time)
En Python 2.4 la sintaxis de decorador tambin funciona:
@register.simple_tag
def current_time(token):
...
Un par de cosas a tener en cuenta acerca de la funcin auxiliar
simple_tag:
10.4.5.
Etiquetas de inclusin
Otro tipo de etiquetas de plantilla comn es aquel que visualiza ciertos datos renderizando otra plantilla. Por
ejemplo la interfaz de administracin de Django usa etiquetas de plantillas personalizadas (custom ) para visualizar los
botones en la parte inferior de la pginas de formularios agregar/cambiar. Dichos botones siempre se ven igual, pero
el destino del enlace cambia dependiendo del objeto que se est modicando. Se trata de un caso perfecto para el uso
de una pequea plantilla que es llenada con detalles del objeto actual.
Ese tipo de etiquetas reciben el nombre de etiquetas de inclusin. Es probablemente mejor demostrar cmo escribir
una usando un ejemplo. Escribamos una etiqueta que produzca una lista de opciones para un simple objeto
Poll
con
{ % show_results poll %}
El resultado ser algo como esto:
<ul>
<li>First choice</li>
<li>Second choice</li>
<li>Third choice</li>
</ul>
Primero denimos la funcin que toma el argumento y produce un diccionario de datos con los resultados. Nota
que nos basta un diccionario y no necesitamos retornar nada ms complejo. Esto ser usado como el contexto para el
fragmento de plantilla:
126
def show_books_for_author(author):
books = author.book_set.all()
return {'books': books}
Luego creamos la plantilla usada para renderizar la salida de la etiqueta. Siguiendo con nuestro ejemplo, la plantilla
es muy simple:
<ul>
{ % for book in books %}
<li> {{ book }} </li>
{ % endfor %}
</ul>
Finalmente creamos y registramos la etiqueta de inclusin invocando el mtodo
Library.
polls/result_snippet.html,
register.inclusion_tag('books/books_for_author.html')(show_books_for_author)
Como siempre, la sintaxis de decoradores de Python 2.4 tambin funciona, de manera que en cambio podramos
haber escrito:
@register.inclusion_tag('books/books_for_author.html')
def show_books_for_author(show_books_for_author):
...
A veces tus etiquetas de inclusin necesitan tener acceso a valores del contexto de la plantilla padre. Para resolver
esto Django provee una opcin
takes_context
takes_context
cuando
creas una etiqueta de plantilla, la misma no tendr argumentos obligatorios y la funcin Python subyacente tendr un
argumento: el contexto de la plantilla en el estado en el que se encontraba cuando la etiqueta fue invocada.
Por ejemplo supongamos que ests escribiendo una etiqueta de inclusin que ser siempre usada en un contexto
que contiene variables
home_link
home_title
Python:
@register.inclusion_tag('link.html', takes_context=True)
def jump_link(context):
return {
'link': context['home_link'],
'title': context['home_title'],
}
Nota
El primer parmetro de la funcin debe llamarse
La plantilla
link.html
context.
{ % jump_link %}
10.5.
Los cargadores de plantillas incluidos con Django (descriptos en la seccin Etiquetas de inclusin ms arriba)
cubrirn usualmente todas tus necesidades de carga de plantillas, pero es muy sencillo escribir el tuyo propio si necesitas
alguna lgica especial en dicha carga. Por ejemplo podras cargar plantillas desde una base de datos, o directamente
desde un repositorio Subversion usando las libreras (bindings ) Python de Subversion, o (como veremos) desde un
archivo ZIP.
Un cargador de plantillas --esto es, cada entrada en la variables de conguracin
objeto invocable (callable ) con la siguiente interfaz:
revisin 757 del 28 de julio de 2008
TEMPLATE_LOADERS--
debe ser un
127
load_template_source(template_name, template_dirs=None)
El argumento template_name es el nombre de la plantilla a cargar (tal como fue pasado a loader.get_template()
loader.select_template()) y template_dirs es una lista opcional de directorios en los que se buscar en lugar
de TEMPLATE_DIRS.
Si un cargador es capaz de cargar en forma exitosa una plantilla, debe retornar una tupla: (template_source,
template_path). Donde template_source es la cadena de plantilla que ser compilada por la maquinaria de plantillas,
y template_path es la ruta desde la cual fue cargada la plantilla. Dicha ruta podra ser presentada al usuario para
o
nes de depuracin as que debe identicar en forma rpida desde dnde fue cargada la plantilla.
Si al cargador no le es posible cargar una plantilla, debe lanzar
django.template.TemplateDoesNotExist.
is_usable. Este es un Booleano que
le
informa a la maquinaria de plantillas si este cargador est disponible en la instalacin de Python actual. Por ejemplo
el cargador desde eggs (que es capaz de cargar plantillas desde eggs Python) ja
pkg_resources
pkg_resources
is_usable
False
si el mdulo
Un ejemplo ayudar a claricar todo esto. Aqu tenemos una funcin cargadora de plantillas que puede cargar
import zipfile
from django.conf import settings
from django.template import TemplateDoesNotExist
def load_template_source(template_name, template_dirs=None):
"""Template loader that loads templates from a ZIP file."""
template_zipfiles = getattr(settings, "TEMPLATE_ZIP_FILES", [])
# Try each ZIP file in TEMPLATE_ZIP_FILES.
for fname in template_zipfiles:
try:
z = zipfile.ZipFile(fname)
source = z.read(template_name)
except (IOError, KeyError):
continue
z.close()
# We found a template, so return the source.
template_path = " %s: %s" % (fname, template_name)
return (source, template_path)
# If we reach here, the template couldn't be loaded
raise TemplateDoesNotExist(template_name)
# This loader is always usable (since zipfile is included with Python)
load_template_source.is_usable = True
TEMPLATE_LOADERS.
mysite.zip_loader entonces agregaremos mysite.zip_loader.load_templ
El nico paso restante si deseamos usar este cargador es agregarlo a la variable de conguracin
Si pusiramos este cdigo en un paquete llamado
a
TEMPLATE_LOADERS.
10.6.
La interfaz de administracin de Django incluye una referencia completa de todas las etiquetas y ltros de plantillas
disponibles para un sitio determinado. Est designada para ser una herramienta que los programadores Django proveen
a los desarrolladores de plantillas. Para verla, ve a la interfaz de administracin y haz click en el enlace Documentacin
en la zona superior derecha de la pgina.
La referencia est dividida en cuatro secciones: etiquetas, ltros, modelos y vistas. Las secciones etiquetas y ltros
describen todas las etiquetas incluidas (en efecto, las referencias de etiquetas y ltros del Captulo 4 han sido extradas
directamente de esas pginas) as como cualquier biblioteca de etiquetas o ltros personalizados disponible.
La pgina views es la ms valiosa. Cada URL en tu sitio tiene all una entrada separada. Si la vista relacionada
incluye una docstring, haciendo click en la URL te mostrar lo siguiente:
revisin 757 del 28 de julio de 2008
128
object_list
la cual se encuentra en
django/views/generic/list_detail.py.
Debido a que los sitios implementados con Django generalmente usan objetos de bases de datos, las pginas models
describen cada tipo de objeto en el sistema as como todos los campos disponibles en esos objetos.
En forma conjunta, las pginas de documentacin deberan proveerte cada etiqueta, ltro, variable y objeto disponible para su uso en una plantilla arbitraria.
10.7.
Normalmente Django carga toda la informacin de conguracin que necesita desde su propio archivo de conguracin por omisin, combinado con las variables de conguracin en el mdulo indicado en la variable de entorno
DJANGO_SETTINGS_MODULE.
esquema de la variable de entorno no es muy conveniente porque probablemente quieras congurar el sistema de plantillas en una manera acorde con el resto de tu aplicacin en lugar de tener que vrtelas con archivos de conguracin
e indicando los mismos con variables de entorno.
Para resolver este problema necesitas usar la opcin de conguracin manual descripta en forma completa en el
Apndice E. En resumen, necesitas importar las partes apropiadas del sistema de plantillas y entonces, antes de invocar
alguna de las funciones de plantillas, invoca
que desees especicar.
Podras desear considerar jar al menos
(aunque el valor por omisin
utf-8
10.8.
Qu sigue?
Hasta ahora este libro ha asumido que el contenido que ests visualizando es HTML. Esta no es una suposicin
incorrecta para un libro sobre desarrollo Web, pero en algunas ocasiones querrs usar Django para generar otros
formatos de datos.
El
`prximo captulo`_ describe cmo puedes usar Django para producir imgenes, PDFs y cualquier otro
Captulo 11
11.1.
HttpRequest
HttpResponse.
La clave para retornar contenido no HTML desde una vista reside en la claseHttpResponse, especcamente en el
argumento
mimetype del constructor. Cambiando el tipo MIME, podemos indicarle al navegador que hemos retornado
open()
usar esta vista bastante sencilla para servir una imagen, y el navegador la mostrar correctamente.
La otra cosa importante a tener presente es que los objetos
Como un ejemplo de cmo funciona esto, veamos la produccin de CSV con Django.
130
11.2.
Produccin de CSV
CSV es formato de datos sencillo que suele ser usada por software de hojas de clculo. Bsicamente es una serie de
las en una tabla, cada celda en la la est separada por comas (CSV signica comma-separated values ). Por ejemplo,
aqu tienes una lista de pasajeros problemticos en lneas areas en formato CSV:
listado
precedente
Administracin
Federal
contiene
de
nmeros
Aviacin
reales;
(FAA)
cortesa
de
de
E.E.U.U.
la
Vea
http://www.faa.gov/data_statistics/passengers_cargo/unruly_passengers/.
Aunque CSV parezca simple, no es un formato que ha sido denido formalmente. Diferentes piezas de software
producen y consumen diferentes variantes de CSV, haciendo un poco complicado usarlo. Afortunadamente, Python
incluye una biblioteca estndar para CSV,
Debido a que el mdulo
csv
csv,
HttpResponse
en lugar
de un chero:
import csv
from django.http import HttpResponse
# Nmero de pasajeros problematicos por ao entre 1995 - 2005. En una aplicacin real
# esto vendra desde una base de datos o cualquier otro medio de almacenamiento.
UNRULY_PASSENGERS = [146,184,235,200,226,251,299,273,281,304,203]
def unruly_passengers_csv(request):
# Creamos el objeto Httpresponse con la cabecera CSV apropiada.
response = HttpResponse(mimetype='text/csv')
response['Content-Disposition'] = 'attachment; filename=unruly.csv'
# Creamos un escritor CSV usando a HttpResponse como "fichero"
writer = csv.writer(response)
writer.writerow(['Year', 'Unruly Airline Passengers'])
for (year, num) in zip(range(1995, 2006), UNRULY_PASSENGERS):
writer.writerow([year, num])
return response
El cdigo y los comentarios deberan ser bastante claros, pero hay unas pocas cosas que merecen mencin especial:
Se le da a la respuesta el tipo MIME
text/csv
text/html).
Esto
Content-Disposition
chero CSV. Esta cabecera (bueno, la parte adjunta) le indicar al navegador que solicite la ubicacin
donde guardar el chero (en lugar de simplemente mostrarlo). Este nombre de chero es arbitrario;
llmalo como quieras. Ser usado por los navegadores en el cuadro de dilogo Guardar como...
131
csv.writer.
La funcin
csv.writer
response
HttpResponse
se
ajustan.
Por cada la en el chero CSV, invocamos a
writer.writerow,
writerow(),
Este es el patrn general que usars siempre que necesites retornar contenido no HTML: crear un objeto
HttpResponse
de respuesta (con un tipo MIME especial), pasrselo a algo que espera un chero, y luego devolver la respuesta.
Veamos unos cuntos ejemplos ms.
11.3.
Generando PDFs
El Formato Portable de Documentos (PDF, por Portable Document Format) es un formato desarrollado por
Adobe que es usado para representar documentos imprimibles, completos con formato perfecto hasta un nivel de
detalle medido en pixels, tipografas empotradas y grcos de vectores en 2D. Puedes pensar en un documento PDF
como el equivalente digital de un documento impreso; efectivamente, los PDFs se usan normalmente cuando se necesita
entregar un documento a alguien para que lo imprima.
Puedes generar PDFs fcilmente con Python y Django gracias a la excelente biblioteca open source ReportLab
(http://www.reportlab.org/rl_toolkit.html). La ventaja de generar cheros PDFs dinmicamente es que puedes crear
PDFs a medida para diferentes propsitos -- supongamos, para diferentes usuarios u diferentes contenidos.
Por ejemplo, hemos usado Django y ReportLab en KUSports.com para generar programas de torneos de la NCAA
personalizados, listos para ser impresos.
11.3.1.
Instalando ReportLab
Antes de que puedas generar ningn PDF, debers instalar ReportLab. Esto es usualmente muy simple: slo
descarga e instala la biblioteca desde
http://www.reportlab.org/downloads.html.
http://www.reportlab.org/rsrc/userguide.
Nota
Si ests usando una distribucin moderna de Linux, podras desear comprobar con la utilidad de
manejo de paquetes de software antes de instalar ReportLab. La mayora de los repositorios de
paquetes ya incluyen ReportLab.
Por ejemplo, si ests usando la (excelente) distribucin Ubuntu, un simple
python-reportlab
apt-get install
11.3.2.
Escribiendo tu Vista
Del mismo modo que CSV, la generacin de PDFs en forma dinmica con Django es sencilla porque la API
ReportLab acta sobre objetos similares a cheros (le-like segn la jerga Python).
A continuacin un ejemplo Hola Mundo:
132
application/pdf.
PDF y no un chero HTML. Si no incluyes esta informacin, los navegadores web probablemente
interpretarn la respuesta como HTML, lo que resultar en jeroglcos en la ventana del navegador.
Interactuar con la API ReportLab es sencillo: slo pasa
canvas.Canvas.
La clase
Canvas
response
HttpResponse
se ajusta-
rn a la norma.
Todos los mtodos de generacin de PDF subsecuentes son llamados pasndoles el objeto PDF (en
este caso
p),
no
response.
11.3.3.
PDFs complejos
Si ests creando un documento PDF complejo (o cualquier pieza de datos de gran tamao), considera usar la
biblioteca
cStringIO
provee una interfaz va objetos le-like que est escrita en C para mxima eciencia.
Ese es el ejemplo Hola Mundo anterior modicado para usar
cStringIO:
cStringIO
11.4.
133
Otras posibilidades
Hay innidad de otros tipos de contenido que puedes generar en Python. Aqu tenemos algunas otras ideas y las
bibliotecas que podras usar para implementarlas:
zipfile,
leer cheros comprimidos en formato ZIP. Puedes usarla para guardar cheros bajo demanda, o quizs
comprimir grandes documentos cuando lo requieran. De la misma manera puedes generar cheros en
formato TAR usando el mdulo de la biblioteca estndar
tarfile.
Imgenes Dinmicas : Biblioteca Python de procesamiento de Imgenes (Python Imaging Library, PIL;
http://www.pythonware.com/products/pil/)
nes (PNG, JPEG, GIF, y muchas ms). Puedes usarla para escalar automticamente imgenes para
generar miniaturas, agrupar varias imgenes en un solo marco e incluso realizar procesamiento de
imgenes directamente en la web.
matplotlib (http://matplotlib.sourceforge.net/)
pygraphviz (https://networkx.lanl.gov/wiki/pygraphviz), una interfaz con la herramienta Graphviz (http://graphviz.org/), puede usarse para generar diagramas estructurados de grafos y redes.
En general, cualquier biblioteca Python capaz de escribir en un chero puede ser utilizada dentro de Django. Las
posibilidades son realmente interminables.
Ahora que hemos visto lo bsico de generar contenido no-HTML, avancemos al siguiente nivel de abstraccin.
Django incluye algunas herramientas bonitas e ingeniosas para generar cierto tipo de contenido no-HTML.
11.5.
Django incluye un framework para la generacin y sindicacin de feeds de alto nivel que permite crear feeds RSS
y Atom de manera sencilla.
Qu es RSS? Qu es Atom?
RSS y Atom son formatos basados en XML que se puede utilizar para actualizar automticamente
http://www.whatisrss.com/,
http://www.atomenabled.org/.
Para crear cualquier feed de sindicacin, todo lo que debes hacer es escribir una corta clase Python. Puedes crear
tantos feeds como desees.
11.5.1.
Inicializacin
Para activar los feeds de sindicacin en tu sitio Django, agrega lo siguiente en tu URLconf:
(r'^feeds/(?P<url>.*)/$',
'django.contrib.syndication.views.feed',
{'feed_dict': feeds}
),
Esa lnea le indica a Django que use el framework RSS para captar las URLs que comienzan con
cambiar
"feeds/"
"feeds/". (Puedes
{'feed_dict': feeds}.
al framework de feeds de sindicacin los feeds que deben ser publicados en dicha URL.
Especcamente,
134
Feed
Feed.
es una simple clase Python que representa un feed de sindicacin. Un feed puede ser simple (p. ej.
noticias del sitio, o una lista de las ltimas entradas del blog) o ms complejo (p. ej. mostrar todas las entradas de
un blog en una categora en particular, donde la categora es variable).
La clase
11.5.2.
Un Feed simple
Este ejemplo simple, tomado de chicagocrime.org, describe un feed que muestra los ltimos cinco items agregados:
django.contrib.syndication.feeds.Feed.
title, link, y description corresponden a los elementos RSS estndar <title>, <link>, y <description>
La clase es subclase de
respectivamente.
items()
es simplemente un mtodo que retorna una lista de objetos que deben incluirse en el feed
como elementos
<item>.
items()
NewsItem
Obtienes unos pocos bits de funcionalidad gratis usando los modelos de Django, pero
items() puede
El sistema RSS renderiza dicha plantilla por cada tem, pasndole dos variables de contexto para
plantillas:
revisin 757 del 28 de julio de 2008
135
title_template y description_template
Feed.
Para especicar el contenido de <link>, hay dos opciones. Por cada tem en items(), Django primero
tratar de ejecutar el mtodo get_absolute_url() en dicho objeto. Si dicho mtodo no existe, entonces trata de llamar al mtodo item_link() en la clase Feed, pasndole un nico parmetro, item,
Tambin puedes cambiar los nombres de estas plantillas especicando
get_absolute_url() y item_link() deben retornar la URL del tem como una cadena normal
de Python.
Para el ejemplo anterior
contiene:
{{ obj.title }}
latest_description.html
{{ obj.description }}
contiene:
11.5.3.
Un Feed ms complejo
Feed separada por cada departamento; esto puede violar el principio No te repitas
a ti mismo (DRY, por Do not repeat yourself ) y creara acoplamiento entre los datos y la lgica de programacin.
En su lugar, el framework de feeds de sindicacin te permite crear feeds genricos que retornan items basados en
la informacin en la URL del feed.
En chicagocrime.org, los feed por departamento de polica son accesibles mediante URLs como estas:
http://www.chicagocrime.org/rss/beats/0613/:
partamento 0613
http://www.chicagocrime.org/rss/beats/1424/:
partamento 1424
El slug aqu es
"beats".
0613
1424
--
y te provee un gancho (hook ) para que le indiques qu signica cada uno de esas partes y cmo inuyen en los items
que sern publicados en el feed.
un ejemplo aclarar esto. Este es el cdigo para los feeds por departamento:
136
/rss/beats/0613/:
['0613'].
['0613', 'foo', 'bar'].
get_object()
Para un requerimiento a
/rss/beats/0613/foo/bar/,
bits
dado.
En este caso, usa la API de base de datos de Django para obtener el departamento. Notar que
get_object()
django.core.exceptions.ObjectDoesNotExist si
try/except abarcando la llamada a Beat.objects.get()
porque no es necesario. Esa funcin, ante una falla lanza la excepcin Beat.DoesNotExist, y
Beat.DoesNotExist es una subclase de ObjectDoesNotExist. Lanzar la excepcin ObjectDoesNotExist
en get_object() le dice a Django que produzca un error 404 error para el requerimiento en curso.
debe capturar la excepcin
<title>, <link>,
description(). En el
title(), link(),
<description>
clase string, pero este ejemplo muestra que estos pueden ser strings o mtodos. Por cada
link,
description,
title,
get_object().
obj,
donde
obj
es el objeto
Feed
11.5.4.
Por omisin, el framework de feeds de sindicacin produce RSS 2.0. Para cambiar eso, agrega un atributo
a tu clase
Feed:
feed_type
feed_type una clase, no a una instancia. Los tipos de feeds disponibles actualmente
Clase Feed
Formato
django.utils.feedgenerator.Rss201rev2Feed
django.utils.feedgenerator.RssUserland091Feed
django.utils.feedgenerator.Atom1Feed
11.5.5.
137
Enclosures
Para especicar enclosures (p. ej. recursos multimedia asociados al tem del feed tales como feeds de podcasts
MP3), usa los ganchos
item_enclosure_url, item_enclosure_length,
item_enclosure_mime_type,
por ejemplo:
Song
song_url
song_length
(p. ej. el
tamao en bytes).
11.5.6.
Idioma
11.5.7.
xml:lang
URLs
link
dicacin completa esto automticamente, usando el dominio del sitio actual acorde a la variable de conguracin
SITE_ID.
11.5.8.
Algunos desarrolladores preeren ofrecer ambas versiones Atom y RSS de sus feeds. Esto es simple de hacer con
Django: solamente crea una subclase de tu clase
feed
y asigna a
feed_type
138
11.6.
El framework Sitemap
Un sitemap es un chero XML en tu sitio web que le indica a los indexadores de los motores de bsqueda cuan
frecuentemente cambian tus pginas as como la importancia relativa de ciertas pginas en relacin con otras (siempre
hablando de pginas de tu sitio). Esta informacin ayuda a los motores de bsqueda a indexar tu sitio.
Por ejemplo, esta es una parte del sitemap del sitio web de Django (http://www.djangoproject.com/sitemap.
xml):
http://www.sitemaps.org/.
El framework sitemap de Django automatiza la creacin de este chero XML si lo indicas expresamente en el cdigo
Python. Para crear un sitemap, debes simplemente escribir una clase
Sitemap
URLconf.
11.6.1.
Instalacin
'django.contrib.sitemaps'
#. Asegrate de que
a tu variable de conguracin
INSTALLED_APPS.
'django.template.loaders.app_directories.load_template_source' est en tu
TEMPLATE_LOADERS. Por omisin se encuentra activado, por lo que los cambios
variable de conguracin
Nota
La aplicacin sitemap no instala tablas en la base de datos. La nica razn de que est en
INSTALLED_APPS
load_template_source
plantillas includas.
11.6.2.
139
Inicializacin
Para activar la generacin del sitemap en tu sitio Django, agrega la siguiente lnea a tu URLconf:
/sitemap.xml.
El nombre del chero sitemap no es importante, pero la ubicacin s lo es. Los motores de bsqueda solamente
indexan los enlaces en tu sitemap para el nivel de URL actual y anterior. Por ejemplo, si
sitemap.xml
reside en
tu directorio principal, el mismo puede hacer referencia a cualquier URL en tu sitio. Pero si tu sitemap reside en
/content/sitemap.xml,
/content/.
{'sitemaps': sitemaps}. sitemaps debe ser un diccionario que
de seccin (p. ej. blog o news) a tu clase Sitemap (p.e., BlogSitemap o NewsSitemap).
instancia de una clase Sitemap (p. ej. BlogSitemap(some_var)).
11.6.3.
Clases Sitemap
Una clase
eventos de tu calendario.
En el caso ms simple, todas estas secciones se unen en un nico
sitemap.xml,
framework para generar un ndice sitemap que haga referencia cheros sitemap individuales, uno por seccin (describindolo sintticamente).
Las clases
Sitemap debe ser una subclase de django.contrib.sitemaps.Sitemap. Estas pueden residir en cualquier
Sitemap
Entry,
Sitemap
Feed,
los miembros de
Sitemap
Feed;
Sitemap
items (requerido): Provee una lista de objetos. Al framework no le importa que tipo de objeto es; todo
location(), lastmod(), changefreq(),
y priority().
location (opcional): Provee la URL absoluta para el objeto dado. Aqu URL absoluta
signica una
Si
Bien:
Mal:
Mal:
'/foo/bar/'
'example.com/foo/bar/'
'http://example.com/foo/bar/'
lastmod (opcional): La fecha de ltima modicacin del objeto, como un objeto datetime de Python.
changefreq
(opcional): Cun a menudo el objeto cambia. Los valores posibles (segn indican las
140
'always'
'hourly'
'daily'
'weekly'
'monthly'
'yearly'
'never'
priority
funciona
11.6.4.
0.5; ver
priority.
una pgina es
la documentacin de
Accesos directos
El framework sitemap provee un conjunto de clases para los casos ms comunes. Describiremos estos casos en las
secciones a continuacin.
FlatPageSitemap
La clase
django.contrib.sitemaps.FlatPageSitemap
actual y crea una entrada en el sitemap. Estas entradas incluyen solamente el atributo
changefreq,
priority.
location
-- no
lastmod,
Sitemap Genrico
GenericSitemap trabaja con cualquier vista genrica (ver Captulo 9) que pudieras poseer con anterioridad.
info_dict que se pasa a la vista genrica. El nico
requerimiento es que el diccionario tenga una entrada queryset. Tambin debe poseer una entrada date_field
que especica un campo fecha para los objetos obtenidos del queryset. Esto ser usado por el atributo lastmod
en el sitemap generado. Tambin puedes pasar los argumentos palabra clave (keyword ) priority y changefreq al
constructor GenericSitemap para especicar dichos atributos para todas las URLs.
Este es un ejemplo de URLconf usando tanto, FlatPageSitemap como GenericSiteMap (con el anterior objeto
hipottico Entry):
La clase
# the sitemap
(r'^sitemap.xml$',
'django.contrib.sitemaps.views.sitemap',
{'sitemaps': sitemaps})
11.6.5.
141
El framework sitemap tambin tiene la habilidad de crear ndices sitemap que hagan referencia a cheros sitemap
individuales, uno por cada seccin denida en tu diccionario
Usas dos vistas en tu URLconf:
sitemaps.
django.contrib.sitemaps.views.index y django.contrib.sitemaps.views.si
django.contrib.sitemaps.views.sitemap
section.
La vista
mado
(r'^sitemap.xml$',
'django.contrib.sitemaps.views.index',
{'sitemaps': sitemaps}),
(r'^sitemap-(?P<section>.+).xml$',
'django.contrib.sitemaps.views.sitemap',
{'sitemaps': sitemaps})
Esto genera automticamente un chero
sitemap-blog.xml.
11.6.6.
La clase
Sitemap
y el diccionario
Puedes desear hacer un ping a Google cuando tu sitemap cambia, para hacerle saber que debe reindexar tu sitio.
El framework provee una funcin para hacer justamente eso:
django.contrib.sitemaps.ping_google().
Nota
Hasta el momento en que este libro se escribi, nicamente Google responde a los pings de
sitemap. Pero es muy probable que pronto Yahoo y/o MSN tambin admitan estos pings.
eso
suceda,
cambiaremos
el
nombre
de
ping_google() a algo como
ping_search_engines(), as que asegrate de vericar la ultima documentacin de sitemap en http://www.djangoproject.com/documentation/0.96/sitemaps/.
Cuando
ping_google() toma un argumento opcional, sitemap_url, que debe ser la URL absoluta de tu sitemap (por ej.,
'/sitemap.xml'). Si este argumento no es provisto, ping_google() tratar de generar un sitemap realizando una
bsqueda reversa en tu URLconf.
ping_google()
lanza la excepcin
de tu sitemap.
Una forma til de llamar a
django.contrib.sitemaps.SitemapNotFound
ping_google()
es desde el mtodo
save():
ping_google()
desde un script
cron
o un manejador de
tareas. La funcin hace un pedido HTTP a los servidores de Google, por lo que no querrs introducir esa demora
asociada a la actividad de red cada vez que se llame al mtodo
save().
142
11.7.
Qu sigue?
A continuacin, seguiremos indagando ms profundamente en las herramientas internas que Django nos ofrece.
El Captulo 12 examina todas las herramientas que necesitas para proveer sitios personalizados: sesiones, usuarios, y
autenticacin.
Adelante!
Captulo 12
12.1.
Cookies
Los desarrolladores de navegadores hace tiempo que se dieron cuenta de que esta carencia de estados iba a representar un problema para los desarrolladores web, y as fue como nacieron las cookies (literalmente galleta ). Una cookie
es una pequea cantidad de informacin que el servidor delega en el navegador, de forma que este la almacena. Cada
vez que el cliente web solicita una pgina del servidor, se le enva de vuelta la cookie.
Veamos con un poco ms de detalle el funcionamiento. Cuando abrimos nuestro navegador y escribimos
google.com,
el navegador enva una solicitud HTTP a Google que empieza ms o menos as:
GET / HTTP/1.1
Host: google.com
...
Cuando Google responde, la respuesta contiene algo parecido a esto:
HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: PREF=ID=5b14f22bdaf1e81c:TM=1167000671:LM=1167000671;
expires=Sun, 17-Jan-2038 19:14:07 GMT;
path=/; domain=.google.com
Server: GWS/2.1
...
Fjate en la lnea que comienza con
y se lo volver a enviar a Google cada vez que vuelva a acceder a alguna de sus pginas; de esa forma, la prxima vez
que vuelvas a Google, la peticin que enviar el navegador se parecer a esta:
GET / HTTP/1.1
Host: google.com
Cookie: PREF=ID=5b14f22bdaf1e81c:TM=1167000671:LM=1167000671
...
revisin 757 del 28 de julio de 2008
144
Google puede saber ahora, gracias al valor de la Cookie, que eres la misma persona que accedi un rato antes. Este
valor puede ser, por ejemplo, una clave en una tabla de la base de datos que almacene los datos del usuario. Con esa
informacin, Google puede hacer aparecer tu nombre en la pgina (De hecho, lo hace).
12.1.1.
A la hora de utilizar las capacidades de persistencia de Django, lo ms probable es que uses las prestaciones de
alto nivel para la gestin de sesiones y de usuarios, prestaciones que discutiremos un poco ms adelante en este mismo
captulo. No obstante, ahora vamos a hacer una breve parada y veremos como leer y denir cookies a bajo nivel. Esto
debera ayudarte a entender como funcionan el resto de las herramientas que veremos en el captulo, y te ser de
utilidad si alguna vez tienes que trabajar con las cookies directamente.
Obtener los valores de las cookies que ya estn denidas es muy fcil. Cada objeto de tipo peticin,
contiene un objeto
COOKIES
request,
que se comporta como un diccionario; puedes usarlo para leer cualquier cookie que el
def show_color(request):
if "favorite_color" in request.COOKIES:
return HttpResponse("Your favorite color is %s" % \
request.COOKIES["favorite_color"])
else:
return HttpResponse("You don't have a favorite color.")
Denir los valores de las cookies es slo un poco ms complicado. Debes usar el mtodo
HttpResponse.
parmetro GET:
de tipo
como
favorite_color
set_cookie() en un objeto
def set_color(request):
if "favorite_color" in request.GET:
# Create an HttpResponse object...
response = HttpResponse("Your favorite color is now %s" % \
request.GET["favorite_color"])
# ... and set a cookie on the response
response.set_cookie("favorite_color",
request.GET["favorite_color"])
return response
else:
return HttpResponse("You didn't give a favorite color.")
Hay una serie de parmetros opcionales que puedes pasar a
response.set_cookie()
Parmetro
max_age
None
Descripcin
El tiempo (en segundos) que la cookie debe permanecer activa. Si este
parmetro es, la cookie desaparecer automticamente cuando se cierre
el navegador.
expires
None
path
"/"
max_age.
145
Parmetro
domain
None
Descripcin
El dominio para el cual es vlida la cookie. Se puede usar este
parmetro para denir una cookie que sea apta para varios domi-
secure
False
True,
12.1.2.
Puede que te hayas dado cuenta de algunos de los problemas potenciales que se presentan con esto de las cookies;
vamos a ver algunos de los ms importantes:
El almacenamiento de los cookies es voluntario; los navegadores no dan ninguna garanta. De hecho,
los navegadores permiten al usuario denir una poltica de aceptacin o rechazo de las mismas. Para
darte cuenta de lo muy usadas que son las cookies en la web actual, simplemente activa la opcin de
Avisar antes de aceptar cualquier cookie y date un paseo por Internet.
A pesar de su uso habitual, las cookies son el ejemplo perfecto de algo que no es conable. Esto
signica que el desarrollador debe comprobar que el usuario est dispuesto a aceptar las cookies antes
de conar en ellas.
An ms importante, nunca debes almacenar informacin fundamental en las cookies. La Web rebosa
de historias de terror acerca de desarrolladores que guardaron informacin irrecuperable en las cookies
del usuario, solo para encontrarse con que el navegador haba borrado todos esos datos por cualesquiera
razones.
Las Cookies (Especialmente aquellas que no se envan mediante HTTPS) no son seguras. Dado que los
datos enviados viajan en texto claro, estn expuestas a que terceras personas lean esa informacin, lo
que se llama ataques de tipo snooping (por snoop, sgonear, husmear). Por lo tanto, un atacante que
tenga acceso al medio puede interceptar la cookie y leer su valor. El resultado de esto es que nunca se
debe almacenar informacin condencial en una cookie.
Hay otro tipo de ataque, an ms insidioso, conocido como ataque man-in-the-middle o MitM (Ataque
de tipo Hombre-en-medio o Intermediario). Aqu, el atacante no solo intercepta la cookie, sino que
adems la usa para actuar ante el servidor como si fuera el usuario legtimo. El
`Captulo 19`_
IsLoggedIn=1
se ha validado. Te sorprendera saber cuantos sitios web cometen este tipo de error; no lleva ms de
unos segundos engaar a sus sistemas de seguridad.
12.2.
Con todas estas limitaciones y agujeros potenciales de seguridad, es obvio que la gestin de las cookies y de las
sesiones persistentes es el origen de muchos dolores de cabeza para los desarrolladores web. Por supuesto, uno de los
objetivos de Django es evitar ecazmente estos dolores de cabeza, as que dispone de un entorno de sesiones diseado
para suavizar y facilitar todas estas cuestiones por ti.
El entorno de sesiones te permite almacenar y recuperar cualquier dato que quieras basndote en la sesin del
usuario. Almacena la informacin relevante solo en el servidor y abstrae todo el problema del envo y recepcin de las
146
cookies. Estas solo almacenan una versin codicada (hash ) del identicador de la sesin, y ningn otro dato, lo cual
te aisla de la mayora de los problemas asociados con las cookies.
Veamos como activar las sesiones, y como usarlas en nuestras vistas.
12.2.1.
Activar sesiones
Las sesiones se implementan mediante un poco de middleware (vase Captulo 15) y un modelo Django. Para
activar las sesiones, necesitas seguir los siguientes pasos:
1. Editar el valor de
2. Comprobar que
ejecutar
startproject
en el valor de
INSTALLED_APPS
(Y
que las hayas borrado, es muy probable que no tengas que hacer nada para empezar a usar las sesiones.
Si lo que quieres en realidad es no usar sesiones, deberas quitar la referencia a
y borrar
'django.contrib.sessions'
de
INSTALLED_APPS.
SessionMiddleware de MIDDLEWARE_CLASSES
12.2.2.
leer y escribir en l de la misma forma en que lo haras con un diccionario normal. Por ejemplo, podras usar algo
como esto en una de tus vistas:
keys()
items()
en
request.session.
Hay dos o tres reglas muy sencillas para usar ecazmente las sesiones en Django:
Debes usar slo cadenas de texto normales como valores de clave en
request.session,
en vez de,
por ejemplo, enteros, objetos, etc. Esto es ms un convenio que un regla en el sentido estricto, pero
merece la pena seguirla.
Los valores de las claves de una sesin que empiecen con el carcter subrayado estn reservadas para
uso interno de Django. En la prctica, slo hay unas pocas variables as, pero, a no ser que sepas
lo que ests haciendo (y ests dispuesto a mantenerte al da en los cambios internos de Django), lo
mejor que puedes hacer es evitar usar el carcter subrayado como prejo en tus propias variables; eso
impedir que Django pueda interferir con tu aplicacin,
Nunca reemplaces
request.session
has_commented
como
True
despus de que
el usuario haya publicado un comentario. Es una forma sencilla (aunque no particularmente segura) de impedir que el
usuario publique dos veces el mismo comentario:
147
def login(request):
try:
m = Member.objects.get(username__exact=request.POST['username'])
if m.password == request.POST['password']:
request.session['member_id'] = m.id
return HttpResponse("You're logged in.")
except Member.DoesNotExist:
return HttpResponse("Your username and password didn't match.")
Y esta le permite cerrar o salir de la sesin:
def logout(request):
try:
del request.session['member_id']
except KeyError:
pass
return HttpResponse("You're logged out.")
Nota
En la prctica, esta sera una forma psima de validar a tus usuarios. El mecanismo de autenticacin que presentaremos un poco ms adelante realiza esta tarea de forma mucho ms segura y
robusta. Los ejemplo son deliberadamente simples para que se comprendan con ms facilidad.
12.2.3.
cookies
sean utilizables
Como ya mencionamos, no se puede conar en que el cualquier navegador sea capaz de aceptar cookies. Por ello,
Django incluye una forma fcil de comprobar que el cliente del usuario disponga de esta capacidad. Slo es necesario
llamar a la funcin
forma es que trabajan las cookies. Cuando se dene una cookie, no tienes forma de saber si el navegador la ha aceptado
realmente hasta la siguiente solicitud.
Es una prctica recomendable llamar a la funcin
de haberla usado. Lo mejor es hacerlo justo despus de haber vericado que las cookies funcionan.
He aqu un ejemplo tpico de uso:
def login(request):
# If we submitted the form...
if request.method == 'POST':
# Check that the test cookie worked (we set it below):
if request.session.test_cookie_worked():
# The test cookie worked, so delete it.
request.session.delete_test_cookie()
# In practice, we'd need some logic to check username/password
# here, but since this is an example...
return HttpResponse("You're logged in.")
# The test cookie failed, so display an error message. If this
revisin 757 del 28 de julio de 2008
148
12.2.4.
Internamente, cada sesin es simplemente un modelo de entidad de Django como cualquier otro, denido en
es el valor que se almacena en la cookie. Dado que es un modelo normal, puedes acceder a las propiedades de las
sesiones usando la API de acceso a la base de datos de Django:
>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}
12.2.5.
Django, en principio, solo salva la sesin en la base de datos si esta ha sido modicada; es decir, si cualquiera de
los valores almacenados en el diccionario es asignado o borrado. Esto puede dar lugar a algunos errores sutiles, como
se indica en el ltimo ejemplo:
# Session is modified.
request.session['foo'] = 'bar'
# Session is modified.
del request.session['foo']
# Session is modified.
request.session['foo'] = {}
# Gotcha: Session is NOT modified, because this alters
# request.session['foo'] instead of request.session.
request.session['foo']['bar'] = 'baz'
Se puede cambiar este comportamiento, especicando la opcin
SESSION_SAVE_EVERY_REQUEST
True.
Si lo ha-
cemos as, Django salvar la sesin en la base de datos en cada peticin, incluso si no se ha modicado ninguno de sus
valores.
SESSION_SAVE_EVERY_REQUEST
True, la cookie de sesin ser reenviada en cada peticin. De forma similar, la seccin de expiracin (expires)
Fjate que la cookie de sesin slo se enva cuando se ha creado o modicado una sesin. Si
est como
12.2.6.
149
Es posible que te hayas jado en que la cookie que nos envi Google al principio del captulo contena el siguiente
texto
cin, que informa al navegador del momento en que se debe desechar, por invlida. Si la cookie no contiene ningn
valor de expiracin, el navegador entiende que esta debe expirar en el momento en que se cierra el propio navegador.
Se puede controlar el comportamiento del entorno para que use cookies de este tipo, breves, ajustando en valor de la
SESSION_EXPIRE_AT_BROWSER_CLOSE.
SESSION_EXPIRE_AT_BROWSER_CLOSE es False, lo que signica que las cookies
almacenadas en el navegador del usuario durante SESSION_COOKIE_AGE segundos (Cuyo valor por defecto es de
opcin
dos semanas, o 1.209.600 segundos). Estos valores son adecuados si no quieres obligar a tus usuarios a validarse cada
vez que abran el navegador y accedan a tu pgina.
Si
SESSION_EXPIRE_AT_BROWSER_CLOSE
se establece a
True,
12.2.7.
Adems de las caractersticas ya mencionadas, hay otros valores de conguracin que inuyen en la gestin de
sesiones con Django, tal y como se muestra en la tabla 12-2.
Cuadro 12.2: Valores de conguracin que inuyen en el comportamiento de las cookies
Opcin
SESSION_COOKIE_DOMAIN
Descripcin
None
".lawrence.com"
None
SESSION_COOKIE_NAME
"sessionid"
SESSION_COOKIE_SECURE
Indica si se debe usar una cookie segura para la cookie de sesin. Si el valor es
True,
False
150
Detalles tcnicos
Para los ms curiosos, he aqu una serie de notas tcnicas acerca de algunos aspectos interesantes
de la gestin interna de las sesiones:
El diccionario de la sesin acepta cualquier objeto Python capaz de ser serializado con
pickled.
pickle
incluido en la
django_session.
request.session,
Django
slo
enva
la
cookie
si
tiene
que
hacerlo.
Si
no
modicas
nin-
SESSION_SAVE_EVERY_REQUEST
como
True).
aun
te
pica
la
curiosidad,
django.contrib.sessions
12.3.
el
cdigo
fuente
es
Referer.
bastante
directo
claro,
mira
en
para ms detalles.
Usuarios e identicacin
TM . Las sesiones nos permiten
Estamos ya a medio camino de poder conectar los navegadores con la Gente de Verdad
almacenar informacin a lo largo de las diferentes peticiones del navegador; la segunda parte de la ecuacin es utilizar
esas sesiones para validar al usuario, es decir, permitirle hacer login. Por supuesto, no podemos simplemente conar
en que los usuarios sean quien dicen ser, necesitamos autenticarlos de alguna manera.
Naturalmente, Django nos proporciona las herramientas necesarias para tratar con este problema tan habitual (Y
con muchos otros). El sistema de autenticacin de usuarios de Django maneja cuentas de usuarios, grupos, permisos
y sesiones basadas en cookies. El sistema tambin es llamada sistema aut/aut (autenticacacin y autorizacin). El
nombre implica que, a menudo, tratar con los usuarios implica dos procesos. Se necesita:
Vericar (autenticacin ) que un usuario es quien dice ser (Normalmente comprobando un nombre
de usuario y una contrasea contra una tabla de una base de datos)
Vericar que el usuario est autorizado (autorizacin ) a realizar una operacin determinada (Normalmente comprobando una tabla de permisos)
Siguiendo estos requerimientos, el sistema aut/aut de Django consta de los siguientes componentes:
12.3.1.
151
Al igual que ocurra con las sesiones, el sistema de autenticacin viene incluido como una aplicacin en el mdulo
django.contrib,
y necesita ser instalado. De igual manera, viene instalado por defecto, por lo que solo es necesario
'django.contrib.auth'
dentro de tu
INSTALLED_APPS
y ejecuta
manage.py syncdb.
'django.contrib.auth.middleware.AuthenticationMiddleware'
MIDDLEWARE_CLASSES despus de SessionMiddleware.
Asegrate de que
en
est incluido
Una vez resuelto este tema, ya estamos preparados para empezar a lidiar con los usuarios en nuestras vistas. La
principal interfaz que usars para trabajar con los datos del usuario dentro de una vista es
request.user; es un objeto
que representa al usuario que est conectado en ese momento. Si no hay ningn usuario conectado, este objeto ser
una instancia de la clase
AnonymousUser
is_authenticated():
if request.user.is_authenticated():
# Do something for authenticated users.
else:
# Do something for anonymous users.
12.4.
Utilizando usuarios
que se describirn en breve) dispondrs de una serie de campos de datos y mtodos asociados al mismo. Los objetos
AnonymousUser emulan parte de esta interfaz, pero no toda, por lo que es preferible comprobar el resultado
user.is_authenticated() antes de asumir de buena fe que nos encontramos ante un usuario legtimo. Las tablas
12-3 y 12-4 listan todos los campos y mtodos, respectivamente, de los objetos de la clase User.
de la clase
de
Campo
username
Descripcin
Obligatorio; 30 caracteres como mximo. Slo acepta caracteres alfanumricos (letras, dgitos y el carcter subrayado).
first_name
last_name
email
password
is_staff
is_active
Booleano. Indica que la cuenta puede ser usada para identicarse. Se puede
poner a
False
tabla.
is_superuser
last_login
Fecha y hora de la ltima vez que el usuario se identic. Se asigna automticamente a la fecha actual por defecto.
date_joined
Fecha y hora en que fue creada esta cuenta de usuario. Se asigna automticamente a la fecha actual en su momento.
152
Mtodo
Descripcin
is_authenticated()
Siempre devuelve
True
de determinar si el usuario se ha identicado. esto no implica que posea ningn permiso, y tampoco comprueba que
la cuenta est activa. Slo indica que el usuario se ha identicado con xito.
is_anonymous()
get_full_name()
set_password(passwd)
check_password(passwd)
devuelve
True
User.
coincide con la contrasea del usuario. Realiza internamente las operaciones necesarias para calcular los cdigos de
comprobacin o hash necesarios.
get_group_permissions()
get_all_permissions()
has_perm(perm)
has_perms(perm_list)
has_module_perms(app_label)
get_and_delete_messages()
Devuelve
email_user(subj, msg)
una
lista
de
mensajes
(objetos
de
la
clase
metro opcional,
remite distinta.
get_profile()
permisos (groups y
153
Django proporciona vistas predenidas para gestionar la entrada del usuario, (el momento en que se identica), y la
salida, (es decir, cuando cierra la sesin), adems de otros trucos ingeniosos. Pero antes de entrar en detalles, veremos
como hacer que los usuario pueden iniciar y cerrar la sesin a mano. Django incluye dos funciones para realizar estas
acciones, en el mdulo
django.contrib.auth: authenticate()
login().
username
password,
User
authenticate().
esta funcin
identicador de usuario. Si falla la comprobacin (ya sea porque sea incorrecta la contrasea o porque sea incorrecta
la identicacin del usuario), la funcin devolver
>>>
>>>
>>>
...
...
...
None:
La llamada a
login() para
objeto User y
authenticate()
slo verica las credenciales del usuario. Todava hay que realizar una llamada a
login()
HttpRequest
y un
authenticate()
login(),
logout()
En la prctica, no es normalmente necesario escribir tus propias funciones para realizar estas tareas; el sistema de
autenticacin viene con un conjunto de vistas predenidas para ello.
revisin 757 del 28 de julio de 2008
154
El primer paso para utilizar las vistas de autenticacin es mapearlas en tu URLconf. Necesitas modicar tu cdigo
hasta tener algo parecido a esto:
/accounts/logout/ son las URL por defecto que usa Django para estas vistas.
login utiliza la plantilla denida en registration/login.html (puedes cambiar el nombre
de la plantilla utilizando un parmetro opcional, template_name). El formulario necesita contener un campo llamado
username y otro llamado password. Una plantilla de ejemplo podra ser esta:
y
{ % extends "base.html" %}
{ % block content %}
{ % if form.errors %}
<p class="error">Sorry, that's not a valid username or password</p>
{ % endif %}
<form action='.' method='post'>
<label for="username">User name:</label>
<input type="text" name="username" value="" id="username">
<label for="password">Password:</label>
<input type="password" name="password" value="" id="password">
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next|escape }}" />
<form action='.' method='post'>
{ % endblock %}
/accounts/profile/. Puedes indicar una
next, cuyo valor debe ser la URL
puedes pasar este valor como un parmetro GET a la vista de
al contexto en una variable llamada next, que puedes incluir
La vista de cierre de sesin se comporta de forma un poco diferente. Por defecto utiliza la plantilla denida
en
registration/logged_out.html
next_page,
12.4.2.
Por supuesto, la razn de haber implementado todo este sistema es permitirnos limitar el acceso a determinadas
partes de nuestro sitio.
La forma ms simple y directa de limitar este acceso es comprobar el resultado de llamar a la funcin
y redirigir a una pgina de identicacin, si procede:
request.user.is_authentic
155
def my_view(request):
if not request.user.is_authenticated():
return render_to_response('myapp/login_error.html')
# ...
Si se desea abreviar, se puede usar el decorador
login_required
login_required:
/accounts/login/, incluyendo la url
/accounts/login/?next=/polls/3/.
next,
por ejemplo
actual
Si el usuario est identicado, ejecuta la vista sin ningn cambio. La vista puede asumir sin problemas
que el usuario esta identicado correctamente
12.4.3.
Se puede limitar el acceso basndose en ciertos permisos o en algn otro tipo de prueba, o proporcionar una pgina
de identicacin distinta de la vista por defecto, y las dos cosas se hacen de manera similar.
La forma ms cruda es ejecutar las pruebas que queremos hacer directamente en el cdigo de la vista. Por ejemplo,
para comprobar que el usuario est identicado y que, adems, tenga asignado el permiso
def vote(request):
if request.user.is_authenticated() and request.user.has_perm('polls.can_vote')):
# vote here
else:
return HttpResponse("You can't vote in this poll.")
De nuevo, Django proporciona una forma abreviada llamada
user_passes_test.
def user_can_vote(user):
return user.is_authenticated() and user.has_perm("polls.can_vote")
@user_passes_test(user_can_vote, login_url="/login/")
def vote(request):
# Code here can assume a logged-in user with the correct permission.
...
user_passes_test tiene un parmetro obligatorio: un objeto que se pueda llamar (normalmente una
User, y devuelva True si el usuario puede acceder
caso contrario. Es importante destacar que user_passes_test no comprueba automticamente que el
El decorador
False
en
usuario est identicado; esa es una comprobacin que se debe hacer explcitamente.
En este ejemplo, hemos usado tambin un segundo parmetro opcional,
login_url,
de la pgina que el usuario debe utilizar para identicarse (/accounts/login/ por defecto).
Comprobar si un usuario posee un determinado permiso es una tarea muy frecuente, as que Django proporciona una
forma abreviada para estos casos: El decorador
permission_required().
login_url,
156
12.4.4.
admin.
El
Captulo 6 describe como usar esta interfaz para modicar los datos de los usuarios y controlar sus permisos y accesos,
y la mayor parte del tiempo esa es la forma ms adecuada de gestin.
A veces, no obstante, hace falta un mayor control, y para eso podemos utilizar las llamadas a bajo nivel que
describiremos en este captulo.
Crear usuarios
Puedes crear usuarios con el mtodo
create_user:
user
save()).
User,
quieres:
set_password():
password,
contrasea se almacena en la base de datos en forma de cdigo de comprobacin (salted hash ) y, por tanto, debe ser
modicada slo a travs de este mtodo.
Para ser ms exactos, el atributo
password
de un objeto
User
hashtype$salt$hash
Es decir, el tipo de hash, el grano de sal (salt ) y el cdigo hash propiamente dicho, separados entre si por el carcter
dolar ($).
El valor de
hashtype puede ser sha1 (por defecto) o md5, el algoritmo usado para realizar una transformacin hash
de un solo sentido sobre la contrasea. El grano de sal es una cadena de texto aleatoria que se utiliza para aumentar
la resistencia de esta codicacin frente a un ataque por diccionario. Por ejemplo:
sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4
revisin 757 del 28 de julio de 2008
Las funciones
157
User.set_password()
User.check_password()
de forma transparente.
from
from
from
from
def register(request):
form = UserCreationForm()
if request.method == 'POST':
data = request.POST.copy()
errors = form.get_validation_errors(data)
if not errors:
new_user = form.save(data)
return HttpResponseRedirect("/books/")
else:
data, errors = {}, {}
return render_to_response("registration/register.html", {
'form' : forms.FormWrapper(form, data, errors)
})
revisin 757 del 28 de julio de 2008
158
{ % extends "base.html" %}
{ % block title %}Create an account{ % endblock %}
{ % block content %}
<h1>Create an account</h1>
<form action="." method="post">
{ % if form.error_dict %}
<p class="error">Please correct the errors below.</p>
{ % endif %}
{ % if form.username.errors %}
{{ form.username.html_error_list }}
{ % endif %}
<label for="id_username">Username:</label> {{ form.username }}
{ % if form.password1.errors %}
{{ form.password1.html_error_list }}
{ % endif %}
<label for="id_password1">Password: {{ form.password1 }}
{ % if form.password2.errors %}
{{ form.password2.html_error_list }}
{ % endif %}
<label for="id_password2">Password (again): {{ form.password2 }}
<input type="submit" value="Create the account" />
</label>
{ % endblock %}
Nota
django.contrib.auth.forms.UserCreationForm es, a la hora de publicar esto, un formulario del estilo oldforms. Vase http://www.djangoproject.com/documentation/0.96/forms/
para ms detalles sobre oldforms. La transicin al nuevo sistema, tal y como se explica en el captulo siete, ser completada muy pronto.
12.4.5.
El usuario actual, as como sus permisos, estn disponibles en el contexto de la plantilla cuando usas
(vase
RequestContext
`Captulo 10`_).
Nota
Tcnicamente
hablando,
tilla
usas
estas
variables
estn
RequestContext y en
"django.core.context_processors.auth" en
slo
si
disponibles
la
en
el
conguracin
la opcin
contexto
est
de
incluido
la
plan-
el
valor
TEMPLATE_CONTEXT_PROCESSORS,
que es el valor que viene predenido cuando se crea un proyecto. Como ya se coment, vase
el
Cuando se usa
RequestContext, el usuario actual (Ya sea una instancia de User o de AnonymousUser) es accesible
{{ user }}:
{ % if user.is_authenticated %}
<p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{ % else %}
<p>Welcome, new user. Please log in.</p>
{ % endif %}
revisin 757 del 28 de julio de 2008
{{ perms }}.
159
perms. Puedes usar {{ perms.polls }} para comprobar si un usuario tienen al{{ perms.polls.can_vote
gn permiso para una determinada aplicacin, o se puede usar una forma ms especca, como
}},
{ % if %}:
{ % if perms.polls %}
<p>You have permission to do something in the polls app.</p>
{ % if perms.polls.can_vote %}
<p>You can vote!</p>
{ % endif %}
{ % else %}
<p>You don't have permission to do anything in the polls app.</p>
{ % endif %}
12.5.
Hay unas cuantas cosas que pertenecen al entorno de autenticacin y que hasta ahora slo hemos podido ver de
pasada. En esta seccin las veremos con un poco ms de detalle.
12.5.1.
Permisos
Los permisos son una forma sencilla de marcar que determinados usuarios o grupos pueden realizar una accin.
Se usan normalmente para la parte de administracin de Django, pero puedes usarlos tambin en tu cdigo.
El sistema de administracin de Django utiliza los siguientes permisos:
Acceso a visualizar el formulario Aadir, y Aadir objetos, est limitado a los usuarios que tengan
el permiso add para ese tipo de objeto.
El acceso a la lista de cambios, ver el formulario de cambios y cambiar un objeto est limitado a los
usuarios que tengan el permisos change para ese tipo de objeto.
Borrar objetos est limitado a los usuarios que tengan el permiso delete para ese tipo de objeto.
Los permisos se denen a nivel de las clases o tipos de objetos, no a nivel de instancias. Por ejemplo, se puede decir
Mara puede modicar los reportajes nuevos, pero no Mara solo puede modicar los reportajes nuevos que haya
creado ella, ni Mara slo puede cambiar los reportajes que tengan un determinado estado, fecha de publicacin o
identicador.
Estos tres permisos bsicos, aadir, cambiar y borrar, se crean automticamente para cualquier modelo Django
que incluya una clase
manage.py syncdb.
Admin.
auth_permission
cuando ejecutas
aplicacin llamada
class USCitizen(models.Model):
# ...
class Meta:
permissions = (
# Permission identifier
("can_drive",
("can_vote",
("can_drink",
)
160
syncdb.
vistas.
Igual que con los usuarios, los permisos se implementa en un modelo Django que reside en el mdulo
django.contrib.auth.model
Esto signica que puedes usar la API de acceso a la base de datos para interactuar con los permisos de la forma que
quieras.
12.5.2.
Grupos
Los grupos son una forma genrica de trabajar con varios usuarios a la vez, de forma que se les pueda asignar
permisos o etiquetas en bloque. Un usuario puede pertenecer a varios grupos a la vez.
Un usuario que pertenezca a un grupo recibe automticamente todos los permisos que se la hayan otorgado al
grupo. Por ejemplo, si el grupo
Editores
tiene el permiso
can_edit_home_page,
Usuarios especiales,
y utilizar
cdigo para permitir el acceso a determinadas porciones de tu sitio slo a los miembros de ese grupo, o para enviarles
un correo electrnico slo a ellos.
Al igual que con los usuarios, la manera ms sencilla de gestionar los grupos es usando la interfaz de administracin
de Django. Los grupos, en cualquier caso, son modelos Django que residen en el mdulo
django.contrib.auth.models
as que, al igual que en el caso anterior, puedes usar la API de acceso a la base de datos para trabajar con los grupos
a bajo nivel.
12.5.3.
Mensajes
El sistema de mensajes es un forma muy ligera y sencilla de enviarle mensajes a un usuario. Cada usuario tiene
asociada una cola de mensajes, de forma que los mensajes lleguen en el orden en que fueron enviados. Los mensajes
no tienen ni fecha de caducidad ni fecha de envo.
La interfaz de administracin de Django usa los mensajes para noticar que determinadas acciones han podido ser
llevadas a cabo con xito. Por ejemplo, al crear un objeto, vers que aparece un mensaje en lo alto de la pgina de
administracin, indicando que se ha podido crear el objeto sin problemas.
Puedes usar la misma API para enviar o mostrar mensajes en tu propia aplicacin. Las llamadas de la API son
bastante simples:
Para crear un nuevo mensaje usa
user.message_set.create(message='message_text').
En el siguiente ejemplo, la vista salva un mensaje para el usuario despus de crear una lista de reproduccin:
RequestContext, los mensajes del usuario actual, si los tuviera, estn accesibles desde la variable de
{{ messages }}. El siguiente ejemplo representa un fragmento de cdigo que muestras los
{ % if messages %}
<ul>
{ % for message in messages %}
<li>{{ message }}</li>
{ % endfor %}
</ul>
{ % endif %}
12.6. QU SIGUE?
161
RequestContext
llama a
get_and_delete_messages
12.5.4.
Perles
La parte nal de nuestro puzzle consiste en el sistema de perles. Para entender mejor que es este sistema y para
que sirve, veamos primero el problema que se supone tiene que resolver.
El resumen sera este: Muchos sitios en Internet necesitan almacenar ms informacin acerca de sus usuarios de
la que est disponible en un objeto de la clase
User.
de campos extra. Django, por el contrario, ha optado por proporcionar un mecanismo sencillo que permita crear un
perl con los datos que queramos, y que queda enlazado con la cuenta de usuario. Estos perles pueden incluso ser
diferentes segn cada proyecto, y tambin se pueden gestionar diferentes perles para sitios diferentes usando la misma
base de datos.
El primer paso para crear un perl es denir el modelo que va a almacenar la informacin que queremos guardar.
ForeignKey,
user. Aparte de
El nico requerimiento que Django impone a este modelo es que disponga de una campo de tipo
sea nico (unique=True) y que lo vincule con el modelo
User.
que
eso,
puedes usar tantos y tan variados campos de datos como quieres. El siguiente ejemplo muestra un perl absolutamente
arbitrario:
AUTH_PROFILE_MODULE
AUTH_PROFILE_MODULE = "myapp.mysiteprofile"
Una vez hecho esto, se puede acceder al perl del usuario llamando a
una excepcin de tipo
DoesNotExist
user.get_profile().
12.6.
Qu sigue?
Si, la verdad es que el sistema de autorizacin tiene tela que cortar. La mayor parte de las veces no tendrs que
preocuparte por todos los detalles que se describen en este captulo, pero si alguna vez tienes que gestionar interacciones
complicadas con los usuarios, agradecers tener todas las utilidades posibles a mano.
En el
`prximo captulo`_, echaremos un vistazo a una parte de Django que necesita la infraestructura que
proporciona el sistema de usuarios/sesiones de Django: la aplicacin de comentarios. Esta aplicacin permite aadir,
de forma muy sencilla, un completo sistema de comentarios -por parte de usuarios annimos o identicados- a cualquier
tipo de objeto que queramos. Hasta el innito y ms all!
Duplicate explicit target name: prximo captulo.
162
Captulo 13
Cache
Los sitios Web estticos, en las que las pginas son servidas directamente a la Web, generan un gran escalamiento.
Una gran desventaja en los sitios Web dinmicos, es precisamente eso, que son dinmicos. Cada vez que un usuario
pide una pgina, el servidor realiza una serie de clculos--consultas a una base de datos, renderizado de plantillas,
lgica de negocio--para crear la pgina que el visitante nalmente ve. Esto es costoso desde el punto de vista del
sobreprocesamiento.
Para la mayora de las aplicaciones Web, esta sobrecarga no es gran cosa. La mayora de las aplicaciones Web no
son el washingtonpost.com o Slashdot; son de un tamao pequeo a uno mediano, y con poco trco. Pero para los
sitios con trco de medio a alto es esencial bajar lo ms que se pueda el costo de procesamiento. He aqu cuando
realizar un cache es de mucha ayuda.
Colocar en cache algo signica guardar el resultado de un clculo costoso para que no se tenga que realizar el
mismo la prxima vez. Aqu mostramos un pseudocdigo explicando como podra funcionar esto para una pgina Web
dinmica:
Django tambin trabaja muy bien con caches de upstream, tales como Squid (http://www.squid-cache.org/)
y las caches de los navegadores. Estos son los tipos de cache que no controlas directamente pero a las cuales puedes
proveerles algunas pistas (va cabeceras HTTP) acerca de qu partes de tu sitio deben ser colocadas en cache y cmo.
Sigue leyendo para descubrir como usar el sistema de cache de Django. Cuando tu sitio se parezca cada vez ms a
Slashdot, estars contento de entender este material.
13.1.
Activando el Cache
El sistema de cache requiere slo una pequea conguracin. A saber, tendrs que decirle donde vivirn los datos
de tu cache, si es en una base de datos, en el sistema de archivos, o directamente en memoria. Esta es una decisin
importante que afecta el rendimiento de tu cache (si, algunos tipos de cache son ms rpidos que otros). La cache en
memoria generalmente ser mucho ms rpida que la cache en el sistema de archivos o la cache en una base de datos,
porque carece del trabajo de tocar los mismos.
CACHE_BACKEND, Django
disponibles para CACHE_BACKEND.
especicas
usar
usas cache y no
todos los valores
164
13.1.1.
Memcached
Por lejos la ms rpida, el tipo de cache ms eciente para Django, Memcached es un framework de cache enteramen-
com/) y subsecuentemente por Danga Interactive (http://danga.com/). Es usado por sitios como Slashdot y Wikipedia
para reducir el acceso a bases de datos e incrementar el rendimiento dramticamente.
Memcached est libremente disponible en
http://danga.com/memcached/.
una cantidad especca de memoria RAM. Su caracterstica principal es proveer una interfaz--una super-liviana-y-
rpida interfaz--para aadir, obtener y eliminar arbitrariamente datos en la cache. Todos los datos son guardados
directamente en memoria, por lo tanto no existe sobrecarga de uso en una base de datos o en el sistema de archivos.
Despus de haber instalado Memcached, es necesario que instales los bindings Python para Memcached, los cuales
CACHE_BACKEND = 'memcached://127.0.0.1:11211/'
Una muy buena caracterstica de Memcached es su habilidad de compartir la cache en varios servidores. Esto
signica que puedes correr demonios de Memcached en diferentes mquinas, y el programa seguir tratando el grupo
de diferentes mquinas como una sola cache, sin la necesidad de duplicar los valores de la cache en cada mquina. Para
sacar provecho de esta caracterstica con Django, incluye todas las direcciones de los servidores en
CACHE_BACKEND,
CACHE_BACKEND = 'memcached://172.19.26.240:11211;172.19.26.242:11211/'
En el siguiente ejemplo, la cache es compartida en diferentes instancias de Memcached corriendo en las direcciones
IP 172.19.26.240 (puerto 11211), 172.19.126.242 (puerto 11212) y 172.19.26.244 (puerto 11213):
CACHE_BACKEND = 'memcached://172.19.26.240:11211;172.19.26.242:11212;172.19.26.244:11213/'
Una ltima observacin acerca de Memcached es que la cache basada en memoria tiene una importante desventaja.
Como los datos de la cache son guardados en memoria, sern perdidos si los servidores se caen. Ms claramente,
la memoria no es para almacenamiento permanente, por lo tanto no te quedes solamente con una cache basada en
memoria. Sin duda, ninguno de los sistemas de cache de Django debe ser utilizado para almacenamiento permanente-son todos una solucin para la cache, no para almacenamiento--pero hacemos hincapi aqu porque la cache basada
en memoria es particularmente temporaria.
13.1.2.
Para usar una tabla de una base de datos como cache, tienes que crear una tabla en tu base de datos y apuntar el
sistema de cache de Django a ella.
Primero, crea la tabla de cache corriendo el siguiente comando:
[nombre_tabla_cache]
es el nombre de la tabla a crear. Este nombre puede ser cualquiera que desees,
siempre y cuando sea un nombre vlido para una tabla y que no est ya en uso en tu base de datos. Este comando
crea una nica tabla en tu base de datos con un formato apropiado para el sistema de cache de Django.
Una vez que se hayas creado la tabla, coloca la propiedad
nombre_tabla es el nombre
cache es mi_tabla_cache:
CACHE_BACKEND
como
"db://nombre_tabla",
donde
CACHE_BACKEND = 'db://mi_tabla_cache'
El sistema de cache usar la misma base de datos especicada en el archivo de conguracin. No podrs usar un
base de datos diferente para tal.
13.1.3.
165
"file://"
en la propiedad
CACHE_BACKEND,
especicando el directorio en tu sistema de archivos que debera almacenar los datos de la cache.
Por ejemplo, para almacenar los datos de la cache en
/var/tmp/django_cache,
coloca lo siguiente:
CACHE_BACKEND = 'file:///var/tmp/django_cache'
Observa que hay tres barras invertidas en el comienzo del ejemplo anterior. Las primeras dos son para
/var/tmp/django_cache.
aqu:: file://c:/foo/bar.
file://,
como
file://,
La ruta del directorio debe ser absoluta --debe comenzar con la raz de tu sistema de archivos. No importa si colocas
una barra al nal de la misma.
Asegrate que el directorio apuntado por esta propiedad exista y que pueda ser ledo y escrito por el usuario de
sistema uado por tu servidor Web para ejecutarse.
Continuando con el ejemplo anterior, si tu servidor corre como usuario
exista y pueda ser ledo y escrito por el usuario
apache.
Cada valor de la cache ser almacenado como un archivo separado conteniendo los datos de la cache serializados (pickled), usando el mdulo Python
pickle.
13.1.4.
Si quieres la ventaja que otorga la velocidad de la cache en memoria pero no tienes la capacidad de correr Memcached, puedes optar por el cache de memoria-local. Esta cache es por proceso y thread-safe, pero no es tan eciente
como Memcache dada su estrategia de bloqueo simple y reserva de memoria.
Para usarla, coloca
CACHE_BACKEND
como
'locmem:///',
por ejemplo:
CACHE_BACKEND = 'locmem:///'
13.1.5.
'simple:///',
por ejemplo:
CACHE_BACKEND = 'simple:///'
Esta cache apenas guarda los datos en proceso, lo que signica que slo debe ser usada para desarrollo o testing.
13.1.6.
Finalmente, Django incluye una cache dummy que no realiza cache; slo implementa la interfaz de cache sin
realizar ninguna accin.
Esto es til cuando tienes un sitio en produccin que usa mucho cache en varias partes y en un entorno de
desarrollo/prueba en cual no quieres hacer cache. En ese caso, usa
CACHE_BACKEND
como
'dummy:///'
en el archivo
CACHE_BACKEND = 'dummy:///'
Como resultado de esto, tu entorno de desarrollo no usar cache, pero tu entorno de produccin si lo har.
13.1.7.
Argumentos de CACHE_BACKEND
Cada tipo de cache puede recibir argumentos. Estos son dados como una query-string en la propiedad
CACHE_BACKEND.
timeout:
El tiempo de vida por omisin, en segundos, que usar la cache. Este argumento tomar el
max_entries:
nmero mximo de entradas permitidas en la cache a partir del cual los valores ms viejos sern
eliminados. Tomar un valor de 300 si no se lo especica.
166
ms rpido pero al costo de perder ms datos de la cache. Este argumento tomar un valor de 3 si no
se especica.
En este ejemplo,
timeout
se ja en
60:
CACHE_BACKEND = "locmem:///?timeout=60"
En este ejemplo,
timeout
se ja en
30
max_entries
en
400:
CACHE_BACKEND = "locmem:///?timeout=30&max_entries=400"
Tanto los argumentos desconocidos asi como los valores invlidos de argumentos conocidos son ignorados silenciosamente.
13.2.
CACHE_BACKEND,
entero. Esto signica que cada pgina que no tenga parmetros GET o POST ser puesta en cache por un cierto
perodo de tiempo la primera vez que sean pedidas.
Para activar la cache por sitio solamente agrega
MIDDLEWARE_CLASSES,
'django.middleware.cache.CacheMiddleware'
a la propiedad
MIDDLEWARE_CLASSES = (
'django.middleware.cache.CacheMiddleware',
'django.middleware.common.CommonMiddleware',
)
Nota
El
orden
de
MIDDLEWARE_CLASSES
importa.
Mira
la
seccin
Orden
de
MIDDLEWA-
la
misma instalacin Django, coloca esta propiedad como el nombre del sitio, u otra cadena que sea
nica para la instancia de Django, para prevenir colisiones. Usa una cadena vaca si no te interesa.
La cache middleware coloca en cache cada pgina que no tenga parmetros GET o POST. Esto signica que si
un usuario pide una pgina y pasa parmetros GET en la cadena de consulta, o pasa parmetros POST, la cache
middleware no intentar obtener la versin en cache de la pgina. Si intentas usar la cache por sitio ten esto en mente
cuando disees tu aplicacin; no uses URLs con cadena de consulta, por ejemplo, a menos que sea aceptable que tu
aplicacin no coloque en cache esas pginas.
CACHE_MIDDLEWARE_ANONYMOUS_ONLY. Si denes esta caractersTrue, la cache middleware slo colocar en cache pedidos annimos (p.e.: pedidos hechos por un
usuario no logueado). Esta es una manera simple y efectiva de deshabilitar la cache para cualquier pgina de algn usua-
CACHE_MIDDLEWARE_ANONYMOUS_ONLY,
AuthenticationMiddleware y que AuthenticationMiddleware aparezca antes
CacheMiddleware en tus MIDDLEWARE_CLASSES
Finalmente, nota que CacheMiddleware automticamente coloca unos pocos encabezados en cada HttpResponse:
rio especco, como la interfaz de administracin de Django. Ten en cuenta que si usas
debers asegurarte que has activado
de
Coloca el encabezado
Last-Modified
no en cache) es requerida.
Coloca el encabezado
Coloca el encabezado
en
13.3.
167
Una forma ms granular de usar el framework de cache es colocar en cache la salida de las diferentes vistas. Esto
tiene el mismo efecto que la cache por sitio (incluyendo la omisin de colocar en cache los pedidos con parmetros
GET y POST). Se aplica a cualquier vista que tu especiques, en vez de aplicarse al sitio entero.
Haz esto usando un decorador, que es un wrapper de la funcin de la vista que altera su comportamiento para usar la
cache. El decorador de cache por vista es llamado
por ejemplo:
my_view, si tu URLconf
se ve como:
urlpatterns = ('',
(r'^foo/(\d{1,2})/$', my_view),
)
los pedidos a
/foo/1/
y a
13.3.1.
my_view
cache_page
ah mismo. Este enfoque acopla tu vista con el sistema de cache, lo cual no es lo ideal
por varias razones. Por ejemplo, puede que quieras reusar las funciones de la vista en otro sitio sin cache, o puede
que quieras distribuir las vistas a gente que quiera usarlas sin que sean colocadas en la cache. La solucin para estos
problemas es especicar la cache por vista en URLconf en vez de especicarla junto a las vistas mismas.
Hacer eso es muy fcil: simplemente envuelve la funcin de la vista con
urlpatterns = ('',
(r'^foo/(\d{1,2})/$', my_view),
)
Ahora la misma cosa con
my_view
envuelto con
cache_page:
cache_page
dentro de tu URLconf.
168
13.4.
Algunas veces, colocar en cache una pgina entera no te hace ganar mucho y es, de hecho, un inconveniente excesivo.
Quizs, por ejemplo, tu sitio incluye una vista cuyos resultados dependen de diversas consultas costosas, lo resultados de las cuales cambian en intervalos diferentes. En este caso, no sera ideal usar la pgina entera en cache que
la cache por sitio o por vista ofrecen, porque no querrs guardar en cache todo el resultado (ya que los resultados
cambian frecuentemente), pero querrs guardar en cache los resultados que rara vez cambian.
Para casos como este, Django expone una simple API de cache de bajo nivel, la cual vive en el mdulo
django.core.cache.
Puedes usar la API de cache de bajo nivel para almacenar los objetos en la cache con cualquier nivel de granularidad que te guste. Puedes colocar en la cache cualquier objeto Python que pueda ser serializado de forma segura:
strings, diccionarios, listas de objetos del modelo, y dems. (La mayora de los objetos comunes de Python pueden ser
serializados; revisa la documentacin de Python para ms informacin acerca de serializacin). N.T.: pickling
Aqu vemos como importar la API:
get(key):
anteriormente, si no se lo especica.
Si el objeto no existe en la cache, o el sistema de cache no se puede alcanzar,
cache.get()
devuelve
None:
get_many()
cache.get_many().
Si al sistema de cache le es
tocar la cache slo una vez, al contrario de tocar la cache por cada valor.
get_many()
devuelve
un diccionario con todas las key que has pedido que existen en la cache y todava no han expirado:
>>> cache.set('a', 1)
>>> cache.set('b', 2)
>>> cache.set('c', 3)
>>> cache.get_many(['a', 'b', 'c'])
{'a': 1, 'b': 2, 'c': 3}
Si una key no existe o ha expirado, no ser incluida en el diccionario. Lo siguiente es una continuacin del ejemplo
anterior:
>>> cache.delete('a')
cache.delete()
13.5.
169
Caches upstream
Este captulo se ha enfocado en la cache de tus propios datos. Pero existe otro tipo de cache que es muy importante
para los desarrolladores web: la cache realizada por los upstream. Estos son sistemas que colocan en cache pginas an
antes de que estas sean pedidas a tu sitio Web.
Aqu hay algunos ejemplos de caches para upstream:
Tu ISP puede tener en cache algunas pginas, si tu pides una pgina de
http://example.com/,
tu ISP te enviar la pgina sin tener que acceder a example.com directamente. Los responsables
de example.com no tienen idea que esto pasa; el ISP se coloca entre example.com y tu navegador,
manejando todo lo que se reera a cache transparentemente.
Tu sitio en Django puede colocarse detrs de un cache proxy, como Squid Web Proxy Cache (http::
//www.squid-cache.org/),
cada pedido ser controlado por el proxy antes que nada, y ser pasado a tu aplicacin slo si es
necesario.
Tu navegador tambin pone pginas en un cache. Si una pgina Web enva unos encabezados apropiados, tu navegador usar su copia de la cache local para los siguientes pedidos a esa pgina, sin
siquiera hacer nuevamente contacto con la pgina web para ver si esta ha cambiado.
La cache de upstream es un gran benecio, pero puede ser peligroso. El contenido de muchas pginas Web pueden
cambiar segn la autenticacin que se haya realizado u otras variables, y los sistemas basados en almacenar en cache
segn la URL pueden exponer datos incorrectos o delicados a diferentes visitantes de esas pginas.
Por ejemplo, digamos que manejas un sistema de e-mail basado en Web, el contenido de la bandeja de entrada
obviamente depende de que usuario est logueado. Si el ISP hace caching de tu sitio ciegamente, el primer usuario
que ingrese al sistema compartir su bandeja de entrada, que est en cache, con los dems usuarios del sistema. Eso,
denitivamente no es bueno.
Afortunadamente, el protocolo HTTP provee una solucin a este problema. Existen un nmero de encabezados
HTTP que indican a las cache de upstream que diferencien sus contenidos de la cache dependiendo de algunas variables,
y para que algunas pginas particulares no se coloquen en cache. Veremos algunos de estos encabezados en las secciones
que siguen.
13.5.1.
El encabezado
Vary dene cuales encabezados debera tener en cuenta un sistema de cache cuando construye claves
de su cache. Por ejemplo, si el contenido de una pgina Web depende de las preferencias de lenguaje del usuario, se
dice que la pgina vara segn el lenguaje.
Por omisin, el sistema de cache de Django crea sus claves de cache usando la ruta que se ha requerido (p.e.:
"/stories/2005/jun/23/bank_robbed/").
Esto signica que cada pedido a esa URL usar la misma versin de
cache, independientemente de las caractersticas del navegador del cliente, como las cookies o las preferencias del
lenguaje. Sin embargo, si esta pgina produce contenidos diferentes basndose en algunas cabeceras del request--como
las cookies, el lenguaje, o el navegador--necesitars usar el encabezado
depende de esas cosas.
Para hacer esto en Django, usa el decorador
vary_on_headers
Vary
como sigue:
170
vary_on_headers():
@vary_on_headers('User-Agent', 'Cookie')
def my_view(request):
# ...
Esto le dice a la cache de upstream que diferencie ambos, lo que signica que cada combinacin de una cookie y
un navegador obtendr su propio valor en cache. Por ejemplo, un pedido con navegador
valor
foo=bar
Mozilla
Como las variaciones con las cookies son tan comunes existe un decorador
Mozilla
vary_on_cookie.
foo=ham.
@vary_on_cookie
def my_view(request):
# ...
@vary_on_headers('Cookie')
def my_view(request):
# ...
El encabezado que le pasas a
que
"user-agent".
al
Vary header,
por ejemplo:
HttpResponse
13.5.2.
Otro problema con la cache es la privacidad de los datos y donde deberan almacenarse los datos cuando se hace
un vuelco de la cache.
El usuario generalmente se enfrenta con dos tipos de cache: su propia cache de su navegador (una cache privada)
y la cache de su proveedor (una cache pblica). Una cache pblica es usada por mltiples usuarios y controlada por
algunos otros. Esto genera un problema con datos sensibles--no quieres que, por ejemplo, el nmero de tu cuenta
bancaria sea almacenado en una cache pblica. Por lo que las aplicaciones Web necesitan una manera de indicarle a
la cache cuales datos son privados y cuales son pblicos.
La solucin es indicar que la copia en cache de una pgina es privada. Para hacer esto en Django usa el decorador
de vista
cache_control:
171
Especicar si una cache debera comprobar siempre la existencia de nuevas versiones, entregando
unicamente el contenido de la cache cuando no hubiesen cambios. (Algunas caches pueden entregar
contenido aun si la pgina en el servidor ha cambiado, simplemente porque la copia en cache todava
no ha expirado.)
En Django, utiliza el decorador
ejemplo,
cache_control
cache_control
le indica a la cache revalidarse en cada acceso y almacenar versiones en cache hasta 3.600
segundos:
Cache-Control
cache_control().
public=True
private=True
no_cache=True
no_transform=True
must_revalidate=True
proxy_revalidate=True
max_age=num_seconds
s_maxage=num_seconds
Tip
Para una explicacin de las directivas
Cache-Control
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.
Nota
El
middleware
de
caching
ya
ja
el
encabezado
propio
max-age con
de max_age en
el
un
valor
de
decorador
correctamente.
13.6.
Otras optimizaciones
Django incluye otras piezas de middleware que pueden ser de ayuda para optimizar el rendimiento de tus aplicaciones:
django.middleware.http.ConditionalGetMiddleware
ETag
Las-Modified.
django.middleware.gzip.GZipMiddleware comprime las respuestas para todos los navegadores modernos, ahorrando ancho de banda y tiempo de transferencia.
13.7.
Orden de MIDDLEWARE_CLASSES
Si utilizas
porque el middleware de cache necesita conocer los encabezados por los cuales cambiar el almacenamiento en la cache.
Coloca el
CacheMiddleware
SessionMiddleware,
GZipMiddleware,
que agrega
que agrega
Cookie
Accept-Encoding
Vary,
inclu-
172
13.8.
Qu sigue?
Django incluye un nmero de paquetes opcionales. Hemos cubierto algunos de los mismos: el sistema de administracin (Captulo 6) y el marco de sesiones/usuarios (Captulo 11).
El
`prximo captulo`_ cubre el resto de los marcos de trabajos de la comunidad. Existen una cantidad
18 N.
Captulo 14
14.1.
django.contrib.
aislada de funcionalidad para agregar. Estas piezas no estn necesariamente relacionadas, pero algunos sub-paquetes
de
django.contrib
incluyen modelos (y por lo tanto requieren que instales sus tablas en tu base de datos), pero otros consisten solamente
de middleware o de etiquetas de plantillas (template tags ).
La nica caracterstica comn a todos los paquetes de
completo, seguiras pudiendo usar las capacidades fundamentales de Django sin problemas. Cuando los desarrolladores
de Django agregan nueva funcionalidad al framework, emplean esa regla de oro al decidir en dnde va a residir la nueva
funcionalidad, si en
admin:
auth:
comments: una aplicacin para comentarios. Esta aplicacin est actualmente bajo un fuerte desarrollo,
y por lo tanto, no puede ser cubierta por completo para cuando se publique de este libro. Chequea el
sitio web de Django para obtener la ltima informacin sobre esta aplicacin.
contenttypes:
instalado es un tipo de contenido aislado. Este framework es usado internamente por otras aplicaciones
contrib, y est especialmente enfocada a los desarrolladores de Django muy avanzados . Dichos
desarrolladores pueden hallar ms informacin sobre esta aplicacin, leyendo el cdigo fuente que est
en
django/contrib/contenttypes/.
csrf:
Request Forgery (CSRF). Consulta la seccin titulada Proteccin contra CSRF ms adelante.
flatpages:
humanize:
los datos. Consulta la seccin titulada Haciendo los datos ms humanos ms adelante.
markup:
redirects:
ms adelante.
sessions:
174
sitemaps: un framework para generara archivos de mapas de sitio XML. Consulta el Captulo 11.
sites: un framework que te permite operar mltiples sitios web desde la misma base de datos, y con
una nica instalacin de Django. Consulta la prxima seccin, Sites.
syndication:
libro.
14.2.
Sites
El sistema sites de Django es un framework genrico que te permite operar mltiples sitios web desde la misma
base de datos, y desde el mismo proyecto de Django. ste es un concepto abstracto, y puede ser difcil de entender,
as que comenzaremos mostrando algunos escenarios en donde sera til usarlo.
14.2.1.
Como explicamos en el Captulo 1, los sitios LJWorld.com y Lawrence.com, que funcionan gracias a Django, son
operados por la misma organizacin de prensa, el diario Lawrence Journal-World de Lawrence, Kansas. LJWorld.com
se enfoca en noticias, mientras que Lawrence.com se enfoca en el entretenimiento local. Pero a veces los editores quieren
publicar un artculo en ambos sitios.
La forma cabeza dura de resolver el problema sera usar una base de datos para cada sitio, y pedirle a los productores
que publiquen la misma nota dos veces: una para LJWorld.com y nuevamente para Lawrence.com. Pero esto es
ineciente para los productores del sitio, y es redundante conservar mltiples copias de la misma nota en las bases de
datos.
Una solucin mejor? Que ambos sitios usen la misma base de datos de artculos, y que un artculo est asociado
con uno o ms sitios por una relacin de muchos-a-muchos. El framework sites de Django, proporciona la tabla de
base de datos que hace que los artculos se puedan relacionar de esta forma. Sirve para asociar datos con uno o ms
sitios.
14.2.2.
Los dos sitios LJWorld.com y Lawrence.com, tienen la funcionalidad de alertas por correo electrnico, que les
permite a los lectores registrarse para obtener noticaciones. Es bastante bsico: un lector se registra en un formulario
web, e inmediatamente obtiene un correo electrnico que dice Gracias por su suscripcin.
Sera ineciente y redundante implementar el cdigo del procesamiento de registros dos veces, as que los sitios
usan el mismo cdigo detrs de escena. Pero la noticia Gracias por su suscripcin debe ser distinta para cada sitio.
Empleando objetos
variables
name
(ej.
El framework sites te proporciona un lugar para que puedas almacenar el nombre (name) y el dominio (domain)
de cada sitio de tu proyecto, lo que signica que puedes reutilizar estos valores de manera genrica.
14.2.3.
framework sites
Sites ms que un framework, es una serie de convenciones. Toda la cosa se basa en dos conceptos simples:
el modelo
Site,
django.contrib.sites,
SITE_ID especica el ID de la
que se halla en
la opcin de conguracin
domain
name.
Site asociado
y
con
'django.contrib.sites' a tu INSTALLED_APPS.
Ejecuta el comando manage.py syncdb para instalar la tabla django_site en tu base de datos.
Agrega uno o ms objetos Site, por medio del sitio de administracin de Django, o por medio
de la API de Python. Crea un objeto Site para cada sitio/dominio que est respaldado por este
1. Agrega
2.
3.
proyecto Django.
revisin 757 del 28 de julio de 2008
14.2. SITES
175
14.2.4.
Las siguientes secciones describen las cosas que puedes hacer con este framework.
ManyToManyField
hacia
Site
article_detail:
Article
del
SITE_ID.
2.
SITE_ID
asignado a
1,
y que el de
activado, entonces la bsqueda de artculos se limita a aquellos en que la lista de sitios incluye LJWorld.com.
Por ejemplo, si un artculo slo se permite en un sitio, puedes usar un modelo como este:
176
Site (Site.objects)
settings.SITE_ID es
get_current(). El siguiente
segn el valor de
tiene un mtodo
tan usado,
ejemplo es
equivalente al anterior:
django.conf.settings.
name
y a
domain
del objeto
Site
14.2. SITES
177
Una forma an ms exible (aunque un poco ms pesada) de hacer lo mismo, es usando el sistema de plantillas
de Django. Asumiendo que Lawrence.com y LJWorld.com tienen distintos directorios de plantillas (TEMPLATE_DIRS),
puedes simplemente delegarlo al sistema de plantillas as:
subject.txt
message.txt
innecesarias.
get_absolute_url()
muy bien. Pero en en algunos casos puedes querer mostrar la URL completa -- con
http://
y el dominio, y todo --
para un objeto. Para hacerlo, puedes usar el framework sites. Este es un ejemplo:
CurrentSiteManager
Site``s juegan roles importante en tu aplicacin, considera el uso del til ``CurrentSiteManager
en tu modelo (o modelos). Es un administrador de modelos (consulta el Apndice B) que ltra automticamente sus
consultas para incluir slo los objetos asociados al
Usa
CurrentSiteManager
Site
actual.
Photo.objects.all() retorna todos los objetos Photo de la base de datos, pero Photo.on_site.all()
Photo asociados con el sitio actual, de acuerdo a la opcin de conguracin SITE_ID.
Photo.objects.filter(site=settings.SITE_ID)
Photo.on_site.all()
revisin 757 del 28 de julio de 2008
178
CurrentSiteManager cul campo de Photo era el Site? Por defecto busca un campo llamado site. Si
ForeignKey o un campo ManyToManyField llamado de otra forma que site, debes pasarlo
explcitamente como el parmetro para CurrentSiteManager. El modelo a continuacin, que tiene un campo llamado
publish_on, lo demuestra:
Cmo supo
Nota
Probablemente querrs tener un
usas
CurrentSiteManager.
Manager
objects = models.Manager().
Adems, algunas partes de Django -- el sitio de administracin y las vistas genricas -- usan
el manager que haya sido denido primero en el modelo. As que si quieres que el sitio de
administracin tenga acceso a todos los objetos (no slo a los especcos al sitio actual), pon un
objects = models.Manager()
14.2.6.
framework
CurrentSiteManager.
Sites
Si bien no es necesario que uses el framework sites, es extremadamente recomendado, porque Django toma ventaja
de ello en algunos lugares. Incluso si tu instalacin de Django est alimentando a un solo sitio, deberas tomarte unos
segundos para crear el objeto site con tu
domain
name,
SITE_ID.
SITE_ID
actual.
En el framework comments, cada comentario est asociado con un sitio en particular. Cuando un
comentario es posteado, su
con la etiqueta de plantillas apropiada, slo los comentarios del sitio actual son mostrados.
En el framework atpages (consulta la seccin Flatpages ms adelante), cada pgina es asociada
con un sitio en particular. Cuando una pgina es creada, t especicas su
atpage chequea el
SITE_ID
site,
y el middleware de
title
{{ site }},
que es el objeto
Site
actual. Adems, la conexin para proporcionar las URLs de los elementos usan el
objeto
Site
description
domain
dede el
django.contrib.auth.views.login
{{ site_name }}.
14.3.
Site
Flatpages
A menudo tendrs una aplicacin Web impulsada por bases de datos ya funcionando, pero necesitars agregar un
par de pginas estticas, tales como una pgina Acerca de o una pgina de Poltica de Privacidad. Sera posible usar
un servidor Web estndar como por ejemplo Apache para servir ese archivos como archivos HTML planos, pero eso
introduce un nivel extra de complejidad en tu aplicacin, porque entonces tienes que preocuparte de la conguracin
14.3. FLATPAGES
179
de Apache, tienes que preparar el acceso para que tu equipo pueda editar esos archivos, y no puedes sacar provecho
del sistema de plantillas de Django para darle estilo a las pginas.
La solucin a este problema es la aplicacin atpages de Django, la cual reside en el paquete
django.contrib.flatpages.
Esta aplicacin te permite manejar esas pginas aisladas mediante el sitio de administracin de Django, y te permite
especicar plantillas para las mismas usando el sistema de plantillas de Django. Detrs de escena usa modelos Django,
lo que signica que almacena las pginas en una base de datos, de la misma manera que el resto de tus datos, y puedes
acceder a las atpages con la API de bases de datos estndar de Django.
Las atpages son identicadas por su URL y su sitio. Cuando creas una atpage, especicas con cual URL est
asociada, junto con en cul(es) sitio(s) est (para ms informacin acerca de sitios, consulta la seccin Sites).
14.3.1.
Usando atpages
'django.contrib.flatpages'
django.contrib.sites, as
INSTALLED_APPS.
1. Agrega
pendes de
2. Agrega
a tu
INSTALLED_APPS. django.contrib.flatpages
de-
'django.contrib.flatpages.middleware.FlatpageFallbackMiddleware'
MIDDLEWARE_CLASSES.
a tu varia-
ble de conguracin
3. Ejecuta el comando
manage.py syncdb
datos.
La aplicacin atpages crea dos tablas en tu base de datos:
FlatPage,
denido en
django/contrib/flatpages/models.py.
El mismo
se ve as:
title: El ttulo de la atpage. El framework no usa esto para nada en especial. Es tu responsabilidad
visualizarlo en tu plantilla.
content:
El contenido de la atpage (por ej. el HTML de la pgina). El framework no usa esto para
enable_comments:
esto para nada en especial. Puedes comprobar este valor en tu plantilla y mostrar un formulario de
comentario si es necesario.
Indica si se requerir registro para ver esta atpage. Esto se integra con el
sites:
Los sitios en los cuales reside esta atpage. Esto se integra con el framework sites de Django,
180
Puedes crear atpages ya sea a travs de la interfaz de administracin de Django o a travs de la API de base de
datos de Django. Para ms informacin, examina la seccin Agregando, modicando y eliminando atpages.
Una vez que has creado atpages,
FlatpageFallbackMiddleware
cualquier aplicacin Django lanza un error, este middleware verica como ltimo recurso la base de datos de atpages
en bsqueda de la URL que se ha requerido. Especcamente busca una atpage con la URL en cuestin y con un
identicador de sitio que coincida con la variable de conguracin
SITE_ID.
flatpages/default.html
si la atpage no ha
especicado una plantilla personalizada. Le pasa a dicha plantilla una nica variable de contexto:
flatpage,
la cual
Nota
Este middleware slo se activa para errores 404 (pgina no encontrada) -- no para errores 500 (error
MIDDLEWARE_CLASSES es
FlatpageFallbackMiddleware en o cerca del nal
14.3.2.
Va la interfaz de administracin
Si has activado la interfaz automtica de administracin de Django, deberas ver una seccin Flatpages en la
pgina de ndice de la aplicacin admin. Edita las atpages como lo haras con cualquier otro objeto en el sistema.
Va la API Python
Como ya se describi, las atpages se representan mediante un modelo Django estndar que reside en
django/contrib/flatpages
Por lo tanto puede acceder a objetos atpage mediante la API de base de datos Django, por ejemplo:
14.4. REDIRECTS
181
</head>
<body>
{{ flatpage.content }}
</body>
</html>
14.4.
Redirects
El framework redirects de Django te permite administrar las redirecciones con facilidad almacenndolos en una
base de datos y tratndolos como cualquier otro objeto modelo de Django. Por ejemplo puedes usar el framework
redirects para indicarle a Django Redirecciona cualquier peticin de
/music/
/sections/arts/music/..
Esto es
til cuando necesitas cambiar las cosas de lugar en tu sitio; los desarrolladores Web deberan hacer lo que est en sus
manos para evitar los enlaces rotos.
14.4.1.
'django.contrib.redirects'
a tu
INSTALLED_APPS.
'django.contrib.redirects.middleware.RedirectFallbackMiddleware'
MIDDLEWARE_CLASSES.
a tu varia-
ble de conguracin
3. Ejecuta el comando
manage.py syncdb crea una tabla django_redirect en tu base de datos. Esta se trata sencillamente de una tabla
site_id, old_path y new_path.
Puedes crear redirecciones tanto a travs de la interfaz de administracin como a travs de la API de base de datos
de Django. Para ms informacin puedes leer la seccin Agregando, modicando y eliminando redirecciones.
Una vez que has creado redirecciones, la clase
RedirectFallbackMiddleware
vez que cualquier aplicacin Django lanza un error 404, este middleware verica como ltimo recurso la base de datos
old_path provisto
SITE_ID. (para ms informacin acerca de
SITE_ID
y el framework sites, consulta la seccin Sites). Luego entonces realiza los siguientes pasos:
Si encuentra una coincidencia y
Si encuentra una coincidencia y
new_path
new_path
new_path.
cerca del nal de la lista, debido a que se trata de una opcin de ltimo recurso.
Nota
Si usas los middlewares redirect y atpages, analiza cual de los dos (redirect o atpages) desearas sea ejecutado primero. Sugerimos congurar atpages antes que redirects (o sea colocar el
middleware atpages antes que el middleware redirects) pero tu podras decidir lo contrario.
14.4.2.
Va la interfaz de administracin
Si has activado la interfaz automtica de administracin de Django, deberas ver una seccin Redirects en la
pgina de ndice de la aplicacin admin. Edita las redirecciones como lo haras con cualquier otro objeto en el sistema.
182
Va la API Python
Las redirecciones se representan mediante un modelo estndar Django que reside en
django/contrib/redirects/models.py.
Por lo tanto puedes acceder a los objetos redirect va la API de base de datos de Django, por ejemplo:
14.5.
El paquete
django.contrib.csrf
peticiones inter-sitio).
CSRF, tambin conocido como session riding (montado de sesiones) es un exploit de seguridad en sitios Web. Se
presenta cuando un sitio Web malicioso induce a un usuario a cargar sin saberlo una URL desde un sitio al cual dicho
usuario ya se ha autenticado, por lo tanto saca ventaja de su estado autenticado. Inicialmente esto puede ser un poco
difcil de entender as que en esta seccin recorreremos un par de ejemplos.
14.5.1.
oculto en su propia pgina maliciosa. De manera que si ests conectado (logged in ) a tu cuenta de webmail del sitio
example.com
example.com.
Claramente, ser desconectado de un sitio de webmail contra tu voluntad no es un incidente de seguridad aterrorizante, pero este tipo de exploit puede sucederle a cualquier sitio que confa en sus usuarios, tales como un sitio de
un banco o un sitio de comercio electrnico.
14.5.2.
example.com
POST
a la URL
POST confirm
con el valor
'true'.
Bueno, aun con dichas medidas extra de seguridad, este esquema tambin puede ser atacado mediante CSRF -- la
pgina maliciosa slo necesita hacer un poquito ms de trabajo. Los atacantes pueden crear un formulario completo
que enve su peticin a tu sitio, ocultar el mismo en un
<iframe>
14.5.3.
183
Previniendo la CSRF
Entonces, Cmo puede tu sitio defenderse de este exploit?. El primer paso es asegurarse que todas las peticiones
GET
no posean efectos colaterales. De esa forma, si un sitio malicioso incluye una de tus pginas como un
<iframe>,
POST. El segundo paso es dotar a cada <form> que se enviar va POST un campo
oculto cuyo valor sea secreto y sea generado en base al identicador de sesin del usuario. Entonces luego, cuando se
est realizando el procesamiento del formulario en el servidor, comprobar dicho campo secreto y generar un error si
dicha comprobacin no es exitosa.
Esto es precisamente que lo hace la capa de prevencin de CSRF de Django, tal como se explica en la siguiente
seccin.
django.contrib.csrf contiene slo un mdulo: middleware.py. Este mdulo contiene una clase middCsrfMiddleware la cual implementa la proteccin contra CSRF.
Para activar esta proteccion, agrega 'django.contrib.csrf.middleware.CsrfMiddleware' a la variable de conguracin MIDDLEWARE_CLASSES en tu archivo de conguracin. Este middleware necesita procesar la respuesta despus
de SessionMiddleware, as que CsrfMiddleware debe aparecer antes que SessionMiddleware en la lista (esto es
El paquete
leware Django:
debido que el middleware de respuesta es procesado desde atrs hacia adelante). Por otra parte, debe procesar la
CsrfMiddleware debe
MIDDLEWARE_CLASSES ya ests listo. Revisa
respuesta antes que la misma sea comprimida o alterada de alguna otra forma, de manera que
aparecer despus de
GZipMiddleware.
CsrfMiddleware.
1. Modica las respuestas salientes a peticiones agregando un campo de formulario oculto a todos
los formularios
POST,
con el nombre
csrfmiddlewaretoken
y un valor que es un
*hash* del
est presente y tenga un valor correcto. Si no cumple estas condiciones, el usuario recibir un
error
HTTP
POST (y sus correspondientes formulaGET nunca deberan tener efectos colaterales; es tu responsabilidad
POST
que no estn acompaadas de una cookie de sesin no son protegidas simplemente porque no
tiene sentido protegerlas, un sitio Web malicioso podra de todas formas generar ese tipo de peticiones.
Content-Type de la respuesta
application/xml+xhtml.
text/html
antes de
CsrfMiddleware
necesita el framework de sesiones de Django para poder funcionar. (Revisa el Captulo 12 para
obtener ms informacin sobre sesiones). Si ests usando un framework de sesiones o autenticacin personalizado que
maneja en forma manual las cookies de sesin, este middleware no te ser de ayuda.
Si tu aplicacin crea pginas HTML y formularios con algn mtodo inusual (por ej. si enva fragmentos de HTML
document.write), podras estr salteandote el ltro que agrega el campo oculto al formulario.
CsrfMiddleware usa una
agregar el campo csrfmiddlewaretoken a tu HTML antes de que la pgina sea enviada al
en sentencias JavaScript
De presentarse esta situacin, el envo del formulario fallar siempre. (Esto sucede porque
expresin regular para
cliente, y la expresin regular a veces no puede manejar cdigo HTML muy extravagante). Si sospechas que esto
podra estar sucediendo, slo examina el cdigo en tu navegador Web para ver si es que
sido insertado en tu
<form>.
csrfmiddlewaretoken
http://en.wikipedia.org/wiki/CSRF.
ha
184
14.6.
Esta aplicacin aloja un conjunto de ltros de plantilla tiles a la hora de agregar un toque humano a los datos.
14.6.1.
apnumber
Para nmeros entre 1 y 9, este ltro retorna la representacin textual del nmero. Caso contrario retorna el numeral.
Esto cumple con el estilo Associated Press.
Ejemplos:
1 se convierte en uno.
2 se convierte en dos.
10 se convierte en 10.
Puedes pasarle ya sea un entero o una representacin en cadena de un entero.
14.6.2.
intcomma
Este ltro convierte un entero a una cadena conteniendo comas cada tres dgitos.
Ejemplos:
4500 se convierte en 4,500.
45000 se convierte en 45,000.
450000 se convierte en 450,000.
4500000 se convierte en 4,500,000.
Puedes pasarle ya sea un entero o una representacin en cadena de un entero.
14.6.3.
intword
Este ltro convierte un entero grande a una representacin amigable en texto. Funciona mejor con nmeros mayores
a un milln.
Ejemplos:
1000000 se convierte en 1.0 milln.
1200000 se convierte en 1.2 milln.
1200000000 se convierte en 1.2 millardos.
Se admiten valores hasta un billardo (1,000,000,000,000,000).
Puedes pasarle ya sea un entero o una representacin en cadena de un entero.
14.6.4.
ordinal
14.7.
185
Filtros de marcado
textile:
markdown:
textile
{ % load markup %}
{{ object.content|textile }}
django.contrib.markup a tu variable de conguracin INSTALLED_APPS. Una
{ % load markup %} en una plantilla y tendrs acceso a dichos ltros. Para ms detalles
django/contrib/markup/templatetags/markup.py.
14.8.
Qu sigue?
Muchos de estos frameworks contribuidos (CSRF, el sistema de autenticacin, etc.) hacen su magia proveyendo
una pieza de middleware. El middleware es esencialmente cdigo que se ejecuta antes y/o despus de cada peticin y
puede modicar cada peticin y respuesta a voluntad. A continuacin trataremos el middleware incluido con Django
y explicaremos cmo puedes crear el tuyo propio.
186
Captulo 15
Middleware
En ocasiones, necesitars ejecutar una pieza de cdigo en todas las peticiones que maneja Django. ste cdigo
puede necesitar modicar la peticin antes de que la vista se encargue de ella, puede necesitar registrar informacin
sobre la peticin para propsitos de debugging, y as sucesivamente.
Tu puedes hacer esto con el framework middleware de Django, que es un conjunto de acoples dentro del procesamiento de peticin/respuesta de Django. Es un sistema de plug-in liviano y de bajo nivel capaz de alterar de forma
global tanto la entrada como la salida de Django.
Cada componente middleware es responsable de hacer alguna funcin especca. Si estas leyendo este libro de forma
lineal (disculpen, posmodernistas), has visto middleware varias veces ya:
Todas las herramientas de usuario y sesin que vimos en el Captulo 12 son posibles gracias a unas
pequeas piezas de middleware (ms especcamente, el middleware hace que
request.user
request.session
La cache global del sitio discutida en el Captulo 13 es solo una pieza de middleware que desva la
llamada a tu funcin de vista si la respuesta para esa vista ya fue almacenada en la cache.
Todas las aplicaciones contribuidas
flatpages, redirects,
csrf
15.1.
Qu es middleware
Un componente middleware es simplemente una clase Python que se ajusta a una cierta API. Antes de entrar en
los aspectos formales de los que es esa API, miremos un ejemplo muy sencillo.
Sitios de trco alto a menudo necesitan implementar Django detrs de un proxy de balanceo de carga (mira
el Captulo 20). Esto puede causar unas pequeas complicaciones, una de las cuales es que la IP remota de cada
peticin (request.META["REMOTE_IP"]) ser la del balanceador de carga, no la IP real que realiza la peticin. Los
balanceadores de carga manejan esto estableciendo una cabecera especial,
X-Forwarded-For,
request.META["REMOTE_ADDR"]:
class SetRemoteAddrFromForwardedFor(object):
def process_request(self, request):
try:
real_ip = request.META['HTTP_X_FORWARDED_FOR']
except KeyError:
pass
else:
# HTTP_X_FORWARDED_FOR can be a comma-separated list of IPs.
# Take just the first one.
real_ip = real_ip.split(",")[0]
request.META['REMOTE_ADDR'] = real_ip
revisin 757 del 28 de julio de 2008
188
X-Forwarded-For de todas las peticiones ser automtirequest.META['REMOTE_ADDR']. Esto signica que tus aplicaciones Django no necesitan conocer
si estn detrs de un proxy de balanceo de carga o no, pueden simplemente acceder a request.META['REMOTE_ADDR'],
Si esto es instalado (mira la siguiente seccin), el valor de
camente insertado en
en
django.middleware.http,
15.2.
Instalacin de Middleware
Si has ledo este libro completamente hasta aqu, ya has visto varios ejemplos de instalacin de middleware; muchos
de los ejemplos en los captulos previos han requerido cierto middleware. Para completar, a continuacin se muestra
la manera de instalar middleware.
Para activar un componente middleware, agregarlo a la tupla
En
MIDDLEWARE_CLASSES,
django-admin.py startproject:
MIDDLEWARE_CLASSES
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.doc.XViewMiddleware'
)
Una instalacin Django no requiere ningn middleware -- La tupla
quieres -- pero te recomendamos que actives
CommonMiddleware,
MIDDLEWARE_CLASSES
El orden es importante. En las fases de peticin y vista, Django aplica el middleware en el orden que gura en
recorre hacia abajo la lista hasta la vista, y en la respuesta la recorre hacia arriba. Mira la seccin Cmo procesa una
peticin Django: Detalles completos en el Captulo 3 para un repaso de las fases.
15.3.
Mtodos de un Middleware
Ahora que sabes qu es un middleware y cmo instalarlo, echemos un vistazo a todos los mtodos disponibles que
las clases middleware pueden denir.
15.3.1.
Utiliza
Inicializar: __init__(self )
__init__()
para realizar una conguracin a nivel de sistema de una determinada clase middleware.
Por razones de rendimiento, cada clase middleware activada es instanciada slo una vez por proceso servidor. Esto
signica que
__init__()
__init__() es para vericar si el middleware es en realidad nece__init__() emite django.core.exceptions.MiddlewareNotUsed, entonces Django remover el middleware
de la pila de middleware. Tu podras usar esta caracterstica para vericar si existe una pieza de software que la clase
middleware requiere, o vericar si el servidor esta ejecutndose en modo debug, o cualquier otra situacin similar.
Si una clase middleware dene un mtodo
15.3.2.
ste mtodo es llamado tan pronto como la peticin ha sido recibida -- antes de que Django haya analizado
sintcticamente la URL para determinar cul vista ejecutar. Se le pasa el objeto
a tu voluntad.
process_request()
Si devuelve
None,
None
o un objeto
HttpResponse.
y la vista apropiada.
Si devuelve un objeto
HttpResponse,
HttpResponse.
15.3.3.
189
ste mtodo es llamado despus de la llamada al pre-procesador de peticin y despus de que Django haya determinado qu vista ejecutar, pero antes de que sa vista sea realmente ejecutada.
Los argumentos que se pasan a esta vista son mostrados en la Tabla 15-1.
Cuadro 15.1: Argumentos que se pasan a process_view()
Argumento
Explicacin
request
view
El objeto
HttpRequest.
La funcin Python que Django llamar para manejar esta peticin. Este es en
realidad el objeto funcin en s, no el nombre de la funcin como string.
args
kwargs
request
As como el mtodo
Si devuelve
y la vista apropiada.
Si devuelve un objeto
HttpResponse,
15.3.4.
HttpResponse.
ste mtodo es llamado despus de que la funcin de vista es llamada y la respuesta generada. Aqu, el procesador
puede modicar el contenido de una respuesta; un caso de uso obvio es la compresin de contenido, como por ejemplo
la compresin con gzip del HTML de la respuesta.
Los parmetros deben ser bastante auto-explicativos:
request
es el objeto peticin, y
response
es el objeto
None, process_response()
HttpResponse. Esa respuesta puede ser la respuesta original pasada a la funcin (posiblemente
15.3.5.
ste mtodo es llamado slo si ocurre algn error y la vista emite una excepcin sin capturar. Puedes usar este
mtodo para enviar noticaciones de error, volcar informacin postmrtem a un registro, o incluso tratar de recuperarse
del error automticamente.
Los parmetros para esta funcin son el mismo objeto request con el que hemos
exception, el cual es el objeto Exception real emitido por la funcin de vista.
process_exception() debe retornar ya sea None o un objeto HttpResponse.
Si devuelve
None,
porado en el framework.
Si devuelve un objeto
HttpResponse,
incorporado en el framework.
Nota
Django trae incorporado una serie de clases middleware (que se discuten en la seccin siguiente)
que hacen de buenos ejemplos. La lectura de su cdigo debera darte una buena idea de la potencia
del middleware.
Tambin puedes encontrar una serie de ejemplos contribuidos por la comunidad en el wiki de
Django:
http://code.djangoproject.com/wiki/ContributedMiddleware
190
15.4.
Middleware incluido
Django viene con algunos middleware incorporados para lidiar con problemas comunes, los cuales discutiremos en
las secciones que siguen.
15.4.1.
django.contrib.auth.middleware.AuthenticationMiddleware.
request.user, que representa el usuario
todo objeto HttpRequest que se recibe.
Clase middleware:
15.4.2.
Middleware Common
Clase middleware:
django.middleware.common.CommonMiddleware.
import re
DISALLOWED_USER_AGENTS = (
re.compile(r'^OmniExplorer_Bot'),
re.compile(r'^Googlebot')
)
Nota el
import re, ya que DISALLOWED_USER_AGENTS requiere que sus valores sean expresiones regure.compile()). El archivo de conguracin es un archivo
de Python, por lo tanto es perfectamente adecuado incluir sentencias import en l.
APPEND_SLASH
es igual a
True,
misma URL con una barra al nal, a menos que el ltimo componente en el path contenga un punto.
De esta manera
foo.com/bar
es redirigido a
foo.com/bar/,
pero
foo.com/bar/file.txt
es pasado
de forma separada estas URLs, lo cual es perjudicial para la valoracin de tu sitio en el motor de
bsqueda, por lo tanto es una buena prctica normalizar las URLs.
Maneja ETags basado en la conguracin USE_ETAGS : ETags son una optimizacin a nivel HTTP
para almacenar condicionalmente las pginas en la cach. Si
USE_ETAGS
es igual a
True,
Django
calcular una ETag para cada peticin mediante la generacin de un hash MD5 del contenido de la
pgina, y se har cargo de enviar respuestas
Nota tambin que existe un middleware de
15.4.3.
Middleware de compresin
Clase middleware:
django.middleware.gzip.GZipMiddleware.
Este middleware comprime automticamente el contenido para aquellos navegadores que comprenden la compresin
gzip (todos los navegadores modernos). Esto puede reducir mucho la cantidad de ancho de banda que consume un
servidor Web. La desventaja es que esto toma un poco de tiempo de procesamiento para comprimir las pginas.
Nosotros por lo general preferimos velocidad sobre ancho de banda, pero si tu preeres lo contrario, solo habilita
este middleware.
15.5. QU SIGUE?
15.4.4.
191
django.middleware.http.ConditionalGetMiddleware.
GET condicionales. Si la respuesta contiene un encabezado
Last-Modified o ETag, y la peticin contiene If-None-Match o If-Modified-Since, la respuesta es reemplazada
por una respuesta 304 (Not modied). El soporte para ETag depende de la conguracin USE_ETAGS y espera que
el encabezado ETag de la respuesta ya este previamente jado. Como se seal anteriormente, el encabezado ETag es
Clase middleware:
Content-Length
15.4.5.
HEAD
Date
Clase middleware:
django.middleware.http.SetRemoteAddrFromForwardedFor.
Este es el ejemplo que examinamos en la seccin anterior Qu es middleware. Este establece el valor de
request.META['RE
basndose en el valor de
parado detrs de un
127.0.0.1.
Atencin!
HTTP_X_FORWARDED_FOR.
HTTP_X_FORWARDED_FOR automticamente,
no uses este middleware. Cualquiera puede inventar el valor de HTTP_X_FORWARDED_FOR, y ya
que este establece REMOTE_ADDR basndose en HTTP_X_FORWARDED_FOR, signica que cualquiera
Este middleware no hace validar
15.4.6.
HTTP_X_FORWARDED_FOR.
Clase middleware:
django.contrib.sessions.middleware.SessionMiddleware.
Este middleware habilita el soporte para sesiones. Mira el Captulo 12 para ms detalles.
15.4.7.
Clase middleware:
django.middleware.cache.CacheMiddleware.
Este middleware almacena en la cache cada pgina impulsada por Django. Este se analiz en detalle en el Captulo
13.
15.4.8.
Middleware de transaccin
Clase middleware:
django.middleware.transaction.TransactionMiddleware.
COMMIT o ROLLBACK de la base de datos con una fase de peticin/respuesta. Si una vista
con xito, se emite un COMMIT. Si la vista provoca una excepcin, se emite un ROLLBACK.
El orden de este middleware en la pila es importante. Los mdulos middleware que se ejecutan fuera de este, se
ejecutan con commit-on-save -- el comportamiento por omisin de Django. Los mdulos middleware que se ejecutan
dentro de este (prximos al nal de la pila) estarn bajo el mismo control de transaccin que las vistas de funcin.
Mira el Apndice C para obtener ms informacin sobre las transacciones de base de datos.
15.4.9.
Middleware X-View
django.middleware.doc.XViewMiddleware.
X-View personalizadas a peticiones HEAD que provienen de direcciones
IP denidas en la conguracin INTERNAL_IPS. Esto es usado por el sistema automtico de documentacin de Django.
Clase middleware:
15.5.
Qu sigue?
Los desarrolladores Web y los diseadores de esquemas de bases de datos no siempre tienen el lujo de comenzar
desde cero. En el
`prximo captulo`_, vamos a cubrir el modo de integrarse con sistemas existentes, tales como
192
Captulo 16
19 .
16.1.
La capa de base de datos de Django genera esquemas SQL desde cdigo Python -- pero con una base de datos
existente, t ya tienes los esquemas SQL. En tal caso, necesitas crear modelos para tus tablas de la base de datos
existente. Para este propsito, Django incluye una herramienta que puede generar el cdigo del modelo leyendo el diseo
de las tablas de la base de datos. Esta herramienta se llama
manage.py inspectdb.
16.1.1.
Empleo de
La utilidad
inspectdb
inspectdb,
inspectdb
realiza una introspeccin de la base de datos a la que apunta tu archivo de conguracin,
determina una representacin del modelo que usar Django para cada una de tus tablas, e imprime el cdigo Python
del modelo a la salida estndar.
Esta es una gua de un proceso tpico de integracin con una base de datos existente desde cero. Las nicas
suposiciones son que Django esta instalado y tienes una base de datos existente.
1. Crea un proyecto Django ejecutando
mysite/settings.py,
go cules son los parmetros de conexin a tu base de datos y cul es su nombre. Especcamente, provee las conguraciones de
DATABASE_PASSWORD, DATABASE_HOST,
4. Ejecuta el comando
de datos
mirada
estndar de la shell:
194
16.1.2.
Como podras esperar, la introspeccin de la base de datos no es perfecta, y necesitars hacer una pequea limpieza
al cdigo del modelo resultante. Aqu hay algunos apuntes para lidiar con los modelos generados:
1. Cada tabla de la base de datos es convertida en una clase del modelo (es decir, hay un mapeo
de uno-a-uno entre las tablas de la base de datos y las clases del modelo). Esto signica que
tendrs que refactorizar los modelos para tablas con relaciones muchos-a-muchos en objetos
ManyToManyField.
2. Cada modelo generado tiene un atributo para cada campo, incluyendo campos de clave primaria
id.
Sin embargo, recuerda que Django agrega automticamente un campo de clave primaria
id
si un modelo no tiene una clave primaria. Por lo tanto, querrs remover cualquier lnea que se
parezca a sta:
id = models.IntegerField(primary_key=True)
No solo estas lneas son redundantes, sino que pueden causar problemas si tu aplicacin agregar nuevos registros a estas tablas. El comando
si un campo es
type is a guess.'
pass,
'_field' al nombre del atributo y establecer el atributo
del campo (ej., pass, class, o for).
tiene una columna INT llamada for, el modelo generado tendr un
agregar
for_field = models.IntegerField(db_column='for')
inspectdb insertar el comentario Python 'Field renamed because it was a Python reserved
word.' a continuacin del campo.
5. Si tu base de datos contiene tablas que hacen referencia a otras tablas (como la mayora de las
bases de datos lo hacen), tal vez tengas que re-acomodar el orden de los modelos generados, de
manera que los modelos que hacen referencia a otros modelos estn ordenados apropiadamente.
Por ejemplo, si un modelo
esta denido, puedes usar el nombre del modelo, en vez del objeto modelo en s.
6.
inspectdb detecta claves primarias para PostgreSQL, MySQL y SQLite. Es decir, inserta primary_key=True
primary_key=True para
al menos un campo en cada modelo, ya que los modelos Django requieren tener un campo
primary_key=True.
7. La deteccin de claves forneas slo funciona con PostgreSQL y con ciertos tipos de tablas
MySQL. En otros casos, los campos de clave fornea sern generados como campos
asumiendo que la columna de clave fornea fue una columna
16.2.
INT.
IntegerField,
Es posible integrar Django con un sistema de autenticacin existente -- otra fuente de nombres de usuario y
contraseas o mtodos de autenticacin.
Por ejemplo, tu compaa ya puede tener una conguracin LDAP que almacena un nombre de usuario y contrasea
para cada empleado. Sera una molestia tanto para el administrador de red como para los usuarios, si cada uno de
ellos tiene cuentas separadas en LDAP y en las aplicaciones basadas en Django.
Para manejar situaciones como sta, el sistema de autenticacin de Django te permite conectarte con otras fuentes
de autenticacin. Puedes anular el esquema por omisin de Django basado en base de datos, o puedes usar el sistema
por omisin en conjunto con otros sistemas.
revisin 757 del 28 de julio de 2008
16.2.1.
195
Detrs de escena, Django mantiene una lista de back-ends de autenticacin que utiliza para autenticar. Cuando
alguien llama a
ticar usando todos sus back-ends de autenticacin. Si el primer mtodo de autenticacin falla, Django intenta con
el segundo, y as sucesivamente, hasta que todos los back-ends han sido intentados.
La lista de back-ends de autenticacin a usar se especica en la conguracin
AUTHENTICATION_BACKENDS.
sta
debe ser una tupla de nombres de ruta Python que apuntan a clases que saben cmo autenticar. Estas clases pueden
estar en cualquier lugar de tu ruta Python
Por omisin,
20 .
AUTHENTICATION_BACKENDS
contiene lo siguiente:
('django.contrib.auth.backends.ModelBackend',)
Ese es el esquema bsico de autenticacin que verica la base de datos de usuarios de Django.
El orden de
AUTHENTICATION_BACKENDS se tiene en cuenta, por lo que si el mismo usuario y contrasea son vlidos
16.2.2.
get_user(id) y authenticate(**credentials).
get_user recibe un id -- el cual podra ser un nombre de usuario, un ID de la base de datos o cualquier
cosa -- y devuelve un objeto User.
El mtodo authenticate recibe credenciales como argumentos de palabras clave. La mayora de las veces se parece
Un back-end de autenticacin es un clase que implementa dos mtodos:
El mtodo
a esto:
class MyBackend(object):
def authenticate(self, username=None, password=None):
# Check the username/password and return a User.
Pero podra tambien autenticar un token, como se muestra a continuacin:
class MyBackend(object):
def authenticate(self, token=None):
# Check the token and return a User.
authenticate debe vericar las credenciales que recibe, y debe retornar un objeto User que
None.
El sistema de administracin de Django esta altamente acoplado a su propio objeto User respaldado por base de
datos descripto en el Captulo 12. La mejor manera de lidiar con esto es crear un objeto User de Django para cada
De cualquier manera,
coincide con esas credenciales, si las credenciales son vlidas. Si no son vlidas, debe retornar
usuario que existe en tu back-end (ej., en tu directorio LDAP, tu base de datos SQL externa, etc.). De cualquier manera
puedes escribir un script para hacer esto por adelantado o tu mtodo de autenticacin puede hacerlo la primera vez
que el usuario ingresa al sistema.
Aqu est un ejemplo de back-end que autentica contra unas variables de usuario y contrasea denidas en tu
archivo
settings.py
y crea un objeto
User
196
user = User.objects.get(username=username)
except User.DoesNotExist:
# Create a new user. Note that we can set password
# to anything, because it won't be checked; the password
# from settings.py will.
user = User(username=username, password='get from settings.py')
user.is_staff = True
user.is_superuser = True
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None
16.3.
Es posible ejecutar una aplicacin Django en el mismo servidor de una aplicacin impulsada por otra tecnologa. La manera ms directa de hacer esto es usar el archivo de conguracin de Apache,
httpd.conf,
para delegar
patrones de URL diferentes a distintas tecnologas (Nota que el Captulo 20 cubre el despliegue con Django en Apache/mod_python, por lo tanto tal vez valga la pena leer ese captulo primero antes de intentar esta integracin).
La clave est en que Django ser activado para un patrn particular de URL slo si tu archivo
httpd.conf lo dice.
El despliegue por omisin explicado en el Captulo 20 asume que quieres que Django impulse todas las pginas en un
dominio particular:
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>
Aqu, la lnea
<Location "/">
<Location>
tienes una aplicacin PHP existente que impulsa la mayora de las pginas en un dominio y quieres instalar el sitio de
administracin de Django en
a
/admin/:
/admin/ sin afectar el cdigo PHP. Para hacer esto, slo congura la directiva <Location>
<Location "/admin/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
PythonDebug On
</Location>
Con esto en su lugar, slo las URLs que comiencen con
/admin/
16.4.
Qu sigue?
Hablando del sitio de administracin de Django y sobre cmo acomodar el framework para encajar con necesidades
existentes, otra tarea comn es personalizar el sitio de administracin de Django. El
en dicha personalizacin.
revisin 757 del 28 de julio de 2008
16.4. QU SIGUE?
197
19 N.
20 N.
del T.: del ingls legacy databases and applications, aplicaciones y base de datos que ya estn en uso en entornos de produccin.
del T.: del ingls Python path.
198
Captulo 17
Inspeccionar modelos de datos : La primer cosa que hacemos cuando hemos denido un nuevo
modelo es llamarlo desde la interfaz de administracin e ingresar algunos datos de relleno.
Esto es usual para encontrar errores de modelado; tener una una interfaz grca al modelo
revela problemas rpidamente.
Gestin de datos adquiridos : Hay una pequea entrada de datos asociada a un sitio como
http://chicagocrime.org,
automtica. No obstante, cuando surgen problemas con los datos automticos, es til poder
entrar y editarlos fcilmente.
200
La interfaz de administracin de Django maneja estos casos comunes con algunas o ninguna personalizacin.
Aunque, como sucede con la mayora de las generalizaciones en el diseo, la gestin unicada de todos estos casos
signica que la interfaz no maneja igual de bien otros modos de edicin.
Hablaremos de estos casos para los que la interfaz de administracin de Django no est diseada un poquito ms
adelante, pero primero, vayamos a una breve disgrecin para una discusin losca.
17.1.
En su ncleo, la interfaz de administracin de Django est diseada para una sola actividad:
Usuarios conables editando contenido estructurado.
S, es extremadamente simple -- pero esa simplicidad se basa en un montn de asunciones importantes. La entera
losofa de la interfaz de administracin de Django sigue directamente estas a asunciones , as que vamos a cavar sobre
el subtexto de esta frase en la secciones que siguen.
17.1.1.
La intefaz de administracin est diseada para ser usada por usuarios en lo que t, el desarrollador, confas. Esto
no signica slo gente que ha sido autenticada; signica que Django asume que se puede conar que tus editores de
contenido harn las cosas correctas.
Signica adems que no hay procesos de aprobacin para la edicin de contenido -- si conas en tus usuarios,
nadie necesita aprobar sus ediciones. Otra implicancia es que el sistema de permisos, aunque poderoso, no permite (al
momento en el que se escribe esto) limitar accesos basados en objetos especcos. Si conas en que alguien edite sus
propias historias, conas en que ese usuario no edite las historias de cualquier otro sin permiso.
17.1.2.
El propsito primario de la interfaz de administracin de Django es dejar que la gente edite informacin. Esto
parece obvio al principio, pero de nuevo tiene poderosas y profundas repercusiones.
Por ejemplo, aunque la interfaz es bastante util para revisar datos (segn se ha descripto=, no est diseada con
este propsito en mente. Por caso, nota la ausencia de un permiso puede ver (ve el Captulo 12). Django asume que
si la gente puede ver el contenido en la interfaz de administrain, entonces tambien tienen permito editarlo.
Otra cosa ms importante es la ausencia de cualquier cosa que se aproxime remotamente a un ujo de trabajo.
Si una tarea dada requiere una serie de pasos, no existe algo que permita forzar a que estos pasos se realicen en un
determinado orden. La interfaz se concentra en editar, no en actividades alrededor de la edicin. Esta supresin de un
ujo de trabajo tambien proviene del principio de conanza: la losofa de la interfaz es que este ujo es una decisin
personal, no algo que se pueda implementar en cdigo.
Finalmente, nota la ausencia de agregaciones en la interfaz. Esto es, no existe la infraestructura necesaria para
mostrar totales, promedios y esas cosas. De nuevo, la interfaz es para editar -- y se espera que escribas tus vistas
personalizadas para todo el resto.
17.1.3.
Como el resto de Django, la interfaz preere que trabajes con datos estructurados. Esto es porque slo sirve para
editar informacin almacenada en modelos de Django; para cualquier otra cosa, como datos almacenados en archivos,
necesitars vistas propias.
17.1.4.
Parada Completa
A esta altura debera estar claro que la interfaz de administracin de Django no intenta ser todas las cosas para
toda la gente; y en cambio, elegimos enfocarnos en una cosa y hacerla extremadamente bien.
Cuando se va a extender la interfaz de administracin, mucha de esa misma losofa se sostiene (nota que extensibilidad no gura de nuestros objetivos). Debido a que vistas personalizadas pueden hacer cualquier cosa, y debido
a que estas puede ser visualmente integradas a la interfaz de administracin muy facilmente (como se describe en la
siguiente seccin), las posibilidades de personalizacin incorporadas estn un poco limitadas por diseo.
Deberas tener en mente que la interfaz de administracin es slo una aplicacin; y aunque sea una muy compleja,
no hace nada que cualquier desarrollador Django con suciente tiempo no podra reproducir. Es enteramente posible
201
que en el futuro alguien desarrolle una interfaz de adminitracin diferente que est basada en un conjunto de asunciones
distintas y que por lo tanto se comportar de otra manera.
Finalmente, debemos destacar que, a la fecha que escribimos esto, los desarrolladores de Django trabajaban en una
nueva versin de la interfaz de administracin que permite mucha ms exibilidad y personalizacin. Para el momento
en que leas esto, esas nuevas caracteristicas pudieron haberse incorporado a la distribucin de Django ocial. Para
averiguar al respecto, preguntale a alguien de la comunidad Django si la rama newforms-admin ha sido integrada.
17.2.
Como sale de fbrica, Django provee un nmero de herramientas para personalizar las plantillas de la interfaz que
vienen integradas, las cuales veremos pronto, pero para las tareas detrs de ellas (por ejemplo, cualquier cosa que
requiera un ujo de trabajo especco o permisos granulares), necesitars leer la seccin titulada Creando Vistas de
administracin personalizadas, ms adelante en este captulo.
Para ahora, miremos algunas maneras rpidas de modicar el aspecto (y, en cierto grado, el comportamiento) de la
interfaz de administracin. El Captulo 6 cubre algunas de las tareas ms comunes: cambiar la marca de la interfaz
de adminitracin (para todos esos Jefes Pelopunta que odian el azul) y proveer un formulario de administracin
personalizado.
Pasado ese punto, el objetivo usualmente implica cambiar alguna de las plantillas para un item en particular. Cada
vista de administracin -- las listas de cambio, los formularios de edicin, las pginas de conrmacin de eliminacin
y vistas de historial -- tienen una plantilla asociada que puede ser reescrita de diferentes maneras.
Primero, puedes reescribir la plantilla globalmente. La vista de administracin busca plantillas utilizando el mecanismo de carga de plantillas estndar, por lo que si creas tus plantillas en alguno de los directorios declarados para tal
n, Django cargar esas en vez de las vienen por defecto. Estas plantillas globales se describen el la Tabla 17-1.
Cuadro 17.1: Plantillas globales de la interfaz de administracin
Vista
admin/change_list.html
admin/change_form.html
admin/delete_confirmation.html
admin/object_history.html
Lista de cambios
Formulario para agregar/editar
Conrmacin de eliminacin
Historial de un objeto
La mayora de las veces, sin embargo, querrs cambiar la plantilla slo para un nico objeto o aplicacin (no
globalmente). As, cada vista busca primero plantillas para modelos y aplicaciones especcas, en el siguiente orden:
admin/<aplicacin>/<nombre_objeto>/<plantilla>.html
admin/<aplicacin>/<plantilla>.html
admin/<plantilla>.html
Por ejemplo, la vista del formulario de agregar/editar para un modelo
en este orden:
admin/libros/libro/change_form.html
admin/libros/change_form.html
admin/change_form.html
17.2.1.
La mayora de las veces, y querrs usar la primer plantilla para crear una basada destinada a un modelo especco.
Usualmente la mejor forma de realizar esto es extendiendo y agregando informacin a uno de los bloques denidos en
la plantilla que se est modicando.
Por ejemplo, supongamos que queremos agregar un pequeo texto de ayuda en la cabecera de nuestra pgina de
libros. Quizas algo parecido a lo que muestra la Figura 17-1.
Esta es una manera muy fcil de hacerlo: simplemente crea una plantilla llamada
e inserta este cdigo:
admin/libreria/libro/change_form.ht
202
203
{ % extends "admin/change_form.html" %}
{ % block form_top %}
<p>Inserta un mensaje de ayuda significativo aqu...</p>
{ % endblock %}
Todas esta plantillas denen un nmero de bloques que puedes sobreescribir. Como con la mayora de los programas,
la mejor documentacin es el propio cdigo, por lo que te animamos a mirar las plantillas originales (que se encuentran
en
django/contrib/admin/templates/)
17.2.2.
JavaScript Personalizado
<head>.
el
{ % extends "admin/object_history.html" %}
{ % block extrahead %}
<script src="http://media.ejemplo.com/javascript/jquery.js" type="text/javascript"></script>
<script type="text/javascript">
// el cdigo que utiliza jQuery ira aqu...
</script>
{ % endblock %}
Nota
No estamos seguros porqu necesitaras jQuery en la pgina de historia de objetos, pero, por
supuesto, este ejemplo es vlido para cualquier plantilla de la interfaz de administracin.
Puedes usar esta tcnica para incluir cualquier tipo de controladores JavaScript que puedas necesitar en tus formularios.
17.3.
Hasta ahora, cualquiera que haya buscando agregar comportamientos personalizados a la interfaz de administracin
probablemente est un poco frustrado. Todo lo que han dicho es cmo cambiar la interfaz visualmente , los escuchamos
llorar. Pero como puedo cambiar la forma en que la interfaz de administracin funciona ?
La primer cosa para entender es que esto no es mgico. Esto es, nada de lo que la interfaz hace es especial de manera
alguna -- ya que se trata simplemente de un conjunto de vistas (que se encuentran en
django.contrib.admin.views)
(r'^admin/libros/reporte/$', 'misitio.libros.admin_views.reporte'),
antes de la lnea que incluye las vistas del administrador. Un esqueletos del URLconf puede parecerse a algo as:
204
urlpatterns = patterns('',
(r'^admin/libreria/reporte/$', 'libreria.admin_views.reporte'),
(r'^admin/', include('django.contrib.admin.urls')),
)
Por qu ponemos la vista personalizada antes de incluir las del administrador? Recuerda que Django procesa los
patrones de URL en orden. La inclusin de los patrones de urls del administrador coincide con casi cualquier cosa que
llega a su punto de inclusin, por lo que si invertimos el orden de esas lineas, Django encontrar una vista por omisin
para ese patrn y no funcionar como queremos. En este caso particular, intentar cargar un un lista de cambios para
un modelo Reporte en la aplicacin libros, que no existe.
Ahora escribamos nuestra vista. Para hacer honor a la simplicidad, slo cargaremos todos los libros dentro del
contexto, y dejaremos que la plantilla maneje el agrupamiento con la etiqueta
books/admin_views.py,
from
from
from
from
{ % regroup %}.
Crea un archivo
def reporte(request):
return render_to_response(
"admin/libros/reporte.html",
{'lista_libros' : Book.objects.all()},
RequestContext(request, {}),
)
reporte = staff_member_required(reporte)
Debido a que dejamos el agrupamiento a la plantilla, esta vista es bastante simple. Sin embargo, hay algunos
fragmentos sutiles dignos de explicitar:
Usamos el decorador
es similar a
el usuario est marcado como un mientro del sta , y tenga en consecuencia acceso a la interfaz de
administracin
Este decorador protege todos las vistas predenidas del administrador, y hace que la lgica de autenticacin para tus vistas coincida con la del resto de la interfaz.
Renderizamos una plantilla que se encuntra bajo
admin/.
se considera una buena practica para mantener todas tus plantillas de administracin agrupadas en
un directorio
Esto asegura que la informacin sobre el usuario en curso est disponible para la plantilla.
Mira el
RequestContext.
Finalmente, haremos una plantilla para esta vista. Extenderemos una plantilla de la administracin para que lograr
que nuestra vista coincida visualmente con el resto de la interfaz:
{ % extends "admin/base_site.html" %}
{ % block title %}Lista de libros por editor{ % endblock %}
{ % block content %}
<div id="content-main">
<h1>Lista de libros por editor:</h1>
{ % regroup lista_libros|dictsort:"editor.nombre" by editor as libros_por_editor %}
{ % for editor in libros_por_editor %}
<h3>{{ editor.grouper }}</h3>
<ul>
{ % for libro in editor.list|dictsort:"titulo" %}
revisin 757 del 28 de julio de 2008
205
admin/base_site.html,
17.4.
Algunas veces las vistas de administracin por omisin simplemente no te sirven. Fcilmente puedes reemplazarlas
por las tuyas propias en cualquier etapa de la interfaz de administracin; simplemente haz que tu URL haga sombra*
sobre la que incorporada. Es decir, si tu vista viene antes que la vista incorporada de la aplicacin en URLconf, tu
vista ser invocada por sobre la de omisin.
Por ejemplo, podriamos reemplazar la vista incorporada para crear libros con un formulario que permita a los
usuarios ingresar simplemente un cdigo ISBN. Luego podriamos buscar la informacin del libro desde
http://isbn.nu
(r'^admin/libreria/libro/add/$', 'misitio.libros.admin_views.agregar_por_isbn'),
Si esta linea aparece antes que las URLs de administracion en tu URLconf, la vista
agregar_por_isbn reemplazar
17.5.
Qu sigue?
Si tu idioma nativo es el ingls --cosa que gracias a los traductores ya no es necesaria para leer este libro-- quizas
no te hayas enterado de una las ms fantsticas caractersticas de la interfaz de administracion: est disponible en
casi 40 idiomas distintos! Esto es posible gracias al framework de internacionalizacin de Django (y el duro trabajo de
los traductores voluntarios de Django). El
`prximo captulo`_ explaya como usar este framework para crear sitios
Django localizados.
Avanti!
Duplicate explicit target name: prximo captulo.
206
Captulo 18
Internacionalizacin
Django fue originalmente desarrollado exactamente en el medio de los Estados Unidos (literalmente; Lawrence,
Kansas, se halla a menos de 40 millas del centro geogrco de la porcin continental de los Estados Unidos). Como la
mayora de los proyectos open source, sin embargo, la comunidad de Django creci hasta incluir gente de todo el globo.
A medida que la comunidad fue tornndose ms diversa, la internacionalizacin y la localizacin fueron tomando una
importancia creciente. Debido a que muchos desarrolladores tienen, en el mejor de los casos, una comprensin difusa
de dichos trminos vamos a denirlos brevemente.
Internacionalizacin se reere al proceso de diseo de programas para el uso potencial de cualquier *locale*
Esto incluye el marcado del texto (tales como elementos de la interfaz con el usuario o mensajes de error) para su
futura traduccin, la abstraccin de la visualizacin de fechas y horarios de manera que sea posible respetar diferentes
estndares locales, la provisin de lo necesario para admitir diferentes zonas horarias, y en general el asegurarse
de que el cdigo no contenga ninguna suposicin acerca de la ubicacin de sus usuarios. Encontrars a menudo
internacionalizacin abreviada como I18N (el nmero 18 se reere al nmero de letras omitidos entre la I inicial y
la N nal).
Localizacin se reere al proceso especco de traducir un programa internacionalizado para su uso en un *locale*
particular. Encontrars a menudo localizacin abreviada como L10N.
Django en si est totalmente internacionalizado; todas las cadenas estn marcadas para su traduccin, y existen
variables de conguracin que controlan la visualizacin de valores dependientes del
Django tambin incluye ms de 40 archivos de localizacin. Si no hablas ingls en forma nativa, existe una buena
probabilidad de que Django ya se encuentre traducido a tu idioma nativo.
El mismo framework de internacionalizacin usado para esas localizaciones est disponible para que lo uses en tu
propio cdigo y plantillas.
En resumen, necesitars agregar una cantidad mnima de *hooks* a tu cdigo Python y a tus plantillas. Esos
*hooks* reciben el nombre de cadenas de traduccin. Los mismos le indican a Django Este texto debe ser traducido
al idioma del usuario nal si existe una traduccin a dicho idioma de ese texto.
Django se encarga de usar esos
*hooks* para traducir las aplicaciones Web al vuelo de acuerdo a las preferencias
Nota
gettext/)
208
en un pequeo
False
en tu archivo de conguracin. Si
USE_I18N
tiene el valor
False
Django implementar
'django.core.context_processors.i18n' de tu vaTEMPLATE_CONTEXT_PROCESSORS.
18.1.
Las cadenas de traduccin especican Este texto debera ser traducido. dichas cadenas pueden aparecer en tu
cdigo Python y en tus plantillas. Es t responsabilidad marcar las cadenas traducibles; el sistema slo puede traducir
cadenas sobre las que est al tanto.
18.1.1.
_().
bajo). Esta funcin est disponible globalmente (o sea como un componente incluido); no es necesario que lo importes.
En este ejemplo, el texto
"Welcome to my site."
def my_view(request):
output = _("Welcome to my site.")
return HttpResponse(output)
La funcin
django.utils.translation.gettext()
es idntica a
_().
_(),
La traduccin funciona tambin sobre valores computados. Este ejemplo es idntico a los dos anteriores:
def my_view(request):
words = ['Welcome', 'to', 'my', 'site.']
output = _(' '.join(words))
return HttpResponse(output)
La traduccin funciona tambin sobre variables. De nuevo, este es otro ejemplo idntico:
def my_view(request):
sentence = 'Welcome to my site.'
output = _(sentence)
return HttpResponse(output)
(algo a tener en cuenta cuando se usan variables o valores computados, como se vea en los dos ejemplos previos,
es que la utilidad de deteccin de cadenas de traduccin de Django,
make-messages ms adelante).
pasas a _() o gettext() pueden contener
make-messages.py,
cados con la sintaxis estndar de interpolacin de cadenas con nombres, por ejemplo:
Me llamo Adrian,
con el marcador de posicin (el nombre) ubicado a continuacin del texto traducido y
Por esta razn, deberas usar interpolacin de cadenas con nombres (por ejemplo %(name)s) en lugar de interpola-
cin posicional (por ejemplo %s o %d). Si usas interpolacin posicional las traducciones no sern capaces de reordenar
el texto de los marcadores de posicin.
revisin 757 del 28 de julio de 2008
18.1.2.
209
Usa la funcin
django.utils.translation.gettext_noop()
duccin sin realmente traducirla en ese momento. Las cadenas as marcadas no son traducidas sino hasta el ltimo
momento que sea posible.
Usa este enfoque si deseas tener cadenas constantes que deben ser almacenadas en el idioma original -- tales como
cadenas en una base de datos -- pero que deben ser traducidas en el ltimo momento posible, por ejemplo cuando la
cadena es presentada al usuario.
18.1.3.
Traduccin perezosa
Usa la funcin
-- cuando
La traduccin en si misma se llevar a cabo cuando sea usada en un contexto de cadena, tal como el renderizado de
una plantilla en el sitio de administracin de Django.
Si no te gusta el nombre largo
gettext_lazy
la siguiente forma:
verbose_name
verbose_name_plural
Meta:
Pluralizacin
Usa la funcin
django.utils.translation.ngettext()
tiene tres argumentos: la cadena de traduccin singular, la cadena de traduccin plural y el nmero de
count).
210
18.2.
Las traducciones en las plantillas Django usan dos etiquetas de plantilla y una sintaxis ligeramente diferente a la
del cdigo Python. Para que tus plantillas puedan acceder a esas etiquetas coloca
plantilla.
La etiqueta de plantilla
{ % trans %}
noop:
{ % trans %}
comillas simples o dobles. Si tu traduccin requiere variables (marcadores de posicin) puedes usar por ejemplo
blocktrans %}:
{%
blocktrans,
and:
{ % blocktrans %}
{ % endblocktrans %},
{ % plural %}
la cual aparece
por ejemplo:
RequestContext
(ver
gettext/ngettext.
`Captulo 10`_), tus plantillas tienen acceso a tres variables especcas rela-
{{ LANGUAGES }}
{{ LANGUAGE_CODE }} es el idioma preferido del usuario actual, expresado como una cadena (por
ejemplo en-us). (Consulta la seccin Cmo descubre Django la preferencia de idioma para informacin adicional).
{%
{%
{%
{%
load i18n %}
get_current_language as LANGUAGE_CODE %}
get_available_languages as LANGUAGES %}
get_current_language_bidi as LANGUAGE_BIDI %}
Tambin existen
plantilla que acepte cadenas constantes. En dichos casos basta con que uses la sintaxis
antes de ser pasada a las funciones de manejo de etiquetas), de manera que no necesitan estar preparadas para manejar
traduccin.
revisin 757 del 28 de julio de 2008
18.3.
211
Una vez que hayas etiquetado tus cadenas para su posterior traduccin, necesitas escribir (u obtener) las traducciones propiamente dichas. En esta seccin explicaremos como es que eso funciona.
18.3.1.
El primer paso es crear un archivo de mensajes para un nuevo idioma. Un archivo de mensajes es un archivo de
texto comn que representa un nico idioma que contiene todas las cadenas de traduccin disponibles y cmo deben
ser representadas las mismas en el idioma en cuestin. Los archivos de mensajes tiene una extensin
Django incluye una herramienta,
bin/make-messages,
.po.
archivos.
Para crear o actualizar un archivo de mensajes, ejecuta este comando:
bin/make-messages.py -l de
de es el cdigo de idioma para el archivo de mensajes que deseas crear. El cdigo de idioma en este caso est
pt_BR para portugus de Brasil y de_AT para alemn de Austria. Echa
un vistazo a los cdigos de idioma en el directorio django/conf/locale/ para ver cuales son los idiomas actualmente
donde
$PYTHONPATH
django (no una copia de trabajo de Subversion, sino el que se halla referenciado por
conf/locale/de/LC_MESSAGES/django.po.
conf/locale.
En el ejemplo
de,
el archivo ser
Si es ejecutado sobre el rbol de tu proyecto o tu aplicacin, har lo mismo pero la ubicacin del directorio locale es
locale/LANG/LC_MESSAGES (nota que no tiene un prejo conf). La primera vez que lo ejecutes en tu rbol necesitars
crear el directorio locale.
Sin gettext?
Si no tienes instaladas las utilidades
gettext, make-messages.py
encuentras ante esa situacin debes o instalar dichas utilidades o simplemente copiar el archivo
de mensajes de ingls (conf/locale/en/LC_MESSAGES/django.po) y usar el mismo como un
punto de partida; se trata simplemente de un archivo de traduccin vaco.
El formato de los archivos
.po
.po
como la informacin de contacto de quines mantienen la traduccin, pero el grueso del archivo es una lista de mensajes
-- mapeos simples entre las cadenas de traduccin y las traducciones al idioma en cuestin propiamente dichas.
Por ejemplo, si tu aplicacin Django contiene una cadena de traduccin para el texto
Welcome to my site:
_("Welcome to my site.")
entonces
make-messages.py
.po
#: path/to/python/module.py:23
msgid "Welcome to my site."
msgstr ""
Es necesaria una rpida explicacin:
de manera
que es tu responsabilidad el cambiar esto. Asegrate de que mantienes las comillas alrededor de tu
traduccin.
Por conveniencia, cada mensaje incluye el nombre del archivo y el nmero de lnea desde el cual la
cadena de traduccin fue extrada.
revisin 757 del 28 de julio de 2008
212
Los mensajes largos son un caso especial. La primera cadena inmediatamente a continuacin de
msgstr
(o
msgid)
es una cadena vaca. El contenido en si mismo se encontrar en las prximas lneas con el formato de una cadena por
lnea. Dichas cadenas se concatenan en forma directa. No olvides los espacios al nal de las cadenas; en caso contrario
todas sern agrupadas sin espacios entre las mismas!.
Por ejemplo, a continuacin vemos una traduccin de mltiples lneas (extrada de la localizacin al espaol incluida
con Django):
msgid ""
"There's been an error. It's been reported to the site administrators via e-"
"mail and should be fixed shortly. Thanks for your patience."
msgstr ""
"Ha ocurrido un error. Se ha informado a los administradores del sitio "
"mediante correo electrnico y debera arreglarse en breve. Gracias por su "
"paciencia."
Notar los espacios nales.
.po
"CHARSET")
para editar el contenido. Generalmente, UTF-8 debera funcionar para la mayora de los idiomas
pero
gettext
Para reexaminar todo el cdigo fuente y las plantillas en bsqueda de nuevas cadenas de traduccin y actualizar
todos los archivos de mensajes para todos los idiomas, ejecuta lo siguiente:
make-messages.py -a
18.3.2.
Luego de que has creado tu archivo de mensajes, y cada vez que realices cambios sobre el mismo necesitars
compilarlo a una forma ms eciente, segn los usa
Esta herramienta recorre todos los archivos
optimizados para su uso por parte de
compile-messages.py
ejecuta
gettext.
.po
gettext.
.mo,
bin/compile-messages.py.
make-messages.py,
de la siguiente manera:
bin/compile-messages.py
Y eso es todo. Tus traducciones estn listas para ser usadas.
18.4.
Una vez que has preparado tus traducciones -- o, si solo deseas usar las que estn incluidas en Django -- necesitars
activar el sistema de traduccin para tu aplicacin.
Detrs de escena, Django tiene un modelo muy exible para decidir qu idioma se usar -- determinado a nivel de
la instalacin, para un usuario particular, o ambas.
Para congurar una preferencia de idioma a nivel de la instalacin, ja
cin. Django usar este idioma como la traduccin por omisin -- la opcin a seleccionarse en ltimo trmino si ningn
otro traductor encuentra una traduccin.
Si todo lo que deseas hacer es ejecutar Django con tu idioma nativo y hay disponible un archivo de idioma para el
mismo, simplemente asigna un valor a
LANGUAGE_CODE.
Si deseas permitir que cada usuario individual especique el idioma que ella o l preere, usa
LocaleMiddleware
para cada usuario.
LocaleMiddleware, agrega django.middleware.locale.LocaleMiddleware a tu variable de conguMIDDLEWARE_CLASSES. Debido a que el orden de los middlewares es relevante, deberas seguir las siguientes
Para usar
racin
LocaleMiddleware.
permite la seleccin del idioma basado en datos incluidos en la peticin. Personaliza el contenido
guas:
Asegrate de que se encuentre entre las primeras clases middleware instaladas.
SessionMiddleware,
213
LocaleMiddleware
usa
datos de la sesin.
Si usas
CacheMiddleware,
coloca
LocaleMiddleware
MIDDLEWARE_CLASSES
MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.locale.LocaleMiddleware'
)
LocaleMiddleware
django_language
django_language.
Accept-Language.
y le indica al servidor qu idioma(s) preeres en orden de prioridad. Django intenta con cada idioma
que aparezca en dicha cabecera hasta que encuentra uno para el que haya disponible una traduccin.
Si eso falla, usa la variable de conguracin global
LANGUAGE_CODE.
En cada uno de dichas ubicaciones, el formato esperado para la preferencia de idioma es el formato estndar,
como una cadena. Por ejemplo, portugus de Brasil es
pt-br.
especicado no, Django usar el idioma base. Por ejemplo, si un usuario especica
Django solo tiene disponible
de
, usar
de.
de-at
LANGUAGES.
Si deseas
restringir la seleccin de idiomas a un subconjunto de los idiomas provistos (debido a que tu aplicacin no incluye
todos esos idiomas), ja tu
LANGUAGES
LANGUAGES = (
('de', _('German')),
('en', _('English')),
)
Este ejemplo restringe los idiomas que se encuentran disponibles para su seleccin automtica a alemn e ingls (y
de-ch o en-us).
LANGUAGES personalizado es posible marcar los idiomas como cadenas de traduccin -- pero usa una funcin gettext() boba, no la que se encuentra en django.utils.translation. Nunca debes importar django.utils.transla
desde el archivo de conguracin debido a que ese mdulo a su vez depende de las variables de conguracin, y eso
creara una importacin circular.
La solucin es usar una funcin
gettext()`
_ = lambda s: s
LANGUAGES = (
('de', _('German')),
('en', _('English')),
)
Con este esquema,
make-messages.py todava ser capaz de encontrar y marcar dichas cadenas para su traduccin
pero la misma no ocurrir en tiempo de ejecucin, de manera que tendrs que recordar envolver los idiomas con la
verdadera
El
Si deseas ofrecer traducciones para tu aplicacin que no se encuentran en el conjunto de traducciones incluidas en el
cdigo fuente de Django, querrs proveer al menos traducciones bsicas para ese idioma. Por ejemplo, Django usa
identicadores de mensajes tcnicos para traducir formatos de fechas y de horas -- as que necesitars al menos esas
traducciones para que el sistema funcione correctamente.
Un buen punto de partida es copiar el archivo
.po
214
Los identicadores de mensajes tcnicos son fcilmente reconocibles; estn completamente en maysculas. No
necesitas traducir los identicadores de mensajes como lo haces con otros mensajes; en cambio, deber proporcionar la
variante local correcta del valor provisto en ingls. Por ejemplo, con
este sera la cadena de formato que deseas usar en tu idioma. El formato es idntico al de la cadena de formato usado
now.
LocaleMiddleware ha determinado la preferencia del usuario, la deja disponible como request.LANGUAGE_CODE
para cada objeto peticin. Eres libre de leer este valor en tu cdigo de vista. A continuacin un ejemplo simple:
Nota que con traduccin esttica (en otras palabras sin middleware) el idioma est en
mientras que con traduccin dinmica (con middleware) el mismo est en
18.5.
django.views.i18n.set_language,
(r'^i18n/', include('django.conf.urls.i18n')),
/i18n/setlang/).
GET, con un parmetro language incluido en la cadena de consulta. Si el
soporte para sesiones est activo, la vista guarda la opcin de idioma en la sesin del usuario. Caso contrario, guarda
el idioma en una cookie
django_language.
Despus de haber jado la opcin de idioma Django redirecciona al usuario, para eso sigue el siguiente algoritmo:
Django busca un parmetro
next
en la cadena de consulta.
Referer.
Si la misma est vaca -- por ejemplo, si el navegador de un usuario suprime dicha cabecera -- entonces
el usuario ser redireccionado a
18.6.
est llamando. Si encuentra una traduccin para el idioma seleccionado, la misma ser instalada.
A continuacin, busca un directorio
django/conf/locale.
215
De esta forma, puedes escribir aplicaciones que incluyan su propias traducciones, y puedes reemplazar traducciones
base colocando las tuyas propias en la ruta de tu proyecto. O puedes simplemente construir un proyecto grande a
partir de varias aplicaciones y poner todas las traducciones en un gran archivo de mensajes. Es tu eleccin.
Nota
Si ests jando manualmente la variables de conguracin, el directorio
locale
en el directorio
del proyecto no ser examinado dado que Django pierde la capacidad de deducir la ubicacin del
directorio del proyecto. (Django normalmente usa la ubicacin del archivo de conguracin para
determinar esto, y en el caso que ests jando manualmente tus variables de conguracin dicho
archivo no existe).
Todos los repositorios de archivos de mensajes estn estructurados de ka misma manera:
$APPPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
$PROJECTPATH/locale/<language>/LC_MESSAGES/django.(po|mo)
LOCALE_PATHS en tu archivo de conguracin
<language>/LC_MESSAGES/django.(po|mo)
$PYTHONPATH/django/conf/locale/<language>/LC_MESSAGES/django.(po|mo)
Para crear archivos de mensajes, usas la misma herramienta
make-messages.py
mensajes de Django. Solo necesitas estar en la ubicacin adecuada -- en el directorio en el cual exista ya sea el directorio
conf/locale (en el caso del rbol de cdigo fuente) o el directorio locale/ (en el caso de mensajes de aplicacin o de
proyecto). Usas tambin la misma herramienta compile-messages.py para producir los archivos binarios django.mo
usados por gettext.
Los archivos de mensajes de aplicaciones son un poquito complicados a la hora de buscar por los mismos -necesitas el
LocaleMiddleware.
del proyecto.
Finalmente, debes dedicarle tiempo al diseo de la estructura de tus archivos de traduccin. Si tus aplicaciones
necesitan ser enviadas a otros usuarios y sern usadas en otros proeyctos, posiblemente quieras usar traducciones
especcas a dichas aplicaciones. Pero el usar traducciones especcas a aplicaciones y aplicaciones en proyectos podran
producir problemas extraos con
make-messages.py. make-messages
debajo de la ruta actual y de esa forma podra colocar en el archivo de mensajes del proyecto identicadores de
mensajes que ya se encuentran en los archivos de mensajes de la aplicacin.
la salida ms fcil de este problema es almacenar las aplicaciones que no son partes del proyecto (y por ende poseen
sus propias traducciones) fuera del rbol del proyecto. De esa forma make-messages.py ejecutado a nivel proyecto slo
traducir cadenas que estn conectadas a tu proyecto y no cadenas que son distribuidas en forma independiente.
18.7.
Traducciones y JavaScript
gettext.
el servidor.
Los catlogos de traduccin para JavaScript deben ser mantenidos tan pequeos como sea posible.
Django provee una solucin integrada para esos problemas: convierte las traducciones a JavaScript, de manera que
puedas llamar a
18.7.1.
gettext
La vista javascript_catalog
javascript_catalog, que
gettext ms un arreglo de cadenas
traduccin se toman desde la aplicacin, el proyecto o el ncleo de Django, de acuerdo a lo que especiques ya sea en
el
info_dict
o en la URL.
216
js_info_dict = {
'packages': ('your.app.package',),
}
urlpatterns = patterns('',
(r'^jsi18n/$', 'django.views.i18n.javascript_catalog', js_info_dict),
)
package debe seguir la sintaxis
INSTALLED_APPS) y deben referirse
Cada cadena en
las cadenas en
locale.
Si especicas
mltiples paquetes, todos esos catlogos son fusionados en un catlogo nico. esto es til si usas JavaScript que usa
cadenas de diferentes aplicaciones.
Puedes hacer que la vista sea dinmica colocando los paquetes en el patrn de la URL:
urlpatterns = patterns('',
(r'^jsi18n/(?P<packages>\S+?)/$, 'django.views.i18n.javascript_catalog'),
)
Con esto, especicas los paquetes como una lista de nombres de paquetes delimitados por un smbolo
+ en la URL.
Esto es especialmente til si tus pginas usan cdigo de diferentes aplicaciones, este cambia frecuentemente y no deseas
tener que descargar un nico gran catlogo. Como una medida de seguridad, esos valores pueden solo tomar los valores
django.conf
18.7.2.
INSTALLED_APPS.
Para usar el catlogo simplemente descarga el script generado dinmicamente de la siguiente forma:
gettext
document.write(gettext('this is to be translated'));
Existe incluso una interfaz
ngettext
d = {
count: 10
};
s = interpolate(ngettext('this is %(count)s object', 'this are %(count)s objects', d.count), d);
La funcin
interpolate admite tanto interpolacin posicional como interpolacin con nombres. De manera que el
ngettext
para generar
18.7.3.
Los catlogos de traducciones se crean y actualizan de la misma manera que el resto de los catlogos de traducciones
de Django: con la herramienta
-d djangojs,
make-messages.py.
de la siguiente forma:
make-messages.py -d djangojs -l de
Esto crea o actualiza el catlogo de traduccin para JavaScript para alemn. Luego de haber actualizado catlogos,
slo ejecuta
compile-messages.py
Django.
18.8.
GETTEXT
Si conoces
217
gettext
gettext podras notar las siguientes particularidades en la forma en que Django maneja las traducciones:
django
djangojs.
entre diferentes programas que almacenan sus datos en una biblioteca comn de archivos de mensajes
(usualmente
catlogos de traducciones de JavaScript para asegurar que los mismos sean tan pequeos como sea
posible.
gettext y gettext_noop.
DEFAULT_CHARSET. Usar ugettext
cadenas
msgfmt.
18.9.
Qu sigue?
Este captulo esencialmente concluye nuestra cobertura de las caractersticas de Django. Deberas conocer lo suciente para comenzar a producir tus propios sitios usando Django.
Sin embargo, escribir el cdigo es solo el primer paso de la instalacin de un sitio Web exitoso. Los siguientes dos
`Captulo
19`_ trata cmo puedes hacer para hace que tus sitios y tus usuarios estn seguros ante atacantes maliciosos y el
captulos cubren las cosas que necesitars conocer si deseas que tu sitio sobreviva en el mundo real. El
Captulo 20 detalla cmo instalar una aplicacin Django en uno o varios servidores.
218
Captulo 19
Seguridad
Internet puede ser un lugar aterrador.
En estos tiempos, los papelones de seguridad con alta exposicin pblica parecen ser cosa de todos los das. Hemos
visto virus propagarse con una velocidad asombrosa, ejrcitos de computadoras comprometidas ser empuados como
armas, una interminable carrera armamentista contra los spammers, y muchos, muchos reportes de robos de identidad
de sitios Web hackeados.
Parte de las tareas de un desarrollador Web es hacer lo que est en sus manos para combatir esas fuerzas de la
oscuridad. Todo desarrollador Web necesita considerar la seguridad como un aspecto fundamental de la programacin
Web. Desafortunadamente, se da el caso de que implementar la seguridad es difcil -- los atacantes slo necesitan
encontrar una nica vulnerabilidad, pero los defensores deben proteger todas y cada una.
Django intenta mitigar esta dicultad. Est diseado para protegerte automticamente de muchos de los errores de
seguridad comunes que cometen los nuevos (e incluso los experimentados) desarrolladores Web. Aun as, es importante
entender de qu se tratan dichos problemas, cmo es que Django te protege, y -- esto es lo ms importante -- los pasos
que puedes tomar para hacer tu cdigo aun ms seguro.
Antes, sin embargo, una importante aclaracin: No es nuestra intencin presentar una gua denitiva sobre todos los
exploits de seguridad Web conocidos, y tampoco trataremos de explicar cada vulnerabilidad en una forma completa.
En cambio, presentaremos una breve sinopsis de problemas de seguridad que son relevantes para Django.
19.1.
out of band (por ejemplo cabeceras HTTP, cookies, y otra informacin de peticin). Es trivial falsicar los metadatos
de la peticin que los navegadores usualmente agregan automticamente.
Todas las vulnerabilidades tratadas en este captulo derivan directamente de conar en datos que arriban a travs
del cable y luego fallar a la hora de limpiar esos datos antes de usarlos. Debes convertir en una prctica general el
preguntarte De donde vienen estos datos`
19.2.
Inyeccin de SQL
La inyeccin de SQL es un exploit comn en el cual un atacante altera los parmetros de la pgina (tales como
datos de
GET/POST
o URLs) para insertar fragmentos arbitrarios de SQL que una aplicacin Web ingenua ejecuta
220
def user_contacts(request):
user = request.GET['username']
sql = "SELECT * FROM user_contacts WHERE username = ' %s';" % username
# execute the SQL here...
Nota
En este ejemplo, y en todos los ejemplos similares del tipo no hagas esto que siguen, hemos
omitido deliberadamente la mayor parte del cdigo necesario para hacer que el mismo realmente
funcione. No queremos que este cdigo sirva si accidentalmente alguien lo toma fuera de contexto
y lo usa.
A pesar de que a primera vista eso no parece peligroso, realmente lo es.
Primero, nuestro intento de proteger nuestra lista de emails completa va a fallar con una consulta construida en
forma ingeniosa. Pensemos acerca de qu sucede si un atacante escribe
"'OR 'a'='a"
OR
"'; DELETE
SELECT * FROM user_contacts WHERE username = ''; DELETE FROM user_contacts WHERE 'a' = 'a';
Ouch! Donde ira a parar nuestra lista de contactos?
19.2.1.
La solucin
Aunque este problema es insidioso y a veces difcil de detectar la solucin es simple: nunca confes en datos provistos
por el usuario y siempre escapa el mismo cuando lo conviertes en SQL.
La API de base de datos de Django hace esto por ti. Escapa automticamente todos los parmetros especiales
SQL, de acuerdo a las convenciones de uso de comillas del servidor de base de datos que ests usando (por ejemplo,
PostgreSQL o MySQL).
Por ejemplo, en esta llamada a la API:
foo.get_list(bar__exact="' OR 1=1")
Django escapar la entrada apropiadamente, resultando en una sentencia como esta:
where del mtodo extra() (ver Apndice C). Dicho parmetro acepta, por diseo, SQL
crudo.
Consultas realizadas a mano usando la API de base de datos de nivel ms bajo.
En tales casos, es fcil mantenerse protegido. para ello evita realizar interpolacin de strings y en cambio usa
parmetros asociados (bind parameters ). Esto es, el ejemplo con el que comenzamos esta seccin debe ser escrito de la
siguiente manera:
execute
221
inserta parmetros desde la lista que se le provee como segundo argumento. Cuando construyas SQL en forma manual
hazlo siempre de esta manera.
Desafortunadamente, no puedes usar parmetros asociados en todas partes en SQL; no son permitidos como identicadores (esto es, nombres de tablas o columnas). As que, si, por ejemplo, necesitas construir dinmicamente una
lista de tablas a partir de una variable enviada mediante
provee una funcin,
django.db.backend.quote_name,
POST,
19.3.
El Cross-site scripting (XSS) (Scripting inter-sitio), puede encontrarse en aplicaciones Web que fallan a la hora
de escapar en forma correcta contenido provisto por el usuario antes de renderizarlo en HTML. Esto le permite a un
atacante insertar HTML arbitrario en tu pgina Web, usualmente en la forma de etiquetas
<script>.
Los atacantes a menudo usan ataques XSS para robar informacin de cookies y sesiones, o para engaar usuarios
y lograr que proporcionen informacin privada a la persona equivocada (tambin conocido como phishing ).
Este tipo de ataque puede tomar diferentes formas y tiene prcticamente innitas permutaciones, as que slo
vamos a analizar un ejemplo tpico. Consideremos esta simple vista Hola mundo:
def say_hello(request):
name = request.GET.get('name', 'world')
return render_to_response("hello.html", {"name" : name})
Esta vista simplemente lee un nombre desde un parmetro
GET
hello.html.
http://example.com/hello/?name=Jacob,
siguiente:
<h1>Hello, Jacob!</h1>
Pero atencin -- qu sucede si accedemos a
http://example.com/hello/?name=<i>Jacob</i>?
En ese caso
obtenemos esto:
<h1>Hello, <i>Jacob</i>!</h1>
Obviamente, un atacante no usar algo tan inofensivo como etiquetas
<i>;
de HTML que se apropiara de tu pgina insertando contenido arbitrario. Este tipo de ataques ha sido usado para
engaar a usuarios e inducirlos a introducir datos en lo que parece ser el sitio Web de su banco, pero en efecto es un
formulario saboteado va XSS que enva su informacin bancaria a un atacante.
El problema se complica aun ms si almacenas estos datos en la base de datos y luego la visualizas en tu sitio. Por
ejemplo, en una oportunidad se encontr que MySpace era vulnerable a un ataque XSS de esta naturaleza. Un usuario
haba insertado JavaScript en su pgina de perl, dicho cdigo agregana lo agregaba a la lista de amigos de todos los
usuarios que visitaran su pgina de perl. En unos pocos das lleg a tener millones de amigos.
Ahora, esto podra sonar relativamente inofensivo, pero no olvides que este atacante haba logrado que su cdigo
-- no el cdigo de MySpace -- se ejecutara en tu computadora. Esto viola la conanza asumida acerca de que todo el
cdigo ubicado en MySpace es realmente escrito por MySpace.
MySpace fue muy afortunado de que este cdigo malicioso no hiciera cosas como borrar automticamente las
cuentas de los usuarios que lo ejecutaran, o cambiar sus contraseas, o inundar el sitio con spam, o cualquiera de los
otros escenarios de pesadilla que esta vulnerabilidad hace posibles.
19.3.1.
La solucin
La solucin es simple: siempre escapa todo el contenido que pudiera haber sido enviado por un usuario. Si simplemente reescribiramos nuestra plantilla de la siguiente manera:
escape
222
19.4.
La Cross-site request forgery (CSRF) (Falsicacin de peticiones inter-sitio) sucede cuando un sitio Web malicioso
engaa a los usuarios y los induce a visitar una URL desde un sitio ante el cual ya se han autenticado -- por lo tanto
saca provecho de su condicin de usuario ya autenticado.
Django incluye herramientas para proteger ante este tipo de ataques. Tanto el ataque en s mismo como dichas
herramientas son tratados con gran detalle en el Captulo 14.
19.5.
Session Forging/Hijacking
No se trata de un ataque especco, sino una clase general de ataques sobre los datos de sesin de un usuario.
Puede tomar diferentes formas:
Un ataque del tipo man-in-the-middle, en el cual un atacante espa datos de sesin mientras estos
viajan por la red (cableada o inalmbrica).
Session forging (Falsicacin de sesin), en la cual un atacante usa un identicador de sesin (posiblemente obtenido mediante un ataque man-in-the-middle) para simular ser otro usuario.
Un ejemplo de los dos primeros sera una atacante en una cafetera usando la red inalmbrica del lugar
para capturar una cookie de sesin. Podra usar esa cookie para hacerse pasar por el usuario original.
Un ataque de falsicacin de cookies en el cual un atacante sobrescribe los datos almacenados en una
cookie que en teora no son modicables. El Captulo 12 explica en detalle cmo funcionan las cookies,
y uno de los puntos salientes es que es trivial para los navegadores y usuarios maliciosos el cambiar
las cookies sin tu conocimiento.
Existe una larga historia de sitios Web que han almacenado una cookie del tipo
LoggedInAsUser=jacob.
IsLoggedIn=1
o aun
En un nivel aun ms sutil, nunca ser una buena idea conar en nada que se almacene en cookies;
nunca sabes quin puede haber estado manoseando las mismas.
Session xation (jacin de sesin), en la cual un atacante engaa a un usuario y logra asignar un
nuevo valor o limpiar el valor existente del identicador de su sesin.
Por ejemplo, PHP permite que los identicadores de sesin se pasen en la URL (por ejemplo,
http://example.com/?PHPSE
Un atacante que logre engaar a un usuario para que haga click en un link que posea un identicador
de sesin jo causar que ese usuario comience a usar esa sesin.
La jacin de sesin se ha usado en ataques de phishing para engaar a usuarios e inducirlos a ingresar
informacin personal en una cuenta que est bajo el control de atacante. Este puede luego conectarse
al sitio con dicho usuario y obtener datos.
223
Un ejemplo cannico es un sitio que almacena un valor de preferencia simple (como el color de fondo
de una pgina) en una cookie. Un atacante podra engaar a un usuario e inducirlo a hacer click en
un link que enva un color que en realidad contiene un ataque XSS; si dicho color no est siendo
escapado, el usuario podra insertar nuevamente cdigo malicioso en el entorno del usuario.
19.5.1.
La solucin
request.session),
eso es manejado en
forma automtica. La nica cookie que usa el framework de sesiones es un identicador de sesin;
todos los datos de la sesiones se almacenan en la base de datos.
Recuerda escapar los datos de la sesin si los visualizas en la plantilla. Revisa la seccin previa sobre
XSS y recuerda que esto se aplica a cualquier contenido creado por el usuario as como a cualquier
dato enviado por el navegador. Debes considerar la informacin de sesiones como datos creados por
el usuario.
Previene la falsicacin de de identicadores de sesin por parte de un atacante siempre que sea
posible.
A pesar de que es prcticamente imposible detectar a alguien que se ha apropiado de un identicador
de sesin, Django incluye proteccin contra un ataque de sesiones de fuerza bruta. Los identicadores
de sesin se almacenan como hashes (en vez de nmeros secuenciales) lo que previene un ataque por
fuerza bruta, y un usuario siempre obtendr un nuevo identicador de sesin si intenta usar uno no
existente, lo que previene la session xation.
Nota que ninguno de estos principios y herramientas previene ante ataques man-in-the-middle. Dichos tipos de
ataques son prcticamente imposibles de detectar. Si tu sitio permite que usuarios identicados visualicen algn tipo
de datos importantes debes, siempre, publicar dicho sitio va HTTPS. Adicionalmente, si tienes un sitio con SSL, debes
asignar a la variable de conguracin
SESSION_COOKIE_SECURE
el valor
True;
de sesin va HTTPS.
19.6.
La hermana menos conocida de la inyeccin de SQL, la inyeccin de cabeceras de email, toma control de formularios
Web que envan emails. Un atacante puede usar esta tcnica para enviar spam mediante tu servidor de email. Cualquier
formulario que construya cabeceras de email a partir de datos de un formulario Web es vulnerable a este tipo de ataque.
Analicemos el formulario de contacto cannico que puede encontrarse en muchos sitios. Usualmente el mismo enva
un mensaje a una direccin de email ja y, por lo tanto, a primera vista no parece ser vulnerable a abusos de spam.
Sin embargo, muchos de esos formularios permiten tambin que los usuarios escriban su propio asunto para el email
(en conjunto con una direccin de, el cuerpo del mensaje y a veces algunos otros campos). Este campo asunto es
usado para construir la cabecera subject del mensaje de email.
Si dicha cabecera no es escapada cuando se construye el mensaje de email, un atacante podra enviar algo como
"hello\ncc:[email protected]" (donde "\n" es un caracter de salto de lnea). Eso hara que las cabeceras de
email fueran:
To: [email protected]
Subject: hello
cc: [email protected]
Como en la inyeccin de SQL, si conamos en la lnea de asunto enviada por el usuario, estaremos permitindole
construir un conjunto malicioso de cabeceras, y podr usar nuestro formulario de contacto para enviar spam.
224
19.6.1.
La solucin
Podemos prevenir este ataque de la misma manera en la que prevenimos la inyeccin de SQL: escapando o vericando
siempre el contenido enviado por el usuario.
Las funciones de mail incluidas en Django (en
django.core.mail)
en ninguno de los campos usados para construir cabeceras (las direcciones de y para, ms el asunto). Si inten-
con un asunto que contenga saltos de lnea, Django arrojar una excepcin
Si no usas las funciones de email de Django para enviar email, necesitars asegurarte de que los saltos de lnea en las
cabeceras o causan un error o son eliminados. Podras querer examinar la clase
SafeMIMEText
en
django.core.mail
19.7.
Directory Traversal
Directory traversal se trata de otro ataque del tipo inyeccin, en el cual un usuario malicioso subvierte cdigo de
manejo de sistema de archivos para que lea y/o escriba archivos a los cuales el servidor Web no debera tener acceso.
Un ejemplo podra ser una vista que lee archivos desde disco sin limpiar cuidadosamente el nombre de archivo:
def dump_file(request):
filename = request.GET["filename"]
filename = os.path.join(BASE_PATH, filename)
content = open(filename).read()
# ...
A pesar que parece que la vista restringe el acceso a archivos que se encuentren ms all que
os.path.join),
si la atacante enva un
filename
que contenga
..
BASE_PATH
(usando
directorio padre), podra acceder a archivos que se encuentren ms arriba que
BASE_PATH.
De all en ms es slo
una cuestin de tiempo el hecho que descubra el nmero correcto de puntos para acceder exitosamente, por ejemplo a
../../../../../etc/passwd.
Todo aquello que lea archivos sin el escaping adecuado es vulnerable a este problema. Las vistas que escriben
archivos son igual de vulnerables, pero las consecuencias son doblemente calamitosas.
Otra permutacin de este problema yace en cdigo que carga mdulos dinmicamente a partir de la URL u otra
informacin de la peticin. Un muy pblico ejemplo se present en el mundo de Ruby on Rails. Con anterioridad a
mediados del 2006, Rails usaba URLs como
e invocar mtodos. El resultado fu que una URL cuidadosamente construida poda cargar automticamente cdigo
arbitrario, incluso un script de reset de base de datos!
19.7.1.
La solucin
Si tu cdigo necesita alguna vez leer o escribir archivos a partir de datos ingresados por el usuario, necesitas limpiar
muy cuidadosamente la ruta solicitada para asegurarte que un atacante no pueda escapar del directorio base ms all
del cual ests restringiendo el acceso.
Nota
No es necesario decirlo, nunca debes escribir cdigo que pueda leer cualquier rea del disco!
Un buen ejemplo de cmo hacer este escaping yace en la vista de publicacin de contenido estticos (en
Este es el cdigo relevante:
import os
import posixpath
# ...
path = posixpath.normpath(urllib.unquote(path))
newpath = ''
for part in path.split('/'):
if not part:
revisin 757 del 28 de julio de 2008
django.view.static).
225
static.serve,
recin mostrado), as que esta vulnerabilidad no afecta demasiado el cdigo del ncleo.
Adicionalmente, el uso de la abstraccin de URLconf signica que Django solo cargar cdigo que le hayas indicado
explcitamente que cargue. No existe manera de crear una URL que cause que Django cargue algo no mencionado en
una URLconf.
19.8.
Mientras se desarrolla, tener la posibilidad de ver tracebacks y errores en vivo en tu navegador es extremadamente
til. Django posee mensajes de depuracin vistosos e informativos especcamente para hacer la tarea de depuracin
ms fcil.
Sin embargo, si esos errores son visualizados una vez que el sitio pasa a produccin, pueden revelar aspectos de tu
cdigo o conguracin que podran ser de utilidad a un atacante.
Es ms, los errores y tracebacks no son para nada tiles para los usuarios nales. La losofa de Django es que los
visitantes al sitio nunca deben ver mensajes de error relacionados a una aplicacin. Si tu cdigo genera una excepcin
no tratada, un visitante al sitio no debera ver un traceback completo -- ni ninguna pista de fragmentos de cdigo o
mensajes de error (destinados a programadores) de Python. En cambio, el visitante debera ver un amistoso mensaje
Esta pgina no est disponible.
Naturalmente, por supuesto, los desarrolladores necesitan ver tracebacks para depurar problemas en su cdigo. As
que el framework debera ocultar todos los mensajes de error al pblico pero debera mostrarlos a los desarrolladores
del sitio.
19.8.1.
La solucin
Django tiene un sencillo control que gobierna la visualizacin de esos mensajes de error. Si se ja la variable de
conguracin
DEBUG
al valor
True,
retornar un mensaje HTTP 500 (Error interno del servidor) y renderizar una plantilla de error provista por ti.
Esta plantilla de error tiene el nombre
Dado que los desarrolladores aun necesitan ver los errores que se generan en un sitio en produccin, todos los
errores que se manejen de esta manera dispararn el envo de un email con el traceback completo a las direcciones de
correo conguradas en la variable
ADMINS.
Los usuarios que implementen en conjunto con Apache y mod_python deben tambin asegurarse que tienen
PythonDebug Off
en sus archivos de conguracin de Apache; esto suprimir cualquier error que pudiera ocurrir aun
19.9.
Esperamos que toda esta exposicin sobre problemas de seguridad no sea demasiado intimidante. Es cierto que la
Web puede ser un mundo salvaje y confuso, pero con un poco de previsin puedes tener un sitio Web seguro.
Ten en mente que la seguridad Web es un campo en constante cambio; si ests leyendo la versin en papel de
este libro, asegrate de consultar recursos sobre seguridad ms actuales en bsqueda de nuevas vulnerabilidades
que pudieran haber sido descubiertas. En efecto, siempre es una buena idea dedicar algn tiempo semanalmente o
mensualmente a investigar y mantenerse actualizado acerca del estado de la seguridad de aplicaciones Web. Es una
pequea inversin a realizar, pero la proteccin que obtendrs para ti y tus usuarios no tiene precio.
226
19.10.
En el
Qu sigue?
`prximo captulo`_, nalmente trataremos las sutilezas de la implementacin de Django: como lanzar un
Captulo 20
Implementando Django
A lo largo de este libro, hemos mencionado algunos objetivos que conducen el desarrollo de Django. Facilidad de
uso, amigabilidad para nuevos programadores, abstraccin de tareas repetitivas -- todos esas metas marcaron el camino
de los desarrolladores.
Sin embargo, desde la concepcin de Django, ha existido siempre otro objetivo importante: Django debera ser fcil
de implementar, y debera poder servir una gran cantidad de trco con recursos limitados.
Las motivaciones para este objetivo se vuelven evidentes cuando observas el trasfondo de Django: un pequeo
peridico en Kansas difcilmente pueda costear hardware de servidor de ltima tecnologa, por lo que los desarrolladores
originales de Django trataron de extraer el mximo desempeo posible de los escasos recursos disponibles. De hecho,
por aos los desarrolladores de Django actuaron como sus propios administradores de sistema -- ya que simplemente
no haba suciente harware como para necesitar administradores dedicados a esa tarea -- incluso manejando sitios con
decenas de millones de entradas por da.
Como Django se volvi un proyecto open source, este enfoque en el desempeo y la facilidad de implementacin
se torn importante por diferentes razones: los desarrolladores acionados tienen los mismos requerimientos. Los
individuos que quieren usar Django estn encantados de saber que pueden hospedar un sitio con trco entre pequeo
y mediano por menos de u$s 10 mensuales.
Pero ser capaz de escalar hacia abajo es solamente la mitad de la batalla. Django tambin debe ser capaz de escalar
hacia arriba para conocer las necesidades de grandes empresas y corporaciones. Aqu, Django adopta una losofa
comn entre los grupos de software del tipo LAMP que suele llamarse shared nothing (nada compartido).
Qu es LAMP?
El acrnimo LAMP fue originalmente acuado para describir un conjunto de software open source
utilizado para propulsar muchos sitios web:
Linux (sistema operativo)
Apache (servidor web)
MySQL (base de datos)
PHP (lenguaje de programacin)
A lo largo del tiempo, el acrnimo se ha vuelto ms una referencia a la losofa de este tipo de
agrupamiento de software que a cualquiera de estos en particular. Por ello, aunque Django usa
Python y es agnstico respecto al motor de base de datos a utilizar, las losofas probadas por
los agrupamientos tipo LAMP permanece en la mentalidad de implementacin de Django.
Han habido algunos (ms que nada cmicos) intentos de acuar acrnimos similares para describir
los agrupamientos de tecnologa que usa Django. Los autores de este libro estn encariados con
LAPD (Linux, Apache, PostgreSQL, y Django) o PAID (PostgreSQL, Apache, Internet, y Django).
Usa Django y consigue un PAID! (N. de T.: En ingls, PAID signica pago).
20.1.
Nada Compartido
Esencialmente, la losofa shared nothing se trata de el acoplamiento dbil aplicado a todo el conjunto de software
utilizado. Esta arquitectura se present como respuesta directa a la que en su momento prevaleca: una aplicacin de
228
servidor web monoltica que encapsulaba el lenguaje, la base de datos y el servidor web -- e incluso partes del sistema
operativo -- un nico proceso (por ejemplo, Java).
Cuando llega el momento de escalar, esto puede ser un problema serio; es casi imposible separar el trabajo de un
proceso monoltico entre muchas maquinas fsicas diferentes, por lo que las aplicaciones monolticas requieren servidores
enormemente potentes. Estos servidores, por supuesto, cuestan decenas o a veces centenas de miles de dolares, dejando
a los sitios web de gran escala lejos del alcance de individuos o pequeas compaas con buenas ideas pero sin efectivo.
No obstante, lo que la comunidad LAMP descubri fue que si se separa cada pieza de esa pila de software Web
en componentes individuales, se podra fcilmente comenzar con un servidor barato y simplemente ir agregando ms
servidores baratos a medida que se crece. Si un servidor de base de datos de u$s3000 ya no puede manejar la carga,
sencillamente se comprara un segundo (o un tercero, o un cuarto) hasta que pueda. Si se necesita ms capacidad de
almacenamiento, se agregara un servidor NFS.
Aunque para que esto funcione, las aplicaciones Web deben dejar de asumir que el mismo servidor es el que maneja
cada peticin -- o incluso las distintas partes de una peticin. En una implementacin LAMP (y Django) de gran
escala, ms de media docena de servidores pueden estar involucrados en servir una sola peticin! Las repercusiones a
esta situacin son numerosas, pero pueden reducirse a estos puntos:
El estado no puede ser guardado localmente. En otras palabras, cualquier dato que deba estar disponible entre mltiples solicitudes, debe almacenarse en algn tipo de almacenamiento permanente como
la base de datos o una cach centralizada.
El software no puede asumir que los recursos son locales. Por ejemplo, la plataforma web no puede
asumir que la base de datos corre en el mismo servidor; por lo que debe ser capaz de conectarse a
servidor de base de datos remoto.
Cada pieza del conjunto debe ser fcilmente trasladable o reemplazable. Si Apache por alguna razn no
funciona para la implementacin dada, deberas ser posible cambiarlo por otro servidor con mnimas
complicaciones. O a nivel hardware, si un servidor web falla, debera ser posible reemplazarlo por
otra maquina con nmos tiempos de cada. Recuerda, esta losofa sobre implementacin se basa
enteramente en hardware barato. Fallas en maquinas individuales deben estar contempladas.
Como probablemente esperabas, Django maneja todo esto ms o menos de forma transparente -- ninguna parte de
Django viola estos principios -- pero conocer la losofa ayuda cuando es tiempo de escalar.
20.2.
229
El open source es famoso por sus llamadas guerras religiosas; mucha tinta (digital) ha sido despilfarrada argumen-
20.3.
Apache con mod_python es actualmente la conguracin ms robusta para usar Django en un servidor en produccin.
mod_python (http://www.djangoproject.com/r/mod_python/) es un plugin de Apache que embebe Python dentro
de Apache y carga cdigo Python en memoria cuando el servidor se inicia. El cdigo permanece en memoria a lo largo
de la vida del proceso Apache, lo que repercute en aumentos signicativos de desempeo comparado con otros arreglos
de servidor.
Django requiere Apache 2.x y mod_python 3.x, y nosotros preferimos el mdulo de multiprocesamiento (MPM)
prefork de Apache, por sobre el MPM worker.
Nota
Congurar Apache est claramente ms all del alcance de este libro, por lo que simplemente mencionaremos algunos detalles que necesitamos. Afortunadamente existen grandes recursos
disponibles para aprender ms sobre Apache. Algunos de los que nos gustan son los siguientes:
La
documentacin
gratuita
de
Apache,
djangoproject.com/r/apache/docs/
disponible
via
http://www.
Pro Apache, Third Edition (Apress, 2004) de Peter Wainwright, disponible via
http://www.djangoproject.com/r/books/pro-apache/
Apache: The Denitive Guide, Third Edition (O'Reilly, 2002) de Ben Laurie y Peter Laurie, disponible via
apache-pra/
20.3.1.
http://www.djangoproject.com/r/books/
Conguracin bsica
Para congurar Django con mod_python, primero debe asegurarse de que tiene Apache instalado con el mdulo
mod_python activado. Esto usualmente signica tener una directiva
LoadModule
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE misitio.settings
PythonDebug On
</Location>
en tu archivo de conguracin de
230
Asegurese de reemplazar
misitio.settings
por el
DJANGO_SETTINGS_MODULE
Esto le dice a Apache, Usa mod_python para cualquier URL en '/' o bajo ella, usando el manejado mod_python
Apache comunmente corre como un usuario diferente de tu usuario normal y puede tener una ruta y un sys.path
distintos. Puedes necesitar decirle a mod_python cmo encontrar tu proyecto y a Django mismo:
PythonDebug Off
PythonDebug On,
tus usuarios vern feas trazas de error de Python si algo sale dentro de mod_python.
Reinicia Apache, y cualquier peticin a tu sitio (o a tu host virtual si pusiste las directivas dentro de un bloque
<VirtualHost>)
Nota
Si implementas Django en un subdirectorio -- esto es, en algun lugar ms profundo que / -Django no recortar el prejo de la URL para tu URLpatterns. Entonces, si tu conguracin de
Apache luce como esto:
<Location "/misitio/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE misitio.settings
PythonDebug On
</Location>
entonces todos tus patrones de URL debern comenzar con
"/misitio/".
que usualmente recomendamos implementar Django sobre la raiz de tu dominio o host virtual.
Alternativamente, simplemente puede hacer descender el nivel de tu URL usando una cua de
URLconf:
urlpatterns = patterns('',
(r'^misitio/', include('normal.root.urls')),
)
20.3.2.
Es enteramente posible correr multiples instalaciones de Django en la misma instancia de Apache. Probablemente
quieras hacer esto si eres un desarrollador web independiente con multiples clientes pero un slo un nico servidor.
Para lograr esto, simplemente usa
VirtualHost
as:
NameVirtualHost *
<VirtualHost *>
ServerName www.ejemplo.com
# ...
SetEnv DJANGO_SETTINGS_MODULE misitio.settings
</VirtualHost>
<VirtualHost *>
ServerName www2.ejemplo.com
# ...
SetEnv DJANGO_SETTINGS_MODULE misitio.other_settings
</VirtualHost>
231
VirtualHost,
para asegurarte de que el cach de cdigo de mod_python no mezcle las cosas. Usa la directiva
para brindar diferentes directivas
<Location>
PythonInterpreter
a interpretes distintos:
<VirtualHost *>
ServerName www.ejemplo.com
# ...
<Location "/algo">
SetEnv DJANGO_SETTINGS_MODULE misitio.settings
PythonInterpreter misitio
</Location>
<Location "/otracosa">
SetEnv DJANGO_SETTINGS_MODULE misitio.other_settings
PythonInterpreter misitio_otro
</Location>
</VirtualHost>
Los valores de
PythonInterpreter
Location
dife-
rentes.
20.3.3.
Debido a que mod_python cachea el cdigo python cargado, cuando implemantas sitios Django sobre mod_python
necesitars reiniciar Apache cada vez que realizar cambios en tu cdigo. Esto puede ser tedioso, por lo que aqui compartimos un pequeo truco para evitarlo: simplemente agrega
MaxRequestsPerChild 1
a tu archivo de conguracin
para forzar a Apache a recargar todo con cada peticin. Pero no hagas esto en un servidor de produccin, o revocaremos
tus privilegios Django.
Si eres el tipo de programador que depuran dispersando sentencias
cuenta que
no tiene efectos sobre mod_python; estas no aparecen en el log de Apache como pudras esperar.
Si necesitas imprimir informacin de depuracin en una conguracin mod_python, probablemente quieras usar el
paquete de registro de eventos estndar de Python (Python's standard logging package). Hay ms informacin disponible en
http://docs.python.org/lib/module-logging.html.
20.3.4.
Django no debera ser utilizado para servir archivos multimedia (imgen, audio, video, ash) por s mismo; mejor
deja ese trabajo al servidor web que hayas elegido. Recomendamos usar un servidor Web separado (es decir, uno que
no est corriendo a la vez Django) para servir estos archivos. Para ms informacin, mira la seccin Escalamiento.
Sin embargo, si no tienes opcin para servir los archivos multimedia que no sea el mismo
usa Django, aqu te mostramos como desactivar mod_python para una parte particular del sitio:
<Location "/media/">
SetHandler None
</Location>
Cambia
Location
<LocationMatch>
para comparar con una expresin regular. Por ejemplo, esto congura
.jpg, .gif,
.png:
<Location "/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</Location>
<Location "/media/">
SetHandler None
</Location>
revisin 757 del 28 de julio de 2008
media
232
<LocationMatch "\.(jpg|gif|png)$">
SetHandler None
</LocationMatch>
En todos estos casos, necesitars congurar la directiva
DocumentRoot
archivos estticos.
20.3.5.
Manejo de errores
Cuando usas Apache/mod_python, los errores sern canalizados por Django -- en otras palabras, estos no se
propagan al nivel de Apache y no aparecern en el
error_log
del servidor.
La excepcin a esto sucede si algo est realmente desordenado en tu conguracin Django. En este caso, vers una
pgina Internal Server Error en tu navegador, y el volcado de error (traceback) de Python completo en tu archivo
error_log
de Apache. Este volcado de error se difunde por multiples lneas. (S, es feo y bastante difcil de leer, pero
20.3.6.
Algunas veces, Apache produce fallas de segmentacin (Segmentation faults, en ingls) cuando instalas Django.
Cuando esto sucede, se trata casi siempre de una o dos causas no muy relacionadas con Django en s:
Puede ser que tu cdigo Python est importando el mdulo
puede entrar en conicto con la versin embebida en Apache. Para informacin detallada, revisa Expat
Causing Apache Crash en
http://www.djangoproject.com/r/articles/expat-apache-crash/.
Puede deberse a que ests corriendo mod_python y mod_php sobre la misma instancia de Apache,
con MySQL como motor de base de datos. En algunos casos, esto ocasiona un conocido problema
que mod_python tiene debido a conictos de versin en PHP y el back-end MySQL de la base. Hay
informacin detallada en un listado FAQ de mod_python, accesible via
com/r/articles/php-modpython-faq/
http://www.djangoproject.
Si continuas teniendo problemas para congurar mod_python, una buena cosa para hacer es poner un esqueleto de sitio sobre mod_python a funcionar, sin el framework Django. Esta es una manera fcil de aislar los problemas especcos de mod_python. El artculo Getting mod_python Working detalla el procedimiento:
//www.djangoproject.com/r/articles/getting-modpython-working/.
http:
El siguiente paso debera ser editar tu cdigo de pruebas y agregar la importacin de cualquier cdigo especco
de Django que estes usando -- tus vistas, tus modelos, tu URLconf, la conguracin de RSS, y as. Incluye estas
importaciones en tu funcin de gestin de pruebas, y accede a la URL correspondiente desde tu navegador. Si esto
causa un colapso, habrs conrmado que es la importacin de cdigo Django la causa del problema. Gradulamente
reduce el conjunto de importaciones hasta que el colapso desaparezca, de manera de encontrar el mdulo especco
que es el culpable. Profundiza en los mdulos y revisa sus importaciones si es necesario. Para ms ayuda, herramientas
de sistema como
ldconfig
en Linux,
otool
en Mac OS, y
ListDLLs
20.4.
Aunque Django bajo Apache y mod_python es la conguracin ms robusta de implementacin, mucha gente usa
hosting compartido, en los que FastCGI es la nica opcin de implementacin.
Adicionalmente, en algunas situaciones, FastCGI permite mayor seguridad y posiblemente una mejor performance
que mod_python. Para sitios pequeos, FastCGI adems puede ser ms liviano que Apache.
20.4.1.
Descripcin de FastCGI
FastCGI es una manera eciente de dejar que una aplicacin externa genere pginas para un servidor Web. El
servidor delega las peticiones Web entrantes (a travs de un socket) a FastCGI, quien ejecuta el cdigo y devuelve la
respuesta al servidor, quien, a su turno, la remitir al navegador del cliente.
Como mod_python, FastCGI permite que el cdigo permanezca en memoria, logrando que las peticiones sean
servidas sin tiempo de inicializacin. A diferencia de mod_python, un proceso FastCGI no corre dentro del proceso
del servidor Web, sino en un proceso separado y persistente.
revisin 757 del 28 de julio de 2008
233
mod_*
flup,
manejar FastCGI. Algunos usuarios han reportado pginas que explotaron con versiones antiguas de
puedes querer utilizar la ltima versin SVN. Puedes conseguir
20.4.2.
flup
en
FastCGI opera sobre un modelo cliente/servidor, y en la mayora de los casos estars iniciando el proceso servidor
FastCGI por tu cuenta. Tu servidor Web (ya sea Apache, lighttpd, o algn otro) hace contacto con tu proceso DjangoFastCGI solo cuando el servidor necesita cargar una pgina dinmica. Como el demonio ya est ejecutando su cdigo
en memoria, puede servir la respuesta muy rpido.
Nota
Si ests en un sistema de hosting compartido, probablemente ests forzado a usar procesos FastCGI
manejados por el Web server. Si ests en esta situacin, debes leer la seccin titulada Ejecutando
Django en un proveedor de Hosting compartido con Apache, ms abajo.
Un servidor Web puede conectarse a un servidor FastCGI de dos formas: usando un socket de dominio Unix, (un
named pipe en sistemas Win32) o un socket TCP. Lo que elijas es una cuestin de preferencias; usualmente un socket
TCP es ms fcil debido a cuestiones de permisos.
Para iniciar tu servidor, primero cambia al directorio de tu proyecto (donde est tu
con el comando
runfcgi:
help como nica opcin despus de runfcgi, se mostrar una lista de todas las opciones disponibles.
socket o si no host y port. Entonces, cuando congures tu servidor Web, solo necesitas
Necesitars especicar un
pidfile
en
manage.py runfcgi,
kill
de
forma:
234
donde
$PIDFILE
es el
pidfile
que especicaste.
Para reiniciar con facilidad tu demonio FastCGI en Unix, pedes usar este breve script en la lnea de comandos:
#!/bin/bash
# Replace these three settings.
PROJDIR="/home/user/myproject"
PIDFILE="$PROJDIR/mysite.pid"
SOCKET="$PROJDIR/mysite.sock"
cd $PROJDIR
if [ -f $PIDFILE ]; then
kill `cat -- $PIDFILE`
rm -f -- $PIDFILE
fi
exec /usr/bin/env - \
PYTHONPATH="../python:.." \
./manage.py runfcgi socket=$SOCKET pidfile=$PIDFILE
20.4.3.
Para usar Django con Apache y FastCGI, necesitars que Apache est instalado y congurado, con mod_fastcgi ins-
talado y habilitado. Consulta la documentacin de Apache y mod_fastcgi para instrucciones detalladas: http://www.djangoproject.co
Una vez que hayas completado la conguracin, apunta Apache a tu instancia FastCGI de Django editando el
archivo
httpd.conf
Usar la directiva
Usar
tu servidor FastCGI.
FastCGIExternalServer
socket
o un
host.
/home/user/public_html/mysite.fcgi
no necesariamente tiene que existir. Es solo una URL usada por el servidor Web internamente -- un enganche para
indicar que las consultas en esa URL deben ser manejadas por FastCGI. (Ms sobre esto en la siguiente seccin.)
FastCGIExternalServer,
mysite.fcgi
En este ejemplo, le decimos a Apache que use FastCGI para manejar cualquier consulta que no represente un
archivo del sistema de archivos y no empiece con
<VirtualHost 12.34.56.78>
ServerName example.com
DocumentRoot /home/user/public_html
Alias /media /home/user/python/django/contrib/admin/media
RewriteEngine On
RewriteRule ^/(media.*)$ /$1 [QSA,L]
revisin 757 del 28 de julio de 2008
235
FastCGI y lighttpd
Asegrate que
antes de
server.document-root = "/home/user/public_html"
fastcgi.server = (
"/mysite.fcgi" => (
"main" => (
# Use host / port instead of socket for TCP fastcgi
# "host" => "127.0.0.1",
# "port" => 3033,
"socket" => "/home/user/mysite.sock",
"check-local" => "disable",
)
),
)
alias.url = (
"/media/" => "/home/user/django/contrib/admin/media/",
)
url.rewrite-once = (
"^(/media.*)$" => "$1",
"^/favicon\.ico$" => "/media/favicon.ico",
"^(/.*)$" => "/mysite.fcgi$1",
)
Ejecutando Mltiples Sitios Django en Una Instancia lighttpd
lighttpd te permite usar conguracin condicional para permitir la conguracin personalizada para cada host.
Para especicar mltiples sitios FastCGI, solo agrega un bloque condicional en torno a tu conguracin FastCGI para
cada sitio:
fastcgi.server.
236
20.4.5.
Muchos proveedores de hosting compartido no te permiten ejecutar tus propios demonios servidores o editar el
archivo
httpd.conf.
En estos casos, an es posible ejecutar Django usando procesos iniciados por el sevidor Web.
Nota
Si ests usando procesos iniciados por el servidor Web, como se explica en esta seccin, no
necesitas iniciar el servidor FastCGI por tu cuenta. Apache iniciar una cantidad de procesos,
escalando segn lo necesite.
En el directorio raz de tu Web, agrega esto a un archivo llamado
.htaccess
mysite.fcgi,
#!/usr/bin/python
import sys, os
# Add a custom Python path.
sys.path.insert(0, "/home/user/python")
# Switch to the directory of your project. (Optional.)
# os.chdir("/home/user/myproject")
# Set the DJANGO_SETTINGS_MODULE environment variable.
os.environ['DJANGO_SETTINGS_MODULE'] = "myproject.settings"
from django.core.servers.fastcgi import runfastcgi
runfastcgi(method="threaded", daemonize="false")
Reiniciando el Server Iniciado
Si cambias cualquier cdigo Python en tu sitio, necesitars decirle a FastCGI que el cdigo ha cambiado. Pero no
hay necesidad de reiniciar Apache en este caso the. Slo volver a subir
que la fecha y hora del archivo cambien. Cuando Apache ve que el archivo ha sido actualizado, reiniciar tu aplicacin
Django por ti.
Si tienen acceso a la lnea de comandos en un sistema Unix system, puedes hacer esto fcilmente usando el comando
touch:
touch mysite.fcgi
20.5.
Escalamiento
Ahora que sabes como tener a Django ejecutando en un servidor simple, veamos como puedes escalar una instalacin
Django. Esta seccin explica como puede escalar un sitio desde un servidor nico a un cluster de gran escala que pueda
servir millones de hits por hora.
Es importante notar, sin embargo, que cada sitio grande es grande de diferentes formas, por lo que escalar es
cualquier cosa menos una operacin de una solucin nica para todos los casos. La siguiente cobertura debe ser
suciente para mostrat el principio general, y cuando sea posible, trateremos de sealar donde se puedan elegir
distintas opciones.
Primero, haremos una buena presuposicin, y hablaremos exclusivamente acerca de escalamiento bajo Apache y
mod_python. A pesar de que conocemos vario casos exitosos de desarrollos FastCGI medios y grandes, estamos mucho
ms familiarizados con Apache.
20.5. ESCALAMIENTO
20.5.1.
237
LA mayora de los sitios empiezan ejecutando en un servidor nico, con una arquitectura que se ve como en la
Figura 20-1.
Esto funciona bien para sitios pequeos y medianos, y es relativamente barato -- puedes instalar un servidor nico
diseado para Django por menos de 3,000 dlares.
Sin embargo, a medida que el trco se incemente, caers rpidamente en contencin de recursos entre las diferentes
piezas de software. Los servidores de base de datos y los servidores Web adoran tener el servidor entero para ellos, y
cuando corren en el mismo servidos siempre terminan peleando por los mismos recursos (RAM, CPU) que preeren
monopolizar.
Esto se resuelve fcilmente moviendo el servidor de base de datos a una segunda mquina, como se explica en la
siguiente seccin.
20.5.2.
En lo que tiene que ver con Django, el proceso de separar el servidor de bases de datos es extremadamente sencillo:
simplemente necesitas cambiar la conguracin de
sea una buena idea usar la IP si es posible, ya que depender de la DNS para la conexin entre el servidor Web y el
servidor de bases de datos no se recomienda.
Con un servidor de base de datos separado, nuestra arquitectura ahora se ve como en la Figura 20-2.
Aqui es donde empezamos a movernos hacia lo que usualmente se llama arquitectura n-tier. No te asustes por la
terminiloga -- slo se reere al hecho de que diferentes tiers de la pila Web separadas en diferentes mquinas fsicas.
A esta altura, si anticipas que en algn momento vas a necesitar crecer ms all de un servidor de base de datos
nico, probablemente sea una buena idea empezar a pensar en pooling de conexiones y/o replicacin de bases de datos.
Desafortunadamente, no hay suciente espacio para hacerle justicia a estos temas en este libro, as que vas a necesitar
consultar la documentacin y/o a la comunidad de tu base de datos para ms informacin.
20.5.3.
An tenemos un gran problema por delante desde la conguracin del servidor nico: el servicio de medios desde
la misma caja que maneja el contenido dinmico.
Estas dos actividades tienen su mejor performance bajo distintas circunstancias, y encerrndolas en la misma caja
terminars con que ninguna de las dos tendr particularmente buena performance. As que el siguiente paso es separar
los medios -- esto es, todo lo que no es generado por una vista de Django -- a un servidor dedicado (ver Figura 20-3).
238
20.5. ESCALAMIENTO
239
Idealmente, este servidor de medios debera correr un servidor Web desnudo, optimizado para la entrega de me-
dios estticos. lighttpd y tux (http://www.djangoproject.com/r/tux/) son dos excelentes elecciones aqu, pero un
servidor Apache bien 'pelado' tambin puede funcionar.
Para sitios pesados en contenidos estticos (fotos, videos, etc.), moverse a un servidor de medios separado es
doblemente importante y debera ser el primer paso en el escalamiento hacia arriba.
De todos modos, este paso puede ser un poco delicado. El administrador de Django necesita poder escribir medios
'subidos' en el servidor de medios. (la conguracin de
MEDIA_ROOT
medio habita en otro servidor, de todas formas necesitas organizar una forma de que esa escritura se pueda hacer a
traves de la red.
La manera ms fcil de hacer esto es usar el NFS para montar los directorios de medios del servidor de medios en
el servidor Web (o los servidores Web). Si los montas en la misma ubicacin apuntada por
MEDIA_ROOT,
el uploading
20.5.4.
A esta altura, ya hemos separado las cosas todo lo posible. Esta conguracin de tres servers debera manejar una
cantidad muy grande de trco -- nosotros servimos alrededor de 10 millones de hits por da con una arquitectura de
este tipo-- as que si creces ms all, necesitars empezar a agregar redundancia.
Actualmente, esto es algo bueno. Una mirada a la Figura 20-3 te permitir cer que si falla aunque sea uno solo
de los servidores, el sitio entero se cae. Asi que a medida que agregas servidores redundantes, no slo incrementas
capacidad, sino tambin conabilidad.
Para este ejemplo, asumamos que el primero que se ve superado en capacidad es el servidor Web. Es fcil tener
mltiples copias de un sitio Djando ejecutando en diferente hardware. -- simplemente copia el cdigo en varias mquinas,
y inicia Apache en cada una de ellas.
Sin embargo, necesitas otra pieza de software para distribuir el trco entre los servidores: un balanceador de carga.
Puedes comprar balanceadores de carga por hardware caros y propietarios, pero existen algunos balanceadores de
carga por software de alta calidad que son open source.
mod_proxy de Apache es una opcin, pero hemos encontrado que Perlbal (http://www.djangoproject.com/r/
perlbal/) es simplemente fantstico. Es un balanceador de carga y proxy inverso escrito por las mismas personas que
escribieron memcached (ver Captulo 13).
Nota
Si ests usando FastCGI, puedes realizar este mismo paso distribucin y balance de carga separando
los servidores Web front-end y los procesos FastCGI back-end en diferentes mquinas. El servidor
front-end se convierte esencialmente en el balanceador de carga, y los procesos FastCGI back-end
reemplaza a los servidores Apache/mod_python/Django.
Con los servidores Web en cluster, nuestra arquitectura en evolucin empieza a verse ms compleja, como se ve en
la Figura 20-4.
Observar que en el diagrama nos referimos a los servidores Web como el cluster para indicar que el numero de
servidores basicamente es variable. Una vez que tienes un balanceador de carga en el frente, pueder agregar y eliminar
servidores Web back-end sin perder un segundo fuera de servicio.
20.5.5.
Yendo a lo grande
r/pgpool/)
240
20.5. ESCALAMIENTO
241
242
Despus de algunas de estas iteraciones, una arquitectura de gran escala debe verse como en la Figura 20-5.
A pesar de que mostramos solo dos o tres servidores en cada nivel, no hay un lmite fundamental a cuantos puedes
agregar.
Una vez que haz llegado a este nivel, te quedan pocas opciones. El Apndice A tiene alguna informacin proveniente
de desarrolladores responsables de algunas instalaciones Django de gran escala. Si ests planicando un sitio Django
de alto trco, es una lectura recomendada.
20.6.
Ajuste de Performance
Si tienes grandes cantidades de dinero, simplemente puedes irle arrojando hardware a los problemas de escalado.
Para el resto de nosotros, sin embargo, el ajuste de performance es una obligacin.
Nota
Incidentalmente, si alguien con monstruosas cantidades de dinero est leyendo este libro, por favor
considere una donacin sustancial al proyecto Django. Aceptamos diamantes en bruto y lingotes
de oro.
Desafortunadamente, el ajuste de performance es ms un arte que una ciencia, y es aun ms dicil de escribir sobre
eso que sobre escalamiento. Si ests pensando seriamente en desplegar una aplicacin Django de gran escala, debers
pasar un un buen tiempo aprendiendo como ajustar cada pieza de tu stack.
Las siguientes secciones, sin embargo, presentan algunos tips especcos del ajuste de performance de Django que
hemos descubiero a traves de los aos.
20.6.1.
Cuando escribimos esto, la RAM realmente cara cuesta aproximadamente 200 dlares por gigabyte -- moneditas
comparado con el tiempo empleado en ajustes de performance. Compra toda la RAM que puedas, y despus compra
un poco ms.
Los procesadores ms rpidos no mejoran la performance tanto. La mayora de los servidores Web desperdician el
90 % de su tiempo esperando I/O del disco. En cuanto empieces a swappear, la performance directamente se muere.
Los discos ms rpidos pueden ayudar levemente, pero son mucho ms caros que la RAM, as que no cuentan.
Si tienes varios servidores, el primer lugar donde poner tu RAM es en el servidor de base de datos. Si puedes,
compra suciente ram como para tener toda tu base de datos en memoria. Esto no es tan difcil. La base de datos de
LJWorld.com -- que incluye medio milln de artculos desde 1989 -- tiene menos de 2 GB.
Despus, maximiza la RAM de tu servidor Web. La situacin ideal es aquella en la que ningn servidor swapea -nunca. Si llegas a ese punto, debes poder manejar la mayor parte del trco normal.
20.6.2.
Deshabilita Keep-Alive
Keep-Alive
es una caracterstica de HTTP que permite que mltiples pedidos HTTP sean servidos sobre una
20.6.3.
Usa memcached
A pesar de que Django admite varios back-ends de cache diferentes, ninguno de ellos siquiera se acerca a ser
tan rpido como memcached. Si tienes un sitio con trco alto, ni pierdas tiempo con los otros -- ve directamente a
memcached.
20.6.4.
Por supuesto, seleccionar memcached no te hace mejor si no lo usas realmente. El Captulo 13 es tu mejor amigo
aqu: aprende como usar el framework de cache de Django, y usalo en todas partes que te sea posible. Un uso de cache
agresivo y preemptico es usualmente lo nico que se puede hacer para mantener un sitio funcionando bajo el mayor
trco.
20.7. QU SIGUE?
20.6.5.
243
nete a la Conversacin
Cada pieza del stack de Django -- desde Linux a Apache a PostgreSQL o MySQL -- tiene una comunidad maravillosa
detrs. Si realmente quieres obtener ese ltimo 1 % de tus servidores, nete a las comunidades open source que estn
detrs de tu software y pide ayuda. La mayora de los miembros de la comunidad del software libre estarn felices de
ayudar.
Y tambin asegrate de unirte a la comunidad Django. Tus humildes autores son solo dos miembros de un grupo increblemente activo y creciente de desarrolladores Django. Nuestra comunidad tiene una enorme cantidad de
experiencia colectiva para ofrecer.
20.7.
Qu sigue?
Has alcanzado el nal de nuestro programa regular. Los siguientes apndices contienen material de referencia que
puedes necesitar a medida que trabajes sobre tus proyectos Django
Te deseamos la mejor de las suertes en la puesta en marcha de tu sitio Django, ya sea un pequeo juguete para t
o el prximo Google.
244
Apndice A
Casos de estudio
Para ayudar a responder las preguntas acerca de cmo funciona Django en el mundo real, hablamos (bueno, nos
escribimos) con un puado de personas que tienen sitios completos y funcionales desarrollados en Django. La mayor
parte de este apndice son sus palabras, que han sido ligeramente editadas para mayor claridad.
A.1.
Elenco
Ned Batchelder es el ingeniero principal de Tabblo.com. Tabblo comenz su vida como una herramienta
para contar historias basadas en fotos compartidas, pero recientemente fue comprado por HewlettPackard para propsitos de mayor alcance:
HP vio valor real en nuestro estilo de desarrollo web, y en la forma en que tendimos puentes
entre el mundo virtual y el mundo fsico. Nos adquirieron de modo que pudiramos llevar esa
tecnologa a otros sitios en la Web. Tabblo.com todava es un gran sitio para contar historias,
pero ahora tambin estamos trabajando en separar componentes y reutilizar las piezas ms
importantes de nuestra tecnologa.
Johannes Beigel es uno de los principales desarrolladores en Brainbot Technologies AG. El sitio
Django ms orientado al pblico de Brainbot es
David Cramer es el desarrollador principal de Curse, Inc. l desarroll Curse.com, un sitio para
devotos a los videojuegos multijugador masivos como World of Warcraft, Ultima Online, y otros.
Curse.com es uno de los sitios sobre Django ms grandes de Internet:
Tenemos aproximadamente entre 60 y 90 millones de visitas a la pgina en promedio por mes,y
tuvimos picos de ms de 130 millones de visitas (en un mes) usando Django. Somos un sitio
web muy dinmico y orientado al usuario especcamente enfocado en juegos multijugador
masivos, y uno de los sitios web ms grandes acerca de World of Warcraft globalmente.
Nuestro sitio web se estableci a principios de 2005, y desde nales de 2006 nos hemos estado
expandiendo a juegos ms all de World of Warcraft.
Christian Hammond es un ingeniero senior en VMware (un desarrollador lder de software de virtua-
246
supona que enviaran un di de los cambios a una lista de correo para ser revisado. Todo
se manejaba por email, y por supuesto, se volvi difcil seguir las revisiones que necesitaban
mayor atencin. Fue entonces que comenzamos a discutir potenciales soluciones para este
problema.
En vez de escribir mis ideas, las puse en cdigo. En poco tiempo, naci Review Board. Review
Board ayuda a los desarrolladores, contribuidores y revisores a seguir la evolucin del cdigo
propuesto a revisin y a mejorar la comunicacin entre unos y otros. En vez de hacer una vaga
referencia a una parte del cdigo en un email, el revisor puede comentar directamente sobre
el cdigo. El cdigo, junto a los comentarios, aparecer entonces en las revisiones, dando a los
desarrolladores suciente contexto para trabajar ms rpidamente en los cambios que hagan
falta.
Review Board creci rpidamente en VMware. De hecho, mucho ms rpido de lo esperado. En
unas pocas semanas, tuvimos diez equipos usando Review Board. Sin embargo, este proyecto
no es interno para VMware. Se decidi desde el da uno que debera ser open source y estar
disponible para ser usado por cualquier compaa o proyecto.
Hicimos un anuncio de open source y habilitamos el sitio conjuntamente, que est disponible en
http://www.review-board.org/.
impresionante como nuestro anuncio interno a VMware. En poco tiempo, nuestro servidor de
demostracin recibi ms de 600 usuarios, y la gente comenz a contribuir al proyecto en s.
Review Board no es la nica herramienta de revisin de cdigo del mercado, pero es la
primera que hemos visto que es abierta y tiene el extenso conjunto de caractersticas en el
que hemos trabajado para que incluya. Esperamos que esto repercuta en benecios de tiempo
para muchos proyectos (open source o no).
A.2.
Por qu Django?
Le preguntamos a cada desarrollador por qu decidi usar Django, qu otras opciones fueron consideradas, y cmo
se tom la decisin denitiva de usar Django.
Ned Batchelder :
Antes de unirme a Tabblo, Antonio Rodriguez (fundador/CTO de Tabblo) hizo una evaluacin de Rails
y Django, y encontr que ambos provean un gran ambiente de desarrollo rpido quick-out-of-the-blocks.
Comparando ambos, encontr que Django tena una mayor profundidad tcnica que hara ms fcil construir
un sitio robusto y escalable. Tambin, el que Django est basado en Python signic que tendramos toda
la riqueza del ecosistema Python para soportar nuestro trabajo. Esto denitivamente qued demostrado a
medida que construimos Tabblo.
Johannes Beigel :
Como hemos estado codicando en Python por muchos aos ya, y rpidamente comenzamos a usar el
framework Twisted, Nevow era la solucin ms natural para resolver nuestras aplicaciones web. Pero pronto
nos dimos cuenta que -- a pesar de la integracin perfecta con Twisted -- muchas cosas eran un poco
incmodas de realizar dentro de nuestros procesos de desarrollo gil.
Luego de investigar un poco en Internet, nos qued claro que Django era el framework de desarrollo web
ms prometedor para nuestros requerimientos.
Lo que nos condujo a Django fue la sintaxis de sus templates, pero pronto apreciamos todas las otras
caractersticas que estaban incluidas, y as fue que compramos rpidamente a Django.
Despus de algunos aos de desarrollo e implementacin en paralelo de sistemas (Nevow todava est
en uso para algunos proyectos en sitios de clientes), llegamos a la conclusin de que Django es mucho
menos incmodo, resultando en un cdigo mucho mejor para mantener, y que es mucho ms divertido para
trabajar.
David Cramer :
Escuch sobre Django en el verano de 2006, momento en que estabamos listos para hacer un reacondicionamiento de Curse, y decidimos investigarlo. Quedamos muy impresionado de lo que poda hacer, y todos
los aspectos donde poda ahorrarnos tiempo. Lo conversamos y al decidirnos por Django comenzamos a
escribir la tercera revisio del sitio web casi inmediatamente.
A.3. COMENZANDO
247
Christian Hammond :
Haba jugado con Django en un par de pequeos proyectos y qued muy impresionado con l. Est basado
en Python, del que soy un gran fantico, y esto lo hace fcil no slo para desarrollar sitios y aplicaciones
web, sino que tambin mantiene el trabajo organizado y mantenible. Esto siempre es un problema en PHP
y Perl. Basado en experiencias del pasado, no necesit pensar mucho para meterme con Django.
A.3.
Comenzando
Como Django es una herramienta relativamente nueva, no hay muchos desarrolladores experimentados ah afuera
que lo dominen ampliamente. Le preguntamos a nuestro panel cmo consiguieron que su equipo adquiriese velocidad
con Django y qu consejos querran compartir con nuevos desarrolladores Django.
Johannes Beigel :
Luego de programar principalmente en C++ y Perl, nos cambiamos a Python y continuamos usando C++
para el cdigo computacionalmente intensivo.
[Aprendimos Django mientras] trabajamos con el tutorial, navegando la documentacin para obtener una
idea de lo que es posible (es fcil perderse muchas caracterstica si slo se sigue el tutorial), e intentando
comprender los conceptos bsicos detrs del middleware, objetos request, modelos de base de datos, etiquetas de plantillas, ltros personalizados, los formularios, autorizacin, localizacin... Luego podramos
revisar ms profundamente esos tpicos cuando realmente los necesitramos.
David Cramer :
La documentacin del sitio web es grandiosa. Pgate a ella.
Christian Hammond :
David y yo tenamos una experiencia previa con Django, aunque era limitada. Hemos aprendido mucho
mientras desarrollbamos Review Board. Le aconsejara a los nuevos usuarios que lean la tan bien escrita
documentacin de Django y el libro que ahora estn leyendo, ya que ambos han sido inestimables para
nosotros.
No tuvimos que sobornar a Christian para conseguir esa declaracin -- lo juramos!
A.4.
Aunque Review Board y Tabblo fueron desarrollos desde cero, los otros sitios fueron portados desde cdigo ya
existente. Estbamos interesados en escuchar fue ese proceso.
Johannes Beigel :
Comenzamos a migrar el sitio desde Nevow, pero pronto nos dimos cuenta de que queramos cambiar
tantos aspectos conceptuales (tanto en la interfaz de usuario como en la parte del servidor de aplicacin)
que empezamos todo de nuevo usando el cdigo que tenamos meramente como una referencia.
David Cramer :
El sitio anterior estaba escrito en PHP. Ir de PHP a Python fue grandioso programticamente. El nico
detalle es que hay que tener mucho ms cuidado con la gestin de memoria [ya que los procesos Django
permanecen mucho ms tiempo que los procesos PHP (que son simples ciclos)].
A.5.
Ahora la pregunta del milln: Cmo los trat Django? Estabamos especialmente interesados en escuchar dnde
Django perdi fuerza -- es importante conocer en que aspectos tus armas son dbiles antes de usarlas en la barricada.
Ned Batchelder :
Django realmente nos permiti experimentar con las funcionalidades de nuestro sitio web. Tanto antes como
una startup en busca del calor de clientes y negocios, como ahora como parte de HP y trabajando con un
nmero de socios, tuvimos que ser muy giles cuando hubo que adaptar el software a nuevas demandas.
248
La separacin de la funcionalidad en modelos, vistas y controladores nos brind una modularidad que
permiti elegir apropiadamente dnde extender y modicar. El ambiente Python de trasfondo nos dio la
oportunidad de utilizar bibliotecas existentes para resolver problemas sin reinventar la rueda. PIL, PDFlib,
ZSI, JSmin, y BeautifulSoup son slo un puado de bibliotecas que agregamos para hacer algunas tareas
que eran engorrosas para nosotros.
La parte ms difcil del nuestro uso de Django ha sido la relacin entre los objetos de memoria y lo objetos
de la base de datos, de algunas maneras. Primero, el Mapeo Objeto-relacional (ORM) de Django no asegura
que dos referencias a la misma entrada en la base de datos sean el mismo objeto Python, por lo que puedes
verte en situaciones donde dos partes del cdigo intentan modicar la misma entrada y una de las copias
est anticuada. Segundo, el modelo de desarrollo de Django te anima a basar tus modelos de objetos de
datos en objetos de base de datos. A lo largo del tiempo hemos encontrado ms y ms usos de objetos de
datos que no se ajustan a la base de datos, y tenemos que migrarlos desde su naturaleza asumiendo que su
informacin se almacenar en una base.
Para una base de cdigo grande y que se utilizar por mucho tiempo, denitivamente tiene sentido gastar
tiempo estudiando las formas en que tus datos sern almacenados y accedidos, y construyendo alguna
infraestructura que soporte esas formas.
Tambin hemos agregado nuestra propia facilidad para la migracin de la base por lo que los desarrolladores
no tienen que aplicar parches SQL para mantener los actuales esquemas de base de datos funcionando. Los
desarrolladores que cambian el esquema escriben una funcin Python para actualizar la base, y eso se aplica
automticamente cuando el servidor se inicia.
Johannes Beigel :
Consideramos Django como una plataforma muy satisfactoria que encaja perfectamente con la manera
Pythonica de pensar. Casi todo simplemente funciona segn lo previsto.
Una cosa que necesit un poco de trabajo en nuestro proyecto en curso fue ajustar la conguracin del
archivo
etc), porque implementamos un sistema altamente modular y congurable, donde todas las vistas de Django
son mtodos de algunas instancias de clase. Pero con la omnipotencia del dinmico cdigo Python, fue
posible hacerlo.
David Cramer :
Gestionamos la implementacin de grandes aplicaciones de base de datos en un n de semana. Esto nos
hubiera llevado una o dos semanas hacerlo en el sitio web previo, en PHP. Django ha brillado exactamente
donde queramos que lo haga.
Ahora, aunque Django es una gran plataforma, es evidente que no est construido para las necesidades
especicas que cualquiera necesite. Al tiempo del lanzamiento inicial del sitio web sobre Django, tuvimos
nuestro mayor trco mensual del ao, y no podamos continuar. Durante los meses siguientes ajustamos
algunos detalles, mayormente el hardware y el software que serva las peticiones a Django. Esto incluy
modicaciones de nuestra conguracin de hardware, optimizacin de Django, y perfeccionar el software
servidor que usbamos, que en ese entonces era lighttpd y FastCGI.
En mayo de 2007, Blizzard (los creadores de World of Warcraft) lanzaron otro parche bastante grande,
como el que haban lanzado en diciembre cuando nuestro sitio fue lanzado en Django. La primer cosa que
pas por nuestras cabezas fue, hey, si soportamos el aluvin de diciembre, esto de ninguna manera puede
ser tan grande, deberamos estar bien. Perdimos cerca de 12 horas antes de que los servidores comenzaran
a sentir el calor. La pregunta surgi de nuevo: Realmente era Django la mejor solucin para lo que nosotros
queramos lograr?
Gracias a todo el gran apoyo de la comunidad, y largas noches, pudimos implementar varios arreglos en
caliente sobre el sitio durante esos das. Los cambios introducidos (que con suerte estarn incorporados
a Django en el momento que este libro vea la luz) permiten que con completa tranquilidad, aquellos (no
cualquiera) que tengan que lidiar con 300 peticiones web por segundo, puedan hacerlo, con Django.
Christian Hammond :
Django nos permiti construir Review Board bastante rpidamente forzndonos a estar organizados a travs
de la separacin de URL, vistas y plantillas, y proveyndonos tiles componentes listos para usar, como
la aplicacin de autenticacin, cacheo, y la abstraccin de base de datos. La mayor parte de esto funcion
realmente bien para nosotros.
revisin 757 del 28 de julio de 2008
249
Siendo un aplicacin web dinmica, tuvimos que escribir un montn de cdigo JavaScript. Esta es una rea
en la que Django no ha podido ayudarnos realmente mucho. El soporte que provee Django para el uso de
plantillas, etiquetas, ltros y formularios son grandiosos, pero no son fcilmente utilizables desde cdigo
JavaScript. Hay veces que quisiramos usar una plantilla en particular o un ltro, pero no hay manera
de usarlo desde JavaScript. Personalmente me gustara ver que se incorporen a Django algunas soluciones
creativa para esto.
A.6.
Estructura de Equipo
A menudo, los proyectos son exitosos gracias a sus equipos, y no a tecnologa elegida. Consultamos a nuestro panel
sobre sus equipos de trabajo, y qu herramientas y tcnicas utilizan para permanecer en carrera.
Ned Batchelder :
Somos un ambiente de Startup Web bastante estndar: Trac/SVN, cinco desarrolladores. Tenemos un
servidor de desarrollo, un servidor de produccin, un script desarrollado ad hoc, y as.
Ah, y amamos Memcached.
Johannes Beigel :
Usamos Trac como nuestro bug tracker y wiki, y recientemente reemplazamos Subversion+SVK por Mercurial (un sistema de control de versiones distribuido escrito en Python que maneja la ramicacin y fusin
con encanto)
Pienso que tenemos un proceso de desarrollo muy gil, pero no seguimos una metodologa rgida como
Extreme Programming (aunque tomamos prestadas muchas ideas de ah). Somos ms bien programadores
pragmticos.
Tenemos un sistema de construccin automatizada (personalizado pero basado en SCons), y pruebas unitarias para casi todo.
David Cramer :
Nuestro equipo consiste en cuatro desarrolladores web, todos trabajando en la misma ocina de modo que
es bastante fcil comunicarse. Nos basamos en herramientas comunes como SVN y Trac.
Christian Hammond :
Review Board tiene actualmente dos desarrolladores principales (David Trowbridge y yo) y un par de
contribuidores. Estamos hospedados en Google Code y usamos su repositorio Subversion, issue tracker,
y wiki. De hecho, usamos Review Board para revisar nuestros cambios antes de incorporarlos. Hacemos
pruebas en nuestras computadores locales, tanto manualmente como por pruebas de unidad. Nuestros
usuarios en VMware que usan Review Board todos los das nos proveen de un montn de feedback til y
reportes de errores, que intentamos incorporar en el programa.
A.7.
Implementacin
Los desarrolladores de Django toman la facilidad de implementacin y escalamiento muy seriamente, por lo que
siempre estamos interesados en escuchar sobre ensayos y tribulaciones del mundo real.
Ned Batchelder :
Hemos usado cacheo tanto en la capa de consulta como de respuesta para agilizar los tiempos de respuesta.
Tenemos una conguracin clsica: un multiplexor, varios servidores de aplicacin, un servidor de base de
datos. Eso ha funcionado bien para nosotros, porque podemos usar cacheo sobre el servidor de aplicacin
para evitar el acceso a la base de datos, y luego agregar tantos servidores de aplicacin como necesitemos
para manejar la demanda.
Johannes Beigel :
Servidores Linux, preferentemente Debian, con muchos gigas de RAM. Lighttpd como servidor Web, Pound
como front-end HTTPS y balanceador de carga si se necesita, y Memcached como sistema de cach. SQLite
para pequeas bases de datos, Postgres si los datos crecen mucho, y cosas altamente especializadas de base
de datos para nuestros componentes de bsqueda y de gestin de conocimiento.
revisin 757 del 28 de julio de 2008
250
David Cramer :
Nuestra estructura todava est para debatirse... (pero es esto actualmente):
Cuando un usuario solicita el sitio se lo enva a un cluster de servidores Squid usando Lighttpd. All, los
servidores verican si el usuario est registrado en el sistema. Si no lo est, se le sirve una pgina cacheada.
Un usuario autenticado es reenviado a un cluster de servidores corriendo Apache2 con mod_python (cada
uno con una gran cantidad de memoria), donde luego cada uno hace uso de en un sistema Memcached
distribuido y un bestial servidor de base de datos MySQL. Los datos estticos, como archivos grandes o
videos, (actualmente) estan hospedados en un servidor corriendo una instalacin mnima de Django usando
lighttpd con fastcgi. Ms adelante, migraremos todos esos datos a un servicio similar al S3 de Amazon.
Christian Hammond :
Hay dos servidores de produccin en este momento. Uno est en VMware y consiste en una maquina virtual
Ubuntu corriendo en VMware ESX. Usamos MySQL para la base de datos, Memcached para nuestro backend de cacheo, y actualmente Apache para el servidor Web. Tenemos varios servidores potentes que pueden
escalarse cuando lo requiramos. Tambin podemos mudar MySQL o Memcached a otra maquina virtual a
medida que nuestra base de usuarios crece.
El segundo servidor de produccin es el de Review Board mismo. La conguracin es casi idntica al
anterior, excepto que la maquina virtual se basa en VMware Server.
Block quote ends without a blank line; unexpected unindent.
Apndice B
http://www.djangoproject.com/documentation/0.96/model-api/.
B.1.
Campos
/0.96? /
class Example(models.Model):
pass = models.IntegerField() # 'pass' es una palabra reservada!
2. Un nombre de campo no puede contener dos o ms guiones bajos consecutivos, debido a la forma en que trabaja la sintaxis de las consultas de
bsqueda de , por ejemplo:
class Example(models.Model):
foo__bar = models.IntegerField() # 'foo__bar' tiene dos guiones bajos!
Estas limitaciones se pueden manejar sin mayores problemas, dado que el nombre del campo
no necesariamente tiene que coincidir con el nombre de la columna en la base de datos. Ver
db_column, ms abajo.
Las palabras reservadas de SQL, como
campo, dado que Django escapea todos los nombres de tabla y columna de la base de datos
en cada consulta SQL subyacente. Utiliza la sintaxis de quoteo del motor de base de datos
particular.
Cada campo en tu modelo debe ser una instancia de la clase de campo apropiada. Django usa los tipos de clase
Field
INTEGER, VARCHAR).
<select>).
<input type="text">,
252
B.1.1.
Un
AutoField
IntegerField
que se incrementa automticamente de acuerdo con los IDs disponibles. Normalmente no nece-
sitars utilizarlos directamente; se agrega un campo de clave primaria automticamente a tu modelo si no especicas
una clave primaria.
B.1.2.
BooleanField
Un campo Verdadero/Falso.
B.1.3.
CharField
Un campo string, para cadenas cortas o largas. Para grandes cantidades de texto, usa
CharField
max_length,
TextField.
B.1.4.
CommaSeparatedIntegerField
B.1.5.
CharField,
se requiere el argumento
max_length.
DateField
Un campo de fecha.
DateField
Argumento
auto_now
Descripcin
Asigna automticamente al campo un valor igual al momento en que se
salva el objeto. Es til para las marcas de tiempo ltima modicacin.
Observar que siempre se usa la fecha actual; no es un valor por omisin
que se pueda sobreescribir.
auto_now_add
B.1.6.
DateTimeField
B.1.7.
Un
DateField.
EmailField
CharField
que chequea que el valor sea una direccin de email vlida. No acepta
max_length;
su
max_length
B.1.8.
FileField
Argumento
upload_to
Descripcin
Una ruta del sistema de archivos local que se agregar a la conguracin
strftime
(ver
http://www.djangoproject.com/r/python/strftime/),
que
ser reemplazada por la fecha y hora del upload del archivo (de manera que los archivos subidos no llenen el directorio
B.1. CAMPOS
dada).
El uso de un
253
FileField
o un
ImageField
MEDIA_ROOT
al directorio donde quieras que Django almacene los archivos subidos. (Por performance, estos
archivos no se almacenan en la base de datos.) Denir
directorio. Asegurarse de que la cuenta del usuario del servidor web tenga permiso de escritura
en este directorio.
2. Agregar el
FileField
ImageField
MEDIA_ROOT
upload_to
MEDIA_ROOT).
get_<fieldname>_url provista por Django.
Por ejemplo, digamos que tu MEDIA_ROOT es '/home/media', y upload_to es 'photos/ %Y/ %m/ %d'. La parte
' %Y/ %m/ %d' de upload_to es formato strftime; ' %Y' es el ao en cuatro dgitos, ' %m' es el mes en dos digitos, y ' %d'
es el da en dos dgitos. Si subes un archivo el 15 de enero de 2007, ser guardado en /home/media/photos/2007/01/15.
Si quieres recuperar el nombre en disco del archivo subido, o una URL que se reera a ese archivo, o el tamao del
archivo, puedes usar los mtodos
get_FIELD_filename(), get_FIELD_url(),
get_FIELD_size().
Ver el Apndice
Nota
Cualquiera sea la forma en que manejes tus archivos subidos, tienes que prestar mucha atencin
a donde los ests subiendo y que tipo de archivos son, para evitar huecos en la seguridad. Valida
todos los archivos subidos para asegurarte que esos archivos son lo que piensas que son.
Por ejemplo, si dejas que cualquiera suba archivos ciegamente, sin validacin, a un directorio que
est dentro de la raz de documentos (document root ) de tu servidor web, alguien podra subir
un script CGI o PHP y ejecutarlo visitando su URL en tu sitio. No permitas que pase!
B.1.9.
FilePathField
Un campo cuyas opciones estn limitadas a los nombres de archivo en un cierto directorio en el sistema de archivos.
Tiene tres argumentos especiales, que se muestran en la Tabla B-3.
Cuadro B.3: Opciones extra de FilePathField
Argumento
Descripcin
path
match
FilePathField
"/home/images").
FilePathField usar para
ltrar los nombres de archivo. Observar que la regex ser aplicada al nombre
recursive
match
/home/images/foo.gif
bar.gif).
pero no con
/home/images/foo/bar.gif
porque el
match
se aplica al
254
B.1.10.
FloatField
Argumento
descripcin
max_digits
decimal_places
Por ejemplo, para almacenar nmeros hasta 999 con una resolucin de dos decimales, hay que usar:
ImageField
FileField, pero valida que el objeto subido sea una imagen vlida.
height_field y width_field, que si se utilizan, sern auto-rellenados con
Similar a
extra,
B.1.12.
IntegerField
Un entero.
B.1.13.
IPAddressField
B.1.14.
NullBooleanField
Similar a
null=True.
B.1.15.
Un
"24.124.1.30").
BooleanField,
pero permite
None/NULL
BooleanField
con
PhoneNumberField
CharField
que chequea que el valor es un telfono vlido estilo U.S. (en formato
XXX-XXX-XXXX).
Nota
Si
necesitas
representar
django.contrib.localflavor
telfonos
para
ver
de
si
otros
ya
estn
pases,
incluidas
consulta
las
el
deniciones
paquete
para
tu
pas.
B.1.16.
PositiveIntegerField
IntegerField,
Similar a
B.1.17.
PositiveSmallIntegerField
Similar a
PositiveIntegerField,
pero solo permite valores por debajo de un lmite. El valor mximo permitido
para estos campos depende de la base de datos, pero como las bases de datos tienen un tipo entero corto de 2 bytes,
el valor mximo positivo usualmente es 65,535.
revisin 757 del 28 de julio de 2008
B.1.18.
255
SlugField
Slug es un trmino de la prensa. Un slug es una etiqueta corta para algo, que contiene solo letras, nmeros,
guiones bajos o simples. Generalmente se usan en URLs.
De igual forma que en
CharField,
puedes especicar
max_length.
Si
max_length
SlugField
implica
db_index=True
datos.
SlugField
prepopulate_from,
models.SlugField(prepopulate_from=("pre_name", "name"))
prepopulate_from
B.1.19.
no acepta nombres
DateTimeField
como argumentos.
SmallIntegerField
Similar a
IntegerField, pero solo permite valores en un cierto rango dependiente de la base de datos (usualmente
-32,768 a +32,767).
B.1.20.
TextField
B.1.21.
TimeField
B.1.22.
DateField
DateTimeField.
URLField
verify_exists
es
True
URLField
toma el argumento
max_length.
omisin es 200.
B.1.23.
USStateField
Nota
Si
necesitas
representar
django.contrib.localflavor
otros
pases
estados,
busca
en
el
paquete
zacin.
B.1.24.
Un
XMLField
TextField que chequea que el valor sea un XML vlido que matchea con un esquema dado. Tiene un argumento
schema_path, que es la ruta en el sistema de archivos a un esquema RELAX NG (http://www.relaxng.
requerido,
org/)
Requiere
B.2.
jing (http://thaiopensource.com/relaxng/jing.html)
Los siguientes argumentos estn disponibles para todos los tipos de campo. Todos son opcionales.
256
B.2.1.
null
Si est en
True,
NULL
False.
NULL. Utiliza null=True
Observar que los valores de string nulo siempre se almacenan como strings vacos, no como
solo para campos no-string, como enteros, booleanos y fechas. En los dos casos, tambin necesitars establecer
blank=True
null
null
sin datos:
NULL y el string
NULL.
string vaco, no
B.2.2.
blank
False.
null. null solo se relaciona con la base de datos, mientras que blank est
relacionado con la validacin. Si un campo tiene blank=True, la validacin del administrador de Django permitir la
entrada de un valor vaco. Si un campo tiene blank=False, es un campo requerido.
Si est en
True,
B.2.3.
choices
Un iterable (ej.: una lista, tupla, o otro objeto iterable de Python) de dos tuplas para usar como opciones para
este campo.
Si esto est dado,la interfaz de administracin de Django utilizar un cuadro de seleccin en lugar del campo de
texto estndar, y limitar las opciones a las dadas.
Una lista de opciones se ve as:
YEAR_IN_SCHOOL_CHOICES = (
('FR', 'Freshman'),
('SO', 'Sophomore'),
('JR', 'Junior'),
('SR', 'Senior'),
('GR', 'Graduate'),
)
El primer elemento de cada tupla es el valor actual a ser almacenado. El segundo elemento es el nombre legible por
humanos para la opcin.
La lista de opciones puede ser denida tambin como parte de la clase del modelo:
class Foo(models.Model):
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)
o fuera de la clase del modelo:
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
class Foo(models.Model):
gender = models.CharField(maxlength=1, choices=GENDER_CHOICES)
Para cada campo del modelo que tenga establecidas
legible por humanos para el valor actual del campo. Ver Apndice C para ms detalles.
B.2.4.
257
db_column
El nombre de la columna de la base de datos a usar para este campo. Si no est dada, Django utilizar el nombre
del campo. Esto es til cuando ests deniendo un modelo sobre una base de datos existente.
Si tu nombre de columna de la base de datos es una palabra reservada de SQL, o contiene caracteres que no estn
permitidos en un nombre de variable de Python (en particular el guin simple), no hay problema. Django quotea los
nombres de columna y tabla detrs de la escena.
B.2.5.
db_index
Si est en
ndice en la base de datos para esta columna cuando cree la tabla (es decir,
cuando ejecute
B.2.6.
default
B.2.7.
Si es
editable
False, el campo no ser editable en la interfaz de administracin o via procesamiento de formularios. El valor
True.
por omisin es
B.2.8.
help_text
Texto de ayuda extra a ser mostrado bajo el campo en el formulario de administracin del objeto. Es til como
documentacin aunque tu objeto no tenga formulario de administracin.
B.2.9.
Si es
primary_key
True,
Su no se especica
primary_key=True
campo:
id = models.AutoField('ID', primary_key=True)
Por lo tanto, no necesitas establecer
primary_key=True
primary_key=True
implica
blank=False, null=False,
unique=True.
objeto.
B.2.10.
radio_admin
Por omisin,el administrador de Django usa una interfaz de cuadro de seleccin (<select>) para campos que son
ForeignKey
o tienen
choices.
Si
radio-button en su lugar.
B.2.11.
Si es
unique
True,
B.2.12.
unique_for_date
DateField
DateTimeField
class Story(models.Model):
pub_date = models.DateTimeField()
slug = models.SlugField(unique_for_date="pub_date")
...
En este cdigo, Django no permitir la creacin de dos historias con el mismo slug publicados en la misma fecha.
Esto diere de usar la restriccin
unique_together
no importa.
revisin 757 del 28 de julio de 2008
pub_date;
la hora
258
B.2.13.
unique_for_month
Similar a
B.2.14.
pero requiere que el campo sea nico con respecto al mes del campo dado.
unique_for_year
Similar a
B.2.15.
unique_for_date,
unique_for_date
unique_for_month,
verbose_name
ForeignKey, ManyToManyField,
OneToOneField,
sicional opcional -- un nombre descriptivo. Si el nombre descriptivo no est dado, Django lo crear automticamente
usando el nombre de atributo del campo, convirtiendo guiones bajos en espacios.
En este ejemplo, el nombre descriptivo es
"first name":
first_name = models.CharField(maxlength=30)
ForeignKey, ManyToManyField, y OneToOneField requieren que el primer argumento sea una clase del modelo, en
verbose_name como argumento con nombre:
B.3.
Relaciones
Es claro que el poder de las bases de datos se basa en relacionar tablas entre s. Django ofrece formas de denir
los tres tipos de relaciones ms comunes en las bases de datos: muchos-a-uno, muchos-a-muchos, y uno-a-uno.
Sin embargo, la semntica de las relaciones uno-a-uno esta siendo revisada mientras se imprime este libro, as que
no se cubren en esta seccin. Consulte en la documentacin on-line la informacin ms actualizada.
B.3.1.
Relaciones Muchos-a-Uno
ForeignKey.
Field:
incluyndolo
ForeignKey
Car tiene
Manufacturer --
Car
tiene solo un
un
Manufacturer
-- es decir, un
Manufacturer
class Manufacturer(models.Model):
...
class Car(models.Model):
manufacturer = models.ForeignKey(Manufacturer)
...
Para crear una relacin recursiva -- un objeto que tiene una relacin muchos-a-uno con l mismo -- usa
models.ForeignKey('self
class Employee(models.Model):
manager = models.ForeignKey('self')
Si necesitas crear una relacin con un modelo que an no se ha denido, puedes usar el nombre del modelo en lugar
del objeto modelo:
B.3. RELACIONES
259
class Car(models.Model):
manufacturer = models.ForeignKey('Manufacturer')
...
class Manufacturer(models.Model):
...
Observar que de todas formas solo puedes usar strings para hacer referencia a modelos dentro del mismo archivo
models.py -- no puedes usar un string para hacer referencia a un modelo en una aplicacin diferente, o hacer referencia
a un modelo que ha sido importado de cualquier otro lado.
Detrs de la escena, Django agrega
"_id"
manufacturer_id.
db_column;
Car,
db_column.) De todas formas, tu cdigo nunca debe utilizar el nombre de la columna de la base de datos, salvo que
escribas tus propias SQL. Siempre te manejars con los nombres de campo de tu objeto modelo.
Se sugiere, pero no es requerido, que el nombre de un campo
ForeignKey (manufacturer
en el ejemplo) sea el
nombre del modelo en minsculas. Por supuesto, puedes ponerle el nombre que quieras. Por ejemplo:
class Car(models.Model):
company_that_makes_it = models.ForeignKey(Manufacturer)
# ...
Los campos
ForeignKey
reciben algunos argumentos extra para denir como debe trabajar la relacin (ver Tabla
Argumento
edit_inline
Descripcin
Si no es
False,
relacionado. Esto signica que el objeto no tendr su propia interfaz de administracin. Usa
models.TABULAR
models.STACKED,
editables inline se muestran como una tabla o como una pila de conjuntos de
campos, respectivamente.
limit_choices_to
datetime
anterior a la fe-
consultas ms complejas.
No es compatible con
max_num_in_admin
edit_inline.
min_num_in_admin
La cantidad mnima de objetos relacionados que se muestran en la interfaz de administracin. Normalmente, en el momento de la creacin se muestran
tran
num_in_admin objetos
num_extra_on_change
min_num_in_admin
num_extra_on_change
objetos relacionados.
260
Argumento
Descripcin
num_in_admin
raw_id_admin
related_name
edit_inline.
to_field
B.3.2.
Relaciones Muchos-a-Muchos
ManyToManyField.
Al igual que
Pizza
Pizza
Topping
-- es decir, un
Topping
ForeignKey, ManyToManyField
puede estar en mltiples pizzas
class Topping(models.Model):
...
class Pizza(models.Model):
toppings = models.ManyToManyField(Topping)
...
Como sucede con
ForeignKey,
'self'
en
lugar del nombre del modelo, y puedes hacer referencia a modelos que todava no se denieron usando un string que
contenga el nombre del modelo. De todas formas solo puedes usar strings para hacer referencia a modelos dentro del
mismo archivo
models.py
-- no puedes usar un string para hacer referencia a un modelo en una aplicacin diferente,
ManyToManyField (toppings,
en el ejemplo) sea un
ManyToManyField,
en los dos.
Topping
tenga
pizzas ManyToManyField
) porque es ms
(toppings) que pensar que un ingrediente est en muchas pizzas. En la forma en que est congurado el ejemplo, el
formulario de administracin de laPizza permitir que los usuarios selecciones los ingredientes.
Los objetos
ManyToManyField
toman algunos argumentos extra para denir como debe trabajar la relacin (ver
Argumento
related_name
Descripcin
El nombre a utilizar para la relacin desde el objeto relacionado hacia este
objeto. Ver Apndice C para ms informacin.
filter_interface
limit_choices_to
Ver la descripcin en
ForeignKey.
261
Argumento
Descripcin
symmetrical
ManyToManyField
el siguiente modelo:
class Person(models.Model):
friends = models.ManyToManyField("self")
ManyToManyField
person_set a la clase
ManyToManyField es simtrico --
Person.
symmetrical
en
False.
ManyToMany
db_table
con
self,
establece
ManyToMany
sean asimtricas.
El nombre de la tabla a crear para almacenar los datos de la relacin muchosa-muchos. Si no se provee, Django asumir un nombre por omisin basado en
los nombres de las dos tablas a ser vinculadas.
B.4.
class Meta
class Book(models.Model):
title = models.CharField(maxlength=100)
class Meta:
# model metadata options go here
...
Los metadatos del modelo son cualquier cosa que no sea un campo, como opciones de ordenamiento, etc.
Las secciones que siguen presentan una lista de todas las posibles
requerida. Agregar
B.4.1.
class Meta
Meta
db_table
class Book
books
manage.py startapp
-- con el
(creada por
class Book(models.Model):
...
class Meta:
db_table = 'things_to_read'
Si no se dene, Django utilizar
para ms informacin.
Si tu nombre de tabla de base de datos es una palabra reservada de SQL, o contiene caracteres que no estn
permitidos en los nombres de variable de Python (especialmente el guin simple), no hay problema. Django quotea los
nombres de tabla y de columna detrs de la escena.
262
B.4.2.
get_latest_by
El nombre de un
mtodo
latest()
DateField o DateTimeField
Manager del modelo.
del
class CustomerOrder(models.Model):
order_date = models.DateTimeField()
...
class Meta:
get_latest_by = "order_date"
Ver el Apndice C para ms informacin sobre el mtodo
B.4.3.
latest().
order_with_respect_to
Marca este objeto como ordenable con respecto al campo dado. Esto se utiliza casi siempre con objetos relacionados para permitir que puedan ser ordenados respecto a un objeto padre. Por ejemplo, si una
un objeto
Question,
Answer
se relaciona a
y una pregunta tiene ms de una respuesta, y el orden de las respuestas importa, hars esto:
class Answer(models.Model):
question = models.ForeignKey(Question)
# ...
class Meta:
order_with_respect_to = 'question'
B.4.4.
ordering
El ordenamiento por omisin del objeto, utilizado cuando se obtienen listas de objetos:
class Book(models.Model):
title = models.CharField(maxlength=100)
class Meta:
ordering = ['title']
-, que indica orden
"?" para ordenar al
Esto es una tupla o lista de strings. Cada string es un nombre de campo con un prejo opcional
descendiente. Los campos sin un
azar.
Por ejemplo, para ordenar por un campo
title
ordering = ['title']
Para ordenar por
title
ordering = ['-title']
Para ordenar por
title
author
B.4.5.
ordering,
permissions
Permisos extra para almacenar en la tabla de permisos cuando se crea este objeto. Se crean automticamente
permisos para agregar, eliminar y cambiar para cada objeto que tenga establecida la opcin
especica un permiso extra,
can_deliver_pizzas:
admin.
Este ejemplo
B.5. MANAGERS
263
class Employee(models.Model):
...
class Meta:
permissions = (
("can_deliver_pizzas", "Can deliver pizzas"),
)
Esto es una lista o tupla de dos tuplas de la forma
(permission_code, human_readable_permission_name).
B.4.6.
unique_together
class Employee(models.Model):
department = models.ForeignKey(Department)
extension = models.CharField(maxlength=10)
...
class Meta:
unique_together = [("department", "extension")]
Esto es una lista de listas de campos que deben ser nicos cuando se consideran juntos. Es usado en la interfaz de
administracin de Django y se refuerza a nivel de base de datos (esto es, se incluyen las sentencias
en la sentencia
B.4.7.
CREATE TABLE).
UNIQUE apropiadas
verbose_name
class CustomerOrder(models.Model):
order_date = models.DateTimeField()
...
class Meta:
verbose_name = "order"
Si no se dene, Django utilizar una versin adaptada del nombre de la clase, en la cual
en
camel case.
B.4.8.
CamelCase
se convierte
verbose_name_plural
class Sphynx(models.Model):
...
class Meta:
verbose_name_plural = "sphynges"
Si no se dene, Django agregar una s al nal del
B.5.
Un
verbose_name.
Managers
Manager
es la interfaz a travs de la cual se proveen las operaciones de consulta de la base de datos a los
264
B.5.1.
Nombres de Manager
objects
Manager
llamado
objects
models.Manager()
Manager
objects
para el
Manager,
puedes
B.5.2.
objects),
pero
no
Managers Personalizados
Puedes utilizar un
ciando tu
Manager
Manager
personalizado en tu modelo.
QuerySet
Manager.
Manager:
Manager
e instan-
Manager,
y/o
Manager
(Para funcionalidad a nivel de registro -- esto es, funciones que actan sobre una instancia simple de un objeto modelo
Manager personalizados .)
Manager personalizado puede retornar cualquier cosa que necesites. No tiene que retornar un QuerySet.
ejemplo, este Manager personalizado ofrece un mtodo with_counts(), que retorna una lista de todos los
OpinionPoll, cada uno con un atributo extra num_responses que es el resultado de una consulta agregada:
B.5. MANAGERS
265
num_responses.
QuerySet
base de un
Manager
devuelve todos los objetos en el sistema. Por ejemplo, usando este modelo:
class Book(models.Model):
title = models.CharField(maxlength=100)
author = models.CharField(maxlength=50)
Book.objects.all() retornar todos los libros de la base de datos.
QuerySet base, sobreescribiendo el mtodo Manager.get_query_set(). get_query_set()
un QuerySet con las propiedades que tu requieres.
la sentencia
Puedes sobreescribir el
debe retornar
Por ejemplo, el siguiente modelo tiene dos managers -- uno que devuelve todos los objetos, y otro que retorna solo
los libros de Roald Dahl:
puedes usar
filter(), exclude(),
y todos
todas legales:
Book.dahl_objects.all()
Book.dahl_objects.filter(title='Matilda')
Book.dahl_objects.count()
Este ejemplo tambin seala otra tcnica interesante: usar varios managers en el mismo modelo. Puedes agregar
tantas instancias de
Manager()
como quieras. Esta es una manera fcil de denir lters comunes para tus modelos.
class MaleManager(models.Manager):
def get_query_set(self):
return super(MaleManager, self).get_query_set().filter(sex='M')
class FemaleManager(models.Manager):
def get_query_set(self):
return super(FemaleManager, self).get_query_set().filter(sex='F')
class Person(models.Model):
first_name = models.CharField(maxlength=50)
last_name = models.CharField(maxlength=50)
sex = models.CharField(maxlength=1, choices=(('M', 'Male'), ('F', 'Female')))
people = models.Manager()
men = MaleManager()
women = FemaleManager()
266
Person.men.all(), Person.women.all(),
Person.people.all(),
con los
resultados predecibles.
Manager personalizados, toma nota que el primer Manager que encuentre Django (en el orden en el
Manager denido en una clase
como el Manager por omisin. Ciertas operaciones -- como las del sitio de administracin de Django -- usan el Manager
por omisin para obtener listas de objetos, por lo que generalmente es una buena idea que el primer Manager est
relativamente sin ltrar. En el ltimo ejemplo, el manager people est denido primero -- por lo cual es el Manager
Si usas objetos
que estn denidos en el modelo) tiene un status especial. Django interpreta el primer
por omisin.
B.6.
Mtodos de Modelo
Dene mtodos personalizados en un modelo para agregar funcionalidad personalizada a nivel de registro para tus
objetos. Mientras que los mtodos
Manager
estn pensados para hacer cosas a nivel de tabla, los mtodos de modelo
class Person(models.Model):
first_name = models.CharField(maxlength=50)
last_name = models.CharField(maxlength=50)
birth_date = models.DateField()
address = models.CharField(maxlength=100)
city = models.CharField(maxlength=50)
state = models.USStateField() # Yes, this is America-centric...
def baby_boomer_status(self):
"""Returns the person's baby-boomer status."""
import datetime
if datetime.date(1945, 8, 1) <= self.birth_date <= datetime.date(1964, 12, 31):
return "Baby boomer"
if self.birth_date < datetime.date(1945, 8, 1):
return "Pre-boomer"
return "Post-boomer"
def is_midwestern(self):
"""Returns True if this person is from the Midwest."""
return self.state in ('IL', 'WI', 'MI', 'IN', 'OH', 'IA', 'MO')
@property
def full_name(self):
"""Returns the person's full name."""
return ' %s %s' % (self.first_name, self.last_name)
El ltimo mtodo en este ejemplo es una propiedad -- un atributo implementado por cdigo getter/setter personalizado. Las propiedades son un truco ingenioso agregado en Python 2.2; puedes leer ms acerca de ellas en
http://www.python.org/download/releases/2.2/descrintro/#property.
Existen tambin un puado de mtodos de modelo que tienen un signicado especial para Python o Django.
Estos mtodos se describen en las secciones que siguen.
B.6.1.
__str__
__str__()
es un mtodo mgico de Python que dene lo que debe ser devuelto si llamas a
str(obj)
(o la funcin relacionada
unicode(obj),
str()
sobre el
particularmente como el valor mostrado para hacer el render de un objeto en el sitio de administracin de Django y
como el valor insertado en un plantilla cuando muestra un objeto. Por eso, siempre debes retornar un string agradable
y legible por humanos en el
__str__
class Person(models.Model):
revisin 757 del 28 de julio de 2008
267
first_name = models.CharField(maxlength=50)
last_name = models.CharField(maxlength=50)
def __str__(self):
return ' %s %s' % (self.first_name, self.last_name)
B.6.2.
get_absolute_url
Dene un mtodo
get_absolute_url()
def get_absolute_url(self):
return "/people/ %i/" % self.id
Django usa esto en la interfaz de administracin. Si un objeto dene
get_absolute_url(),
la pgina de edi-
cin del objeto tendr un enlace View on site, que te llevar directamente a la vista pblica del objeto, segn
get_absolute_url().
Tambin un par de otras partes de Django, como el framework de sindicacin de feeds, usan
get_absolute_url()
como facilidad para recompensar a las personas que han denido el mtodo.
Es una buena prctica usar
get_absolute_url()
DRY: la URL de este objeto de dene dos veces, en el archivo URLconf y en el modelo.
Adems puedes desacoplar tus modelos de el URLconf usando el decorator
permalink.
funcin de view, una lista de parmetros posicionales, y (opcionalmente) un diccionario de parmetros por nombre.
Django calcula la URL completa correspondiente usando el URLconf, sustituyendo los parmetros que le has pasado
en la URL. Por ejemplo, si tu URLconf contiene una lnea como sta:
(r'^people/(\d+)/$', 'people.views.details'),
tu modelo puede tener un mtodo
get_absolute_url
como ste:
@models.permalink
def get_absolute_url(self):
return ('people.views.details', [str(self.id)])
En forma similar, si tienes una entrada en URLconf que se ve como esta:
(r'/archive/(?P<year>\d{4})/(?P<month>\d{1,2})/(?P<day>\d{1,2})/$', archive_view)
puedes hacer referencia a la misma usando
permalink()
como sigue:
@models.permalink
def get_absolute_url(self):
return ('archive_view', (), {
'year': self.created.year,
'month': self.created.month,
'day': self.created.day})
Observar que especicamos una secuencia vaca para el segundo argumento en este caso, porque slo queremos
pasar argumentos por clave, no argumentos por nombre.
De esta forma, ests ests ligando la URL absoluta del modelo a la vista que se utiliza para mostrarla, sin repetir
la informacin de la URL en ningn lado. An puedes usar el mtodo
get_absolute_url
268
B.6.3.
Sintete libre de escribir sentencias SQL personalizadas en mtodos personalizados de modelo y mtodos a nivel
django.db.connection representa la conexin actual a la base de datos. Para usarla, invoconnection.cursor() para obtener un objeto cursor. Despus, llama a cursor.execute(sql, [params]) para
ejecutar la SQL, y cursor.fetchone() o cursor.fetchall() para devolver las las resultantes:
de mdulo. El objeto
ca
def my_custom_sql(self):
from django.db import connection
cursor = connection.cursor()
cursor.execute("SELECT foo FROM bar WHERE baz = %s", [self.baz])
row = cursor.fetchone()
return row
connection y cursor implementan en su mayor parte la DB-API estndar de Python (http://www.python.
org/peps/pep-0249.html). Si no ests familiarizado con la DB-API de Python, observa que la sentencia SQL en
cursor.execute() usa placeholders, " %s", en lugar de agregar los parmetros directamente dentro de la SQL. Si usas
esta tcnica, la biblioteca subyacente de base de datos automticamente agregar comillas y secuencias de escape a
" %s", no
tus parmetros segn sea necesario. (Observar tambin que Django espera el placeholder
el placeholder
"?",
que es utilizado por los enlaces Python a SQLite. Python bindings. Esto es por consistencia y salud mental).
Una nota nal: Si todo lo que quieres hacer es usar una clusula
where, tables,
B.6.4.
params
WHERE
Como se explica en el Apndice C, cada modelo obtiene algunos mtodos automticamente -- los ms notables son
save()
delete().
Un caso de uso clsico de sobreescritura de los mtodos incorporados es cuando necesitas que suceda algo cuando
guardas un objeto, por ejemplo:
class Blog(models.Model):
name = models.CharField(maxlength=100)
tagline = models.TextField()
def save(self):
do_something()
super(Blog, self).save() # Call the "real" save() method.
do_something_else()
Tambin puedes evitar el guardado:
class Blog(models.Model):
name = models.CharField(maxlength=100)
tagline = models.TextField()
def save(self):
if self.name == "Yoko Ono's blog":
return # Yoko shall never have her own blog!
else:
super(Blog, self).save() # Call the "real" save() method
B.7.
La clase
Admin
Las siguientes secciones presentan una lista de todas las opciones posibles de
Admin.
requerida. Para utilizar una interfaz de administracin sin especicar ninguna opcin, use
class Admin:
pass
Agregar
class Admin
pass,
como en:
B.7.1.
269
date_hierarchy
Establece
class CustomerOrder(models.Model):
order_date = models.DateTimeField()
...
class Admin:
date_hierarchy = "order_date"
B.7.2.
elds
Establece
fields
cin.
fields
es una estructura anidada bastante compleja que se demuestra mejor con un ejemplo. Lo siguiente est
FlatPage
que es parte de
django.contrib.flatpages:
class FlatPage(models.Model):
...
class Admin:
fields = (
(None, {
'fields': ('url', 'title', 'content', 'sites')
}),
('Advanced options', {
'classes': 'collapse',
'fields' : ('enable_comments', 'registration_required', 'template_name')
}),
)
Formalmente,
fields
<fieldset>
en el
fields no est denido, Django mostrar por omisin cada campo que no sea un AutoField y tenga editable=True,
en un conjunto de campos simple, en el mismo orden en que aparecen los campos denidos en el modelo.
El diccionario
field_options
elds
Una tupla de nombres de campo a mostrar en el conjunto de campos. Esta clave es requerida.
Para mostrar mltiples campos en la misma linea, encierra esos campos en su propia tupla. En este ejemplo, los
campos
first_name
last_name
270
description
Un string de texto extra opcional para mostrar encima de cada conjunto de campos, bajo el encabezado del mismo.
Se usa tal cual es, de manera que puedes usar cualquier HTML, y debes crear las secuencias de escape correspondientes
para cualquier carcter especial HTML (como los ampersands).
B.7.3.
js
Una lista de strings representando URLs de archivos JavaScript a vincular en la pantalla de administracin mediante
etiquetas
<script src="">.
Esto puede ser usado para ajustar un tipo determinado de pgina de administracin en
JavaScript o para proveer quick links para llenar valores por omisin para ciertos campos.
http:// o /
settings.ADMIN_MEDIA_PREFIX.
B.7.4.
list_display
Establece
Si no se dene
__str__()
de cada objeto.
ForeignKey,
del administrador.
con la representacin
list_display:
Django mostrar el
__str__()
separada para cada la en la tabla. Si de todas formas quieres hacer esto, dale a tu modelo un mtodo
personalizado, y agrega el nombre de ese mtodo a
personalizados en
list_display
BooleanField
True o False.
Si el campo es un
o en lugar de
list_display.
en breve.)
o
NullBooleanField,
Si el string dado es un mtodo del modelo, Django lo invocar y mostrar la salida. Este mtodo debe
tener un atributo de funcin
short_description
class Person(models.Model):
name = models.CharField(maxlength=50)
birthday = models.DateField()
class Admin:
list_display = ('name', 'decade_born_in')
def decade_born_in(self):
return self.birthday.strftime(' %Y')[:3] + "0's"
decade_born_in.short_descripcin = 'Birth decade'
Si el string dado es un mtodo del modelo, Django har un HTML-escape de la salida por omisin.
Si no quieres 'escapear' la salida del mtodo, dale al mtodo un atributo
True.
allow_tags
con el valor en
class Person(models.Model):
first_name = models.CharField(maxlength=50)
last_name = models.CharField(maxlength=50)
color_code = models.CharField(maxlength=6)
class Admin:
list_display = ('first_name', 'last_name', 'colored_name')
def colored_name(self):
return '<span style="color: # %s;"> %s %s</span>' % (self.color_code, self.first_name, self
colored_name.allow_tags = True
271
True
boolean con
False, Django
True.
valor en
mostrar un bonito
class Person(models.Model):
first_name = models.CharField(maxlength=50)
birthday = models.DateField()
class Admin:
list_display = ('name', 'born_in_fifties')
def born_in_fifties(self):
return self.birthday.strftime(' %Y')[:3] == 5
born_in_fifties.boolean = True
Los mtodos
__str__()
list_display
list_display
utilizados en ordenamientos (porque Django hace todo el ordenamiento a nivel de base de datos).
De todas formas, si un elemento de
class Person(models.Model):
first_name = models.CharField(maxlength=50)
color_code = models.CharField(maxlength=6)
class Admin:
list_display = ('first_name', 'colored_first_name')
def colored_first_name(self):
return '<span style="color: # %s;"> %s</span>' % (self.color_code, self.first_name)
colored_first_name.allow_tags = True
colored_first_name.admin_order_field = 'first_name'
El cdigo precedente le dir a Django que ordene segn el campo
por
B.7.5.
colored_first_name
en el sitio de administracin.
list_display_links
Establece
list_display_links
list_display
de cambios de un objeto.
Por omisin, la pgina de la lista de cambios vincular la primera columna -- el primer campo especicado en
list_display -- a la pgina de cambios de cada tem. Pero list_display_links te permite cambiar cules columnas
se vinculan. Establece list_display_links a una lista o tupla de nombres de campo (en el mismo formato que
list_display) para vincularlos.
list_display_links puede especicar uno o varios nombres de campo. Mientras los nombres de campo aparezcan
en list_display, a Django no le preocupa si los campos vinculados son muchos o pocos. El nico requerimiento es
que si quieres usarlist_display_links, debes denir list_display.
En este ejemplo, los campos first_name y last_name sern vinculados a la pgina de la lista de cambios:
class Person(models.Model):
...
class Admin:
list_display = ('first_name', 'last_name', 'birthday')
list_display_links = ('first_name', 'last_name')
Finalmente, observa que para usar
list_display_links,
list_display.
272
B.7.6.
list_lter
Establece
list_filter
para activar los ltros en la barra lateral derecha de la pgina de la lista de cambios en la
interfaz de administracin. Debe ser una lista de nombres de campo, y cada campo especicado debe ser de alguno de
los tipos
class User(models.Model):
...
class Admin:
list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
list_filter = ('is_staff', 'is_superuser')
B.7.7.
list_per_page
Establece
list_per_page
para controlar cuantos items aparecen en cada pgina de la lista de cambios del admi-
B.7.8.
100.
list_select_related
Establece
list_select_related para indicarle a Django que use select_related() al recuperar la lista de objetos
de la pgina de la lista de cambios del administrador. Esto puede ahorrarte una cantidad de consultas a la base de
datos si ests utilizando objetos relacionados en la lista de cambios que muestra el administrador.
True
ForeignKey.
B.7.9.
False.
Por omisin es
select_related(),
False,
list_display
sea una
ver Apndice C.
ordering
Establece
ordering
para especicar como deben ordenarse los objetos en la pgina de la lista de cambios del
administrador. Esto debe ser una lista o tupla en el mismo formato que el parmetro
ordering
del modelo.
Si no est denido, la interfaz de administracin de Django usar el ordenamiento por omisin del modelo.
B.7.10.
save_as
Establece
Normalmente, los objetos tienen tres opciones al guardar: Save, Save and continue editing y Save and add
another. Si
save_as
es
True,
Save and add another ser reemplazado por un botn Save as.
Save as signica que el objeto ser guardado como un objeto nuevo (con un identicador nuevo), en lugar del
objeto viejo.
Por omisin,
B.7.11.
save_as
es
False.
save_on_top
Establece
save_on_top para agregar botones de guardado a lo largo del encabezado de tus formularios de cambios
del administrador.
Normalmente, los botones de guardado aparecen solamente al pie de los formularios. Si estableces
save_on_top,
B.7.12.
save_on_top
es
False.
search_elds
Establece
search_fields
trador. Debe ser una lista de nombres de campo que se utilizar para la bsqueda cuando alguien enve una consulta
en ese cuadro de texto.
Estos campos deben ser de alguna tipo de campo de texto, como
una bsqueda relacionada sobre una
ForeignKey
273
class Employee(models.Model):
department = models.ForeignKey(Department)
...
class Admin:
search_fields = ['department__name']
Cuando alguien hace una bsqueda en el cuadro de bsqueda del administrador, Django divide la consulta de
bsqueda en palabras y retorna todos los objetos que contengan alguna de las palabras, sin distinguir maysculas y
['first_name', 'last_name']
y un usuario busca
en SQL:
WHERE (first_name ILIKE ' %john %' OR last_name ILIKE ' %john %')
AND (first_name ILIKE ' %lennon %' OR last_name ILIKE ' %lennon %')
Para bsquedas ms rpidas y/o ms restrictivas, agrega como prejo al nombre de campo un operador como se
muestra en la Tabla B-7.
Cuadro B.7: Operadores Permitidos en search_elds
Operador
Signicado
el principio del campo. Por ejemplo, si search_fields es ['^first_name',
'^last_name'], y un usuario busca john lennon, Django har el equivalente a esta clusula WHERE en SQL:
WHERE (first_name ILIKE 'john %' OR last_name ILIKE 'john %')
AND (first_name ILIKE 'lennon %' OR last_name ILIKE 'lennon %')
Esta consulta es ms eciente que la consulta ' %john %', dado que la base de datos solo necesita
Matchea
examinar el principio de una columna de datos, en lugar de buscar a travs de todos los datos
de la columna. Adems, si la columna tiene un ndice, algunas bases de datos pueden permitir
el uso del ndice para esta consulta, a pesar de que sea una consulta
LIKE.
search_fields es
['=first_name', '=last_name'] y un usuario busca john lennon, Django har el equivalente
a esta clausula WHERE en SQL:
WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john')
AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')
Matchea exactamente, sin distinguir maysculas y minsculas. Por ejemplo, si
Observar que la entrada de la consulta se divide por los espacios, por lo cual actualmente no
es posible hacer una bsqueda de todos los registros en los cuales
'john winston'
@
first_name
es exactamente
Realiza una bsqueda en todo el texto. Es similar al mtodo de bsqueda predeterminado, pero
usa un ndice. Actualmente solo est disponible para MySQL.
274
Apndice C
com/documentation/0.96/db-api/.
http://www.djangoproject.
A lo largo de este apndice, vamos a hacer referencia a los siguientes modelos, los cuales pueden formar una simple
aplicacin de blog:
C.1.
Creando Objetos
Para crear un objeto, crea una instancia de la clase modelo usando argumentos de palabra clave y luego llama a
save()
276
save()
save().
INSERT.
no retorna nada.
create
de la clase
Manager
que describiremos
en breve.
C.1.1.
Emitir una seal pre_save. Esto provee una noticacin de que un objeto est a punto de
*listener* que ser invocado en cuanto esta seal sea emitida.
Estas seales todava estn en desarrollo y no estaban documentadas cuando este libro fue a
impresin; revisa la documentacin en lnea para obtener la informacin ms actual.
2.
Pre-procesar los datos. Se le solicita a cada campo del objeto implementar cualquier modicacin automatizada de datos que pudiera necesitar realizar.
La mayora de los campos no realizan pre-procesamiento -- los datos del campo se guardan tal
como estn. Slo se usa pre-procesamiento en campos que tienen comportamiento especial, como
campos de archivo.
3.
Preparar los datos para la base de datos. Se le solicita a cada campo que provea su valor
actual en un tipo de dato que puede ser grabado en la base de datos.
La mayora de los campos no requieren preparacin de los datos. Los tipos de datos simples,
como enteros y cadenas, estn listos para escribir como un objeto de Python. Sin embargo,
DateFields
datetime Python para almacenar datos. Las bases de datos no almacenan objetos
datetime,
de manera que el valor del campo debe ser convertido en una cadena de fecha que
Insertar los datos en la base. Los datos pre-procesados y preparados son entonces incorporados en una sentencia SQL para su insercin en la base de datos.
5.
noticacin de que un objeto ha sido grabado satisfactoriamente. De nuevo, estas seales todava
no han sido documentadas.
C.1.2.
especiques
AutoField
grabas, solo defnelo explcitamente antes de grabarlo en vez de conar en la asignacin automtica de valor del
identicador:
>>>
>>>
3
>>>
>>>
3
277
Si asignas manualmente valores de claves primarias autoincrementales Asegrate de no usar un valor de clave
primaria que ya existe!. Si creas un objeto con un valor explcito de clave primaria que ya existe en la base de datos,
Django asumir que ests cambiando el registro existente en vez de crear uno nuevo.
Dado el ejemplo precedente de blog
'Cheddar Talk',
datos:
C.2.
Para grabar los cambios hechos a un objeto que existe en la base de datos, usa
Dada la instancia de
su registro en la base:
save().
UPDATE.
UPDATE
y cuando usar
INSERT
save() para
INSERT o UPDATE.
Habrs notado que los objetos de base de datos de Django usan el mismo mtodo
crear y cambiar objetos. Django abstrae la necesidad de usar sentencias SQL
Especcamente, cuando llamas a
save(),
Si el atributo clave primaria del objeto tiene asignado un valor que evala
(esto es, un valor distinto a
consulta
SELECT
None
True
pecicada.
Si el registro con la clave primaria especicada ya existe, Django ejecuta una
consulta
UPDATE.
Si el atributo clave primaria del objeto no tiene valor o si lo tiene pero no existe
un registro, Django ejecuta un
INSERT.
Debido a esto, debes tener cuidado de no especicar un valor explcito para una clave primaria
cuando grabas nuevos objetos si es que no puedes garantizar que el valor de clave primaria est
disponible para ser usado.
La actualizacin de campos
ForeignKey
C.3.
Recuperando objetos
A travs del libro has visto cmo se recuperan objetos usando cdigo como el siguiente:
QuerySet
usando el
Manager
QuerySet
solicitados.
revisin 757 del 28 de julio de 2008
278
El Apndice B trat ambos objetos desde el punto de vista de la denicin del modelo; ahora vamos a ver cmo
funcionan.
QuerySet
Un
representa una coleccin de objetos de tu base de datos. Puede tener cero, uno, o muchos ltros --
QuerySet se compara a
SELECT y un ltro es una clusula de limitacin como por ejemplo WHERE o LIMIT.
Consigues un QuerySet usando el Manager del modelo. Cada modelo tiene por lo menos un Manager y tiene, por
omisin, el nombre objects. Accede al mismo directamente a travs de la clase del modelo, as:
criterios que limitan la coleccin basados en parmetros provistos. En trminos de SQL un
una declaracin
>>> Blog.objects
<django.db.models.manager.Manager object at 0x137d00d>
Los
Managers
solo son accesibles a travs de las clases de los modelos, en vez desde una instancia de un modelo,
para as hacer cumplir con la separacin entre las operaciones a nivel de tabla y las operaciones a nivel de registro:
El
C.4.
Caching y QuerySets
QuerySet
Cada
contiene un cache, para minimizar el acceso a la base de datos. Es importante entender como
QuerySet
QuerySet
ocurre un acceso a la base de datos -- Django graba el resultado de la consulta en el cache del
QuerySet
y retorna
los resultados que han sido solicitados explcitamente (por ejemplo, el siguiente elemento, si se est iterando sobre el
QuerySet).
QuerySet
Ten presente este comportamiento de caching, porque puede morderte si no usas tus
ejemplo, lo siguiente crear dos
QuerySets,
Entry
QuerySet
y re-salo:
queryset = Poll.objects.all()
print [p.headline for p in queryset] # Evaluate the query set.
print [p.pub_date for p in queryset] # Reuse the cache from the evaluation.
C.5.
Filtrando objetos
La manera mas simple de recuperar objetos de una tabla es conseguirlos todos. Para hacer esto, usa el mtodo
all()
en un
Manager:
>>> Entry.objects.all()
El mtodo
all()
retorna un
QuerySet
Sin embargo, usualmente solo necesitars seleccionar un subconjunto del conjunto completo de objetos. Para crear
QuerySet
exclude():
filter()
y/o
inicial, aadiendo condiciones con ltros. Usualmente hars esto usando los
filter()
como
exclude()
mente en breve.
revisin 757 del 28 de julio de 2008
C.5.1.
279
Encadenando ltros
El resultado de renar un
QuerySet
es otro
QuerySet
>>> qs = Entry.objects.filter(headline__startswith='What')
>>> qs = qs..exclude(pub_date__gte=datetime.datetime.now())
>>> qs = qs.filter(pub_date__gte=datetime.datetime(2005, 1, 1))
Esto toma el
QuerySet
inicial de todas las entradas en la base de datos, agrega un ltro, luego una exclusin,
QuerySet
QuerySet
QuerySet
no implica ninguna
actividad en la base de datos. De hecho, las tres lneas precedentes no hacen ninguna llamada a la base de datos;
puedes enlazar/encadenar ltros todo el da y Django no ejecutar realmente la consulta hasta que el
evaluado.
Puedes evaluar un
QuerySet
Iterando : Un
QuerySet
QuerySet es iterable, y ejecuta su consulta en la base de datos la primera vez que iteras
QuerySet no es evaluado hasta que se iterado sobre l en el bucle
for:
qs = Entry.objects.filter(pub_date__year=2006)
qs = qs.filter(headline__icontains="bill")
for e in qs:
print e.headline
Esto imprime todos los ttulos desde el 2006 que contienen bill pero genera solo un acceso a la base
de datos.
Imprimindolo : Un
QuerySet
repr()
veniencia en el interprete interactivo Python, as puedes ver inmediatamente tus resultados cuando
usas el API interactivamente.
QuerySet
QuerySet
puede ser
QuerySet
QuerySet
ejecutando
list()
sobre el
QuerySet
sacar
ventaja de tu base de datos para cargar datos e inicializar objetos solo a medida que vas necesitando
los mismos.
QuerySet
obtienes un nuevo
q1 = Entry.objects.filter(headline__startswith="What")
q2 = q1.exclude(pub_date__gte=datetime.now())
q3 = q1.filter(pub_date__gte=datetime.now())
Estos tres
QuerySets
QuerySet
entradas que contienen un ttulo que empieza con What. El segundo es un sub-conjunto del
primero, con un criterio adicional que excluye los registros cuyo
hoy. El tercero es un sub-conjunto del primero, con un criterio adicional que selecciona solo los
registros cuyo
pub_date
QuerySet
el proceso de renamiento.
sea
280
C.5.2.
Limitando QuerySets
LIMIT
OFFSET.
5):
>>> Entry.objects.all()[:5]
Esto retorna las entradas desde la sexta hasta la dcima (OFFSET
5 LIMIT 5):
>>> Entry.objects.all()[5:10]
Generalmente, el rebanar un
QuerySet
QuerySet
retorna un nuevo
usas el parmetro step de la sintaxis de rebanado de Python. Por ejemplo, esto realmente ejecutara la consulta con
el objetivo de retornar una lista, objeto de por medio de los primeros diez:
>>> Entry.objects.all()[:10:2]
SELECT foo FROM bar LIMIT 1) usa un simple ndice
Entry en la base de datos, despus de ordenar las entradas
>>> Entry.objects.order_by('headline')[0]
y es equivalente a lo siguiente:
>>> Entry.objects.order_by('headline')[0:1].get()
Nota, sin embargo, que el primero de estos generar
IndexError
DoesNotExist
si
C.5.3.
QuerySet
QuerySet
o la forma como se ejecuta su consulta SQL. Estos mtodos se describen en las secciones
que siguen. Algunos de estos mtodos reciben argumentos de patrones de bsqueda, los cuales se discuten en detalle
mas adelante.
lter(**lookup)
Retorna un nuevo
QuerySet
QuerySet
exclude(**kwargs)
Retorna un nuevo
order_by(*campos)
Por omisin, los resultados retornados por un
por la opcin
ordering
QuerySet
en los metadatos del modelo (ver Apndice B). Puedes sobrescribir esto para una consulta
order_by():
>>> Entry.objects.order_by('?')
distinct()
Retorna un nuevo
QuerySet
que usa
SELECT DISTINCT
resultado de la misma.
Por omisin, un
problema porque
Sin embargo, si tu consulta abarca mltiples tablas, es posible obtener resultados duplicados cuando un
es evaluado. Esos son los casos en los que usaras
distinct().
QuerySet
281
values(*campos)
Retorna un
QuerySet especial que evala a una lista de diccionarios en lugar de objetos instancia de modelo. Cada
uno de esos diccionarios representa un objeto, con las las claves en correspondencia con los nombre de los atributos de
los objetos modelo:
de campos para los campos que especiques. Si no especicas los campos, cada diccionario contendr una clave y un
valor para todos los campos en la table de base de datos:
>>> Blog.objects.values()
[{'id': 1, 'name': 'Beatles Blog', 'tagline': 'All the latest Beatles news.'}],
>>> Blog.objects.values('id', 'name')
[{'id': 1, 'name': 'Beatles Blog'}]
Este mtodo es til cuando sabes de antemano que solo vas a necesitar valores de un pequeo nmero de los
campos disponibles y no necesitars la funcionalidad de un objeto instancia de modelo. Es ms eciente el seleccionar
solamente los campos que necesitas usar.
QuerySet
tipo
debe ser ya
acuerdo al
tipo
provisto:
"year"
retorna una lista de todos los valores de aos distintos entre s para el campo.
"month"
"day"
retorna una lista de todos los valores de aos/mes distintos entre s para el campo.
retorna una lista de todos los valores de aos/mes/da distintos entre s para el campo.
orden, cuyo valor por omisin es 'ASC', debe ser 'ASC' o 'DESC'. El mismo especica cmo ordenar los resultados.
Aqu tenemos algunos ejemplos:
282
select_related()
Retorna un
QuerySet que seguir automticamente relaciones de clave fornea, seleccionando esos datos adicionales
de objetos relacionados cuando ejecuta su consulta. Esto contribuye a la mejora de rendimiento que resulta en consultas
(aveces mucho) ms grandes pero signican que el uso posterior de relaciones de clave fornea no requerirn consultas
a la base de datos.
Los siguientes ejemplos ilustran la diferencia entre bsquedas normales y bsquedas
select_related().
Esta es
select_related:
sigue claves forneas tan lejos como le sea posible. Si tienes los siguientes modelos:
class City(models.Model):
# ...
class Person(models.Model):
# ...
hometown = models.ForeignKey(City)
class Book(models.Model):
# ...
author = models.ForeignKey(Person)
entonces una llamada a
y la
City
Book.objects.select_related().get(id=4)
colocar en el cache la
Person
relacionada
relacionada:
>>> b = Book.objects.select_related().get(id=4)
>>> p = b.author
# Doesn't hit the database.
>>> c = p.hometown
# Doesn't hit the database.
>>> b = Book.objects.get(id=4) # No select_related() in this example.
>>> p = b.author
# Hits the database.
>>> c = p.hometown
# Hits the database.
Notar que
Usualmente, el usar
entonces evitar muchas llamadas a la base de datos. Sin embargo, en siuaciones con conjuntos de relaciones profundamente anidadas,
select_related()
extra()
A veces, el lenguaje de consulta de Django no puede expresar facilmente clusulas
extremos, Django provee un modicador de
dentro del SQL generado por un
QuerySet.
QuerySet
llamado
extra()
Por denicin, estas consultas especiales pueden no ser portables entre los distintos motores de bases de datos
(debido a que ests escribiendo cdigo SQL explcito) y violan el principio DRY, as que deberas evitarlas de ser
posible.
revisin 757 del 28 de julio de 2008
283
tables.
select permite indicar campos adicionales en una clusula de SELECT. Debe contener un diccionario
que mapee nombres de atributo a clusulas SQL que se utilizarn para calcular el atributo en cuestin:
pub_date
Entry
is_recent,
El siguiente ejemplo es ms avanzado; realiza una subconsulta para darle a cada objeto
entry_count,
Entry
asociados al blog:
FROM.)
where.
blog_blog
en
Tanto
where
como
tables
reciben
Python:
El
params
select
where
ya que
params
asegura
que los valores sern escapados correctamente de acuerdo con tu motor de base de datos particular.
Este es un ejemplo de lo que est incorrecto:
Metodos de
Los mtodos de
QuerySet
QuerySet
QuerySet
que no devuelven un
QuerySet
QuerySet
get(**lookup)
Devuelve el objeto que matchee el parmetro de bsqueda provisto. El parmetro debe proveerse de la manera
descripta en la seccin Patrones de bsqueda. Este mtodo levanta
DoesNotExist.
get()
de mltiples excepciones
284
create(**kwargs)
Este mtodo sirve para crear un objeto y guardarlo en un mismo paso. Te permite abreviar dos pasos comunes:
object
created
(object, created),
donde
Est pensado como un atajo para el caso de uso tpico y es ms que nada til para scripts de importacin de datos,
por ejemplo:
try:
Este patrn se vuelve inmanejable a medida que aumenta el nmero de campos en el modelo. El ejemplo anterior
puede ser escrito usando
obj, created =
first_name
last_name
defaults
)
get_or_create
as:
Person.objects.get_or_create(
= 'John',
= 'Lennon',
= {'birthday': date(1940, 10, 9)}
get_or_create() -- excepto el argumento opcional defaults -- ser utilizado
get_or_create devolver una tupla con ese objeto y False. Si
get_or_create() instanciar y guardar un objeto nuevo, devolviendo una tupla con el
get().
Si se encuentra un objecto,
no se encuentra un objeto,
nuevo objeto y
True.
'defaults'
defaults,
ya estuviera asignado, y se usa el resultado como claves para el constructor del modelo.
Foo.objects.get_or_create(
defaults__exact = 'bar',
defaults={'defaults': 'baz'}
)
Nota
Como ya se mencion,
get_or_create
cesar datos y crear nuevos campos si los que existen no estn disponibles. Si necesitas utilizar
get_or_create()
POST
285
count()
Devuelve un entero representando el nmero de objetos en la base de datos que coincidan con el
QuerySet. count()
un entero largo en vez de un entero normal de Python. Esto es una caracterstica particular de la implementacin
subyacente que no debera ser ningn problema en la vida real.
in_bulk(id_list)
Este mtodo toma una lista de claves primarias y devuelve un diccionario que mapea cada clave primaria en una
instancia con el ID dado, por ejemplo:
>>>
{1:
>>>
{1:
>>>
{}
Blog.objects.in_bulk([1])
Beatles Blog}
Blog.objects.in_bulk([1, 2])
Beatles Blog, 2: Cheddar Talk}
Blog.objects.in_bulk([])
in_bulk(),
latest(eld_name=None)
Devuelve el ltimo objeto de la tabla, ordenados por fecha, utilizando el campo que se provea en el argumento
field_name como fecha. Este ejemplo devuelve el Entry ms reciente en la tabla, de acuerdo con el campo pub_date:
>>> Entry.objects.latest('pub_date')
Si el
Meta
de tu modelo especica
el
campo indicado en
Al igual que
C.6.
Patrones de bsqueda
WHERE de SQL. Consisten de
filter(), exclude() y get() de QuerySet.
toman la forma de campo__tipodebusqueda=valor (notar el doble guin
Los patrones de bsqueda son la manera en que se especica la carne de una clusula
argumentos de palabra clave para los mtodos
Los parmetros bsicos de bsqueda
bajo). Por ejemplo:
>>> Entry.objects.filter(pub_date__lte='2006-01-01')
se traduce (aproximadamente) al siguiente comando SQL:
TypeError.
286
C.6.1.
exact
exact.
C.6.2.
exact
iexact
Realiza una bsqueda por coincidencias exactas sin distinguir maysculas de minsculas:
C.6.3.
etctera.
contains
Entry.objects.get(headline__contains='Lennon')
Esto coincidir con el titular
SQLite no admite sentencias
comporta como
icontains.
LIKE
Entry.objects.filter(headline__contains=' %')
Django se hace cargo del escapado. El SQL resultante ser algo similar a esto:
C.6.4.
icontains
>>> Entry.objects.get(headline__icontains='Lennon')
A diferencia de
contains, icontains
s trer
se
C.6.5.
287
Estos representan los operadores de mayor a, mayor o igual a, menor a, y menor o igual a, respectivamente:
>>> Entry.objects.filter(id__gt=4)
>>> Entry.objects.filter(id__lt=15)
>>> Entry.objects.filter(id__gte=0)
Estas consultas devuelven cualquier objeto con un ID mayor a 4, un ID menor a 15, y un ID mayor o igual a 1,
respectivamente.
Por lo general estos operadores se utilizarn con campos numricos. Se debe tener cuidado con los campos de
caracteres, ya que el orden no siempre es el que uno se esperara (i.e., la cadena 4 resulta ser mayor que la cadena
10).
C.6.6.
in
Entry.objects.filter(id__in=[1, 3, 4])
Esto devolver todos los objetos que tengan un ID de 1, 3 o 4.
C.6.7.
startswith
>>> Entry.objects.filter(headline__startswith='Will')
Esto encontrar los titulares Will he run` y Willbur named judge, pero no Who is Will` o will found in crypt.
C.6.8.
istartswith
>>> Entry.objects.filter(headline__istartswith='will')
Esto devolver los titulares Will he run`, Willbur named judge, y will found in crypt, pero no Who is Will`
C.6.9.
>>> Entry.objects.filter(headline__endswith='cats')
>>> Entry.objects.filter(headline__iendswith='cats')
C.6.10.
range
range en cualquier lugar donde podras utilizar BETWEEN en SQL -- para fechas, nmeros, e incluso
cadenas de caracteres.
C.6.11.
Para campos
date
datetime,
288
# Bsqueda por ao
>>>Entry.objects.filter(pub_date__year=2005)
# Bsqueda por mes -- toma enteros
>>> Entry.objects.filter(pub_date__month=12)
# Bsqueda por da
>>> Entry.objects.filter(pub_date__day=3)
# Combinacin: devuelve todas las entradas de Navidad de cualquier ao
>>> Entry.objects.filter(pub_date__month=12, pub_date_day=25)
C.6.12.
isnull
Toma valores
True o False, que correspondern a consultas SQL de IS NULL``y ``IS NOT NULL, respectivamente:
>>> Entry.objects.filter(pub_date__isnull=True)
__isnull=True
vs.
__exact=None
__isnull=True
__exact=None. __exact=None
siempre
devolver como resultado un conjunto vaco, ya que SQL requiere que ningn valor sea igual
a
NULL. __isnull
NULL
sin realizar la
comparacin.
C.6.13.
search
full-text,
full-text.
full-text.
Esto es como
contains
Ntese que este tipo de bsqueda slo est disponible en MySQL y requiere de manipulacin directa de la base de
datos para agregar el ndice
C.6.14.
full-text.
El patrn de bsqueda pk
pk,
primaria es el campo
id,
pk
no se limita a bsquedas
__exact
pk
tambin funcionan con joins. Por ejemplo, estas tres sentencias son equivalentes:
pk
para
C.7.
289
Q (django.db.models.Q)
palabra clave. Estos argumentos de palabra clave son especicados como se indica en la seccin Patrones de bsqueda.
Por ejemplo, este objeto
LIKE:
Q(question__startswith='What')
Los objetos
Q.
Por ejemplo, un
OR
&
|.
de dos consultas
question__startswith
sera:
Q(question__startswith='Who') | Q(question__startswith='What')
Esto ser equivalente a la siguiente clusula
WHERE
en SQL:
&
|.
Tambin se
puede
como argumentos a una funcin de bsqueda, los argumentos sern unidos con AND, por ejemplo:
Poll.objects.get(
Q(question__startswith='Who'),
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)
se traduce aproximadamente al siguiente SQL:
los argumentos provistos a una funcin de bsqueda (sean argumentos de palabra clave u objetos
AND. Sin embargo, si se provee un objeto
ejemplo, lo siguiente:
Poll.objects.get(
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)),
question__startswith='Who')
es una consulta vlida, equivalente al ejemplo anterior, pero esto:
# CONSULTA INVALIDA
Poll.objects.get(
question__startswith='Who',
Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
no es vlido.
Hay algunos ejemplos disponibles online en http://www.djangoproject.com/documentation/0.96/models/or_lookups/
.
C.8.
Objetos Relacionados
cias de ese modelo tendrn una API conveniente para acceder a estos objetos relacionados.
Por ejemplo, si
e es un objeto Entry, puede acceder a su Blog asociado accediendo al atributo blog, esto es e.blog.
Django tambin crea una API para acceder al otro lado de la relacin -- el vnculo del modelo relacionado al
b es un
entry_set: b.entry_set.all().
objeto
Blog,
Entry
de esta seccin.
revisin 757 del 28 de julio de 2008
290
C.8.1.
Django ofrece un mecanismo poderoso e intuitivo para seguir relaciones cuando se realizan bsquedas, hacindose
cargo de los
JOINs
de SQL de manera automtica. Para cruzar una relacin simplemente hace falta utilizar el nombre
de campo de los campos relacionados entre modelos, separados por dos guiones bajos, hasta que llegues al campo que
necesitabas.
Este ejemplo busca todos los objetos
Entry
que tengan un
Blog
cuyo
nombre
sea
'Beatles Blog':
Blog
Entry
cuyo
headline
contenga
'Lennon':
>>> Blog.objects.filter(entry__headline__contains='Lennon')
C.8.2.
Si un modelo contiene un
ForeignKey, las
e = Entry.objects.get(id=2)
e.blog # Devuelve el objeto Blog relacionado
Se puede acceder y asignar el valor de la clave fornea va el atributo. Como sera de esperar, los cambios a la clave
fornea no se guardan en el modelo hasta que invoques el mtodo
save(),
por ejemplo:
e = Entry.objects.get(id=2)
e.blog = some_blog
e.save()
Si un campo
ForeignKey
tiene la opcin
null=True
NULL),
se le puede asignar
None:
e = Entry.objects.get(id=2)
e.blog = None
e.save() # "UPDATE blog_entry SET blog_id = NULL ...;"
El acceso a relaciones uno-a-muchos se almacena la primera vez que se accede al objeto relacionado. Cualquier
acceso subsiguiente a la clave fornea del mismo objeto son cacheadas, por ejemplo:
e = Entry.objects.get(id=2)
print e.blog # Busca el Blog asociado en la base de datos.
print e.blog # No va a la base de datos; usa la versin cacheada.
Notar que el mtodo de
QuerySet select_related()
a-muchos de la instancia:
e = Entry.objects.select_related().get(id=2)
print e.blog # No va a la base de datos; usa la versin cacheada.
print e.blog # No va a la base de datos; usa la versin cacheada.
select_related()
C.8.3.
Las relaciones de clave fornea son automticamente simtricas -- se inere una relacin inversa de la presencia de
un campo
ForeignKey
ForeignKey, las instancias del modelo de la clave fornea tendrn acceso a un Manager que
Manager se llama FOO_set, donde FOO es el nombre
modelo que contiene la clave fornea, todo en minsculas. Este Manager devuelve QuerySets, que pueden ser ltradas
Si un modelo tiene una
devuelve todas las instancias del primer modelo. Por defecto, este
291
b = Blog.objects.get(id=1)
b.entry_set.all() # Encontrar todos los objetos Entry relacionados a b.
# b.entry_set es un Manager que devuelve QuerySets.
b.entry_set.filter(headline__contains='Lennon')
b.entry_set.count()
Se puede cambiar el nombre del atributo FOO_set indicando el parmetro related_name en la denicin del
ForeignKey(). Por ejemplo, si el modelo Entry fuera cambiado por blog = ForeignKey(Blog, related_name='entries'),
el ejemplo anterior pasara a ser as:
b = Blog.objects.get(id=1)
b.entries.all() # Encontrar todos los objetos Entry relacionados a b.
# b.entries es un Manager que devuelve QuerySets.
b.entries.filter(headline__contains='Lennon')
b.entries.count()
No se puede acceder al
Manager de ForeignKey inverso desde la clase misma; debe ser accedido desde una instancia:
QuerySet
Manager
de
ForeignKey
por ejemplo:
b = Blog.objects.get(id=1)
e = Entry.objects.get(id=234)
b.entry_set.add(e) # Associates Entry e with Blog b.
create(**kwargs): Crea un nuevo objeto, lo guarda, y lo deja en el conjunto de objetos relacionados.
Devuelve el objeto recin creado:
b = Blog.objects.get(id=1)
e = b.entry_set.create(headline='Hello', body_text='Hi', pub_date=datetime.date(2005, 1, 1)
# No hace falta llamar a e.save() ac -- ya ha sido guardado
Esto es equivalente a (pero ms simple que) lo siguiente:
b = Blog.objects.get(id=1)
e = Entry(blog=b, headline='Hello', body_text='Hi', pub_date=datetime.date(2005, 1, 1))
e.save()
Notar que no es necesario especicar el argumento de palabra clave correspondiente al modelo que
dene la relacin. En el ejemplo anterior, no le pasamos el parmetro
que el campo
blog
del nuevo
Entry
debera ser
b.
b = Blog.objects.get(id=1)
e = Entry.objects.get(id=234)
b.entry_set.remove(e) # Desasociar al Entry e del Blog b.
ForeignKey donde
null=True. Si el campo relacionado no puede pasar ser None (NULL), entonces un objeto no puede ser
quitado de una relacin sin ser agregado a otra. En el ejemplo anterior, el quitar a e de b.entry_set()
es equivalente a hacer e.blog = None, y dado que la denicin del campo ForeignKey blog (en el
modelo Entry) no indica null=True, esto es una accin invlida.
Para evitar inconsistencias en la base de datos, este mtodo slo existe para objetos
clear():
b = Blog.objects.get(id=1)
b.entry_set.clear()
Notar que esto no borra los objetos relacionados -- simplemente los desasocia.
Al igual que
remove(), clear
ForeignKey
donde
null=True.
292
Para asignar todos los miembros de un conjunto relacionado en un solo paso, simplemente se le asigna al conjunto
un objeto iterable, por ejemplo:
b = Blog.objects.get(id=1)
b.entry_set = [e1, e2]
Si el mtodo
clear()
todos los objetos en el iterable (en este caso, la lista) sean agregados al conjunto. Si el mtodo
disponible, todos los objetos del iterable son agregados al conjunto sin quitar antes los objetos pre-existentes.
Todas las operaciones inversas denidas en esta seccin tienen efectos inmediatos en la base de datos. Toda
creacin, borradura y agregado son inmediata y automticamente grabados en la base de datos.
C.8.4.
Relaciones muchos-a-muchos
Ambos extremos de las relaciones muchos-a-muchos obtienen una API de acceso automticamente. La API funciona
igual que las funciones inversas de las relaciones uno-a-muchos (descriptas en la seccin anterior).
La nica diferencia es el nombrado de los atributos: el modelo que dene el campo
del atributo del campo mismo, mientras que el modelo inverso utiliza el nombre del modelo original, en minsculas,
con el sujo
'_set'
e = Entry.objects.get(id=3)
e.authors.all() # Devuelve todos los objetos Author para este Entry.
e.authors.count()
e.authors.filter(name__contains='John')
a = Author.objects.get(id=5)
a.entry_set.all() # Devuelve todos los obejtos Entry para este Author.
ForeignKey, los ManyToManyField pueden indicar un related_name. En el ejemplo
ManyToManyField en el modelo Entry indicara related_name='entries', cualquier instancia de
atributo entries en vez de entry_set.
Author
tendra un
C.8.5.
Las consultas que involucran objetos relacionados siguen las mismas reglas que las consultas que involucran campos
normales. Cuando se indica el valor que se requiere en una bsqueda, se puede utilizar tanto una instancia del modelo
o bien el valor de la clave primaria del objeto.
Por ejemplo, si
es un objeto
Blog
con
id=5,
C.9.
Borrando Objectos
delete().
de retorno:
293
e.delete()
Tambin se puede borrar objetos en grupo. Todo objeto
miembros de ese
QuerySet.
QuerySet
tiene un mtodo
Entry
delete()
que tengan un ao de
pub_date
igual a
2005:
Entry.objects.filter(pub_date__year=2005).delete()
Cuando Django borra un objeto, emula el comportamiento de la restriccin de SQL
palabras, todos los objetos que tengan una clave fornea que apunte al objeto que est siendo borrado sern borrados
tambin, por ejemplo:
b = Blog.objects.get(pk=1)
# Esto borra el Blog y todos sus objetos Entry.
b.delete()
Notar que
delete()
es el nico mtodo de
QuerySet
Si realmente quieres borrar todos los objetos, hay que pedirlo explcitamente al conjunto completo de objetos:
Entry.objects.all().delete()
C.10.
Adems de
C.10.1.
save()
delete(),
get_FOO_display()
choices,
get_FOO_display(),
donde
FOO
es
el nombre del campo. Este mtodo devuelve el valor humanamente legible del campo. Por ejemplo, en el siguiente
modelo:
GENDER_CHOICES = (
('M', 'Male'),
('F', 'Female'),
)
class Person(models.Model):
name = models.CharField(max_length=20)
gender = models.CharField(max_length=1, choices=GENDER_CHOICES)
cada instancia de
Person
tendr un mtodo
get_gender_display:
get_next_by_FOO(**kwargs) y get_previous_by_FOO(**kwargs)
Por cada campo DateField y DateTimeField que no tenga null=True, el objeto tendr dos mtodos get_next_by_FOO()
get_previous_by_FOO(), donde FOO es el nombre del campo. Estos mtodos devuelven el objeto siguiente y anterior
en orden cronolgico respecto del campo en cuestin, respectivamente, levantando la excepcin DoesNotExist cuando
y
http://www.djangoproject.com/documentation/0.96/models/lookup/.
294
C.10.3.
get_FOO_lename()
Todo campo
FileField
get_FOO_filename(),
donde
FOO
Esto devuelve el nombre de archivo completo en el sistema de archivos, de acuerdo con la variable
Notar que el campo
campo
ImageField
C.10.4.
ImageField
FileField,
MEDIA_ROOT.
get_FOO_url()
FileField
C.10.5.
get_FOO_size()
FileField el objeto tendr un mtodo get_FOO_size(), donde FOO es el nombre del campo. Este
os.path.getsize.)
mtodo devuelve el tamao del archivo, en bytes. (La implementacin de este mtodo utiliza
C.10.6.
save_FOO_le(lename, raw_contents)
FileField,
save_FOO_file(),
donde
FOO
Este mtodo guarda el archivo en el sistema de archivos, utilizando el nombre dado. Si un archivo con el nombre dado
ya existe, Django le agrega guiones bajos al nal del nombre de archivo (pero antes de la extensin) hasta que el
nombre de archivos est disponible.
C.10.7.
es el nombre del campo. Estos mtodos devuelven el alto y el ancho (respectivamente) de la imagen, en pixeles, como
un entero.
C.11.
Atajos (Shortcuts)
A medida que desarrolles tus vistas, descubrirs una serie de modismos en la manera de utilizar la API de la base
de datos. Django codica algunos de estos modismos como atajos que pueden ser utilizados par simplicar el proceso
de escribir vistas. Estas funciones se pueden hallar en el mdulo
C.11.1.
django.shortcuts.
get_object_or_404()
en la funcin
Manager
get()
subyacente. Si no quieres que se utilice el manager por defecto, o si quiere buscar en una lista de objetos relacionados,
se le puede pasar a
get_object_or_404()
un objeto
Manager
en vez:
C.11.2.
get_list_or_404()
C.12.
295
filter()
en vez de a
Si te encuentras necesitando escribir una consulta SQL que es demasiado compleja para manejarlo con el mapeador
de base de datos de Django, todava puede optar por escribir la sentencia directamente en SQL crudo.
La forma preferida para hacer esto es dndole a tu modelo mtodos personalizados o mtodos de
Manager persona-
lizados que realicen las consultas. Aunque no exista ningn requisito en Django que exija que las consultas a la base
de datos vivan en la capa del modelo, esta implementacin pone a toda tu lgica de acceso a los datos en un mismo
lugar, lo cual es una idea astuta desde el punto de vista de organizacin del cdigo. Por ms instrucciones, vase el
Apndice B..
Finalmente, es importante notar que la capa de base de datos de Django es meramente una interfaz a tu base de
datos. Puedes acceder a la base de datos utilizando otras herramientas, lenguajes de programacin o frameworks de
bases de datos -- No hay nada especcamente de Django acerca de tu base de datos.
296
Apndice D
Publisher
D.1.
Author
Book,
denidos en dicho captulo, ya que sern usados en los ejemplo incluidos en esta apndice.
La mayora de las vistas aceptan varios argumentos que pueden modicar su comportamiento. Muchos de esos
argumentos funcionan igual para la mayora de las vistas. La tabla D-1 describe estos argumentos comunes; cada vez
que veas uno de estos argumentos en la lista de parmetros admitidos por una vista genrica, su comportamiento ser
tal y como se describe en esta tabla.
Cuadro D.1: Argumentos comunes de las vistas genricas.
Argumento
allow_empty
Descripcin
Un valor booleano que indica como debe comportarse la vista si
no hay objetos disponibles. Si vale
context_processors
Falsa.
de contexto adicionales.
extra_context
mimetype
utiliza
el
tipo
DEFAULT_MIME_TYPE,
queryset
Un
objeto
de
denido
en
la
variable
de
conguracin
text/html.
QuerySet
(por
Author.objects.all())
tipo
ejemplo,
este argumento.
template_loader
El
cargador
de
plantillas
django.template.loader.
Vase
utilizar.
el
Por
`Captulo
defecto
es
10`_ donde
template_name
El nombre completo de la plantilla a usar para representar la pgina. Este argumento se puede usar si queremos modicar el nombre
que se genera automticamente a partir del
QuerySet.
298
Argumento
Descripcin
template_object_name
D.2.
object_list.
django.views.generic.simple hay varias vistas sencillas que manejan unos cuantos problemas
frecuentes: mostrar una plantilla que no necesita una vista lgica, y hacer una redireccin de una pgina.
D.2.1.
Vista a importar :
django.views.generic.simple.direct_to_template
Esta vista representa una plantilla, a la que se le pasa una variable de plantilla accesible como
{{ params }},
que es un diccionario que contiene los parmetros capturados de la URL, si los hubiera.
Ejemplo
Dada la siguiente conguracin del URLconf:
Argumentos obligatorios
template:
D.2.2.
Vista a importar :
django.views.generic.simple.redirect_to
Esta vista redirige a otra URL. La URL que se pasa como parmetro puede tener secuencias de formato aptas para
diccionarios, que sern interpretadas contra los parmetros capturados desde la URL origen.
Si la URL pasada como parmetro es
None,
HTTP).
Ejemplo
Este URLconf redirige desde
/foo/<id>/
/bar/<id>/:
/bar/:
299
url:
None
D.3.
Vistas de listado/detalle
Django.views.generic.list_detail) se encar-
gan de la habitual tarea de mostrar una lista de elementos por un lado (el listado) y una vista individual para cada
uno de los elementos (el detalle).
D.3.1.
Listas de objetos
Vista a importar :
django.views.generic.list_detail.object_list
Ejemplo
Si consideramos el objeto
Author
object_list
queryset:
Un
QuerySet
Argumentos opcionales
paginate_by:
es un nmero entero que especica cuantos objetos se deben mostrar en cada pgina.
Segn se especique en este parmetro, los resultados sern paginados, de forma que se distribuirn
por varias pginas de resultado. La vista determinar que pgina de resultados debe mostrar o bien
desde un parmetro
page
Get)
page
especicada en
el URLconf. En cualquiera de los dos casos, el ndice comienza en cero. En la siguiente seccin hay
una nota sobre paginacin donde se explica con un poco ms de detalle este sistema.
Adems, esta vidta acepta cualquiera de los siguientes argumentos opcionales descritos en la tabla D-1:
allow_empty
context_processors
extra_context
mimetype
revisin 757 del 28 de julio de 2008
para
300
template_loader
template_name
template_object_name
Nombre de la plantilla
Si no se ha especicado el parmetro opcional
Tanto la etiqueta de la aplicacin como la etiqueta del modelo se obtienen del parmetro
Contexto de plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
object_list: La lista de los objetos. El nombre de la variable viene determinado por el parmetro
template_object_name, y vale 'object' por defecto. Si se deniera template_object_name como
'foo', el nombre de esta variable sera foo_list.
is_paginated: Un valor booleano que indicar si los resultados sern paginados o no. Concretamente,
valdr False si el nmero de objetos disponibles es inferior o igual a paginate_by.
Si los resultados estn paginados, el contexto dispondr tambin de estas variables:
results_per_page: El nmero de objetos por pgina. (Su valor es el mismo que el del parmetro
paginate_by).
has_next: Un valor booleano indicando si hay una siguiente pgina.
has_previous: Un valor booleano indicando si hay una pgina previa.
page: El nmero de la pgina actual, siendo 1 la primera pgina.
next: El nmero de la siguiente pgina. Incluso si no hubiera siguiente pgina, este valor seguir siendo un numero entero que apuntara a una hipottica siguiente pgina. Tambin utiliza
un ndice basado en 1, no en cero.
en cero.
page
cerse a este:
page
en la URL: Por
/objects/?page=3
En ambos casos,
page
D.3.2.
Vista de detalle
Vista a importar :
django.views.generic.list_detail.object_detail
301
Ejemplo
Siguiendo con el ejemplo anterior, podemos aadir una vista de detalle de cada autor modicacando el URLconf
de la siguiente manera:
queryset:
Un
QuerySet
que ser usado para localizar el objeto a mostrar (vase la Tabla D-1).
object_id:
o bien:
slug:
La etiqueta o slug del objeto en cuestin. Si se usa este sistema de identicacin, hay que
slug_field
Argumentos opcionales
slug_field: El nombre del atributo del objeto que contiene el slug. Es obligatorio si ests usando el
argumento slug, y no se debe usar si ests usando el argumento object_id.
template_name_field: El nombre de un atributo del objeto cuyo valor se usar como el nombre de
la plantilla a utilizar. De esta forma, puedes almacenar en tu objeto la plantilla a usar.
'the_template' que contiene la cadena de textemplate_name_field para que valga 'the_template', entonces la vista
usar como plantilla 'foo.html'.
por template_name_field no existe, se usara el indicado por el argumento
'foo.html',
y denes
template_name.
casos.
Esta vista tambin acepta estos argumentos comunes (Vase la tabla D-1):
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
Nombre de la plantilla
Si no se especican
302
Contexto de plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
D.4.
si se ha especicado el argumento
denimos
template_object_name
Estas vistas genricas basadas en fechas se suelen utilizar para organizar la parte de archivo de nuestro contenido.
Los casos tpicos son los archivos por ao/mes/da de un peridico, o el archivo de una bitcora o blog.
Truco:
En principio, estas vistas ignoran las fechas que estn situadas en el futuro.
Esto signica que si intentas visitar una pgina del archivo que est en el futuro, Django mostrar
automticamente un error 404 (Pgina no encontrada), incluso aunque hubiera objetos con esa
fecha en el sistema.
Esto te permite publicar objetos por adelantado, que no se mostrarn pblicamente hasta que se
llegue a la fecha de publicacin deseada.
Sin embargo, para otros tipos de objetos con fechas, este comportamiento no es el deseable (por
ejemplo, un calendario de prximos eventos). Para estas vistas, podemos denir el argumento
allow_future como True y de esa manera conseguir que los objetos con fechas futuras aparezcan
(o permitir a los usuarios visitar pginas de archivo en el futuro).
D.4.1.
ndice de archivo
Vista a importar :
django.views.generic.date_based.archive_index
Esta vista proporciona un ndice donde se mostrara los ltimos objetos (es decir, los ms recientes) segn la
fecha.
Ejemplo
Supongamos el tpico editor que desea una pgina con la lista de sus ltimos libros publicados. Suponiendo que tenemos un objeto
Book con un atributo de fecha de publicacin, publication_date, podemos usar la vista archive_index
El
QuerySet
303
Argumentos opcionales
num_latest:
El nmero de objetos que se deben enviar a la plantilla. Su valor por defecto es 15.
Esta vista tambin acepta estos argumentos comunes (Vase la tabla D-1):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
Nombre de la plantilla
Si no se ha especicado
template_name,
se usar la plantilla
<app_label>/<model_name>_archive.html.
Contexto de la plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
date_list:
queryset.
datetime.date
primero.
Por ejemplo, para un blog que tuviera entradas desde el ao 2003 hasta el 2006, la lista contendr
cuatro objetos de tipo
latest:
Los ltimos
D.4.2.
datetime.date,
num_latest objetos en el sistema, considerndolos ordenados de forma descendate_field de referencia. Por ejemplo, si num_latest vale 10, entonces latest
ltimos 10 objetos contenidos en el queryset.
Archivos anuales
Vista a importar :
django.views.generic.date_based.archive_year
Esta vista sirve para presentar archivos basados en aos. Poseen una lista de los meses en los que hay algn objeto,
y pueden mostrar opcionalmente todos los objetos publicados en un ao determinado.
Ejemplo
Vamos a ampliar el ejemplo anterior incluyendo una vista que muestre todos los libros publicados en un determinado
ao:
304
Argumentos obligatorios
date_field:
queryset:
Igual que en
El
QuerySet
archive_index
de objetos archivados.
year: El ao, con cuatro dgitos, que la vista usar para mostrar el archivo (Como se ve en el ejemplo,
normalmente se obtiene de un parmetro en la URL).
Argumentos opcionales
make_object_list: Un valor booleano que indica si se debe obtener la lista completa de objetos para
este ao y pasrsela a la plantilla. Si es True, la lista de objetos estar disponible para la plantilla
con el nombre de object_list (Aunque este nombre podra ser diferente; vase la informacin sobre
object_list en la siguiente explicacin sobre Contexto de plantilla). Su valor por defecto es False.
allow_future:
Un valor booleano que indica si deben incluirse o no en esta vista las fechas en el
futuro.
Esta vista tambin acepta los siguientes argumentos comunes (Vase la Tabla D-1):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
Nombre de la plantilla
Si no se especica ningn valor en
Contexto de la plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
date_list:
datetime.date,
queryset,
en orden
ascendente.
year:
object_list: Si el parmetro make_object_list es True, esta variable ser una lista de objetos cuya
fecha de referencia cae en en ao a mostrar, ordenados por fecha. El nombre de la variable depende
D.4.3.
Archivos mensuales
Vista a importar :
django.views.generic.date_based.archive_month
Esta vista proporciona una representacin basada en meses, en la que se muestran todos los objetos cuya fecha de
referencia caiga en un determinado mes y ao.
305
Ejemplo
Siguiendo con nuestro ejemplo, aadir una vista mensual debera ser algo sencillo:
urlpatterns = patterns('',
(r'^books/$', date_based.archive_index, book_info),
(r'^books/(?P<year>d{4})/?$', date_based.archive_year, book_info),
(
r'^(?P<year>d{4})/(?P<month>[a-z]{3})/$',
date_based.archive_month,
book_info
),
)
Argumentos obligatorios
usado para el
Argumentos opcionales
month_format:
month. La
time.strftime (La documentacin de esta funcin
http://www.djangoproject.com/r/python/strftime/). Su valor por defecto
Una cadena de texto que determina el formato que debe usar el parmetro
" %b",
que signica el nombre del mes, en ingls, y abreviado a tres letras (Es decir, jan, feb,
etc.). Para cambiarlo de forma que se usen nmeros, hay que utilizar como cadena de formato
allow_future:
" %m".
Un valor booleano que indica si deben incluirse o no en esta vista las fechas en el
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
Nombre de la plantilla
Si no se especica ningn valor en
Contexto de la plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
306
D.4.4.
Archivos semanales
Vista a importar :
django.views.generic.date_based.archive_week
Nota
Por consistencia con las bibliotecas de manejo de fechas de Python, Django asume que el primer
da de la semana es el domingo.
Ejemplo
urlpatterns = patterns('',
# ...
(
r'^(?P<year>d{4})/(?P<week>d{2})/$',
date_based.archive_week,
book_info
),
)
Argumentos obligatorios
year:
week:
queryset:
El
QuerySet
DateTimeField
Argumentos opcionales
allow_future:
Un valor booleano que indica si deben incluirse o no en esta vista las fechas en el
futuro.
Esta vista tambin acepta los siguientes argumentos comunes (Vase la Tabla D-1):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
Nombre de la plantilla
Si no se ha especicado ningn valor en
Contexto de la plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
week:
Un objeto de tipo
datetime.date,
object_list: Una lista de objetos disponibles para la semana en cuestin. El nombre de esta variable
depende del parmetro template_object_name, que es 'object' por defecto. Si template_object_name
fuera 'foo', el nombre de esta variable sera foo_list.
D.4.5.
307
Archivos diarios
Vista a importar :
django.views.generic.date_based.archive_day
Ejemplo
urlpatterns = patterns('',
# ...
(
r'^(?P<year>d{4})/(?P<month>[a-z]{3})/(?P<day>d{2})/$',
date_based.archive_day,
book_info
),
)
Argumentos obligatorios
year:
month:
day:
queryset:
El
QuerySet
month_format
day_format.
DateTimeField
Argumentos opcionales
month_format:
Una cadena de texto que determina el formato que debe usar el parmetro
month.
day_format:
Equivalente a
month_format,
" %d"
(que es el
da del mes como nmero decimal y relleno con ceros de ser necesario; 01-31).
allow_future:
Un valor booleano que indica si deben incluirse o no en esta vista las fechas en el
futuro.
Esta vista tambin acepta los siguientes argumentos comunes (Vase la Tabla D-1):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
Nombre de la plantilla
Si no se ha especicado ningn valor en
Contexto de la plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
day:
Un objeto de tipo
datetime.date
next_day: Un objeto de tipo datetime.date que representa el siguiente da. Si cae en el futuro, valdr
None.
revisin 757 del 28 de julio de 2008
308
object_list: Una lista de objetos disponibles para el da en cuestin. El nombre de esta variable depende del parmetro template_object_name, que es 'object' por defecto. Si template_object_name
fuera 'foo', el nombre de esta variable sera foo_list.
D.4.6.
La vista
Ejemplo
urlpatterns = patterns('',
# ...
(r'^books/today/$', date_based.archive_today, book_info),
)
D.4.7.
Vista a importar :
django.views.generic.date_based.object_detail
/entries/<slug>/,
Nota
Si ests usando pginas de detalle basadas en la fecha con slugs en la URL, lo ms probable es
que quieras usar la opcin
unique_for_date
los slugs nunca se duplican para una misma fecha. Lee el apndice F para ms detalles sobre la
opcin
unique_for_date.
Ejemplo
Esta vista tiene una (pequea) diferencia con las dems vistas basadas en fechas que hemos visto anteriormente, y es
que necesita que le especiquemos de forma inequvoca el objeto en cuestin; esto lo podemos hacer con el identicador
del objeto o con un campo de tipo slug.
Como el objeto que estamos usando en el ejemplo no tiene ningn campo de tipo slug, usaremos el identicador para
la URL. Normalmente se considera una buena prctica usar un campo slug, pero no lo haremos en aras de simplicar
el ejemplo.
urlpatterns = patterns('',
# ...
(
r'^(?P<year>d{4})/(?P<month>[a-z]{3})/(?P<day>d{2})/(?P<object_id>[w-]+)/$',
date_based.object_detail,
book_info
),
)
Argumentos obligatorios
year:
month:
day:
queryset:
El
QuerySet
month_format
day_format.
DateTimeField
309
object_id:
o bien un:
slug:
El slug del objeto. Si se utiliza este argumento, es obligatorio especicar un valor para el
argumento
slug_field
Argumentos opcionales
allow_future:
Un valor booleano que indica si deben incluirse o no en esta vista las fechas en el
futuro.
day_format:
Equivalente a
month_format,
" %d"
(que es el
da del mes como nmero decimal y relleno con ceros de ser necesario; 01-31).
month_format:
month.
Una cadena de texto que determina el formato que debe usar el parmetro
slug_field:
El nombre del atributo que almacena el valor del slug. Es obligatorio incluirlo si se ha
usado el argumento
de
de tex-
to
la vista
'foo.html',
y denes
Esta vista tambin acepta los siguientes argumentos comunes (Vase la Tabla D-1):
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
Nombre de la plantilla
Si no se ha especicado ningn valor en
Contexto de la plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
object: El object. El nombre de esta variable depende del parmetro template_object_name, que es
object por defecto. Si template_object_name fuera foo, el nombre de esta variable sera foo.
D.5.
El mdulo
Django.views.generic.create_update
objetos.
Nota
Estas vistas pueden cambiar ligeramente en la nueva revisin de la arquitectura de formularios de
Django (que est en fase de desarrollo con el nombre
Todas estas vistas presenta formularios si se acceden con
si se acceden con
POST.
django.newforms).
Estas vistas tienen un concepto muy simple de la seguridad. Aunque aceptan un argumento llamado
login_required,
que restringe el acceso slo a usuarios identicados, no hacen nada ms. Por ejemplo, no comprueban que el usuario
que est modicando un objeto sea el mismo usuario que lo creo, ni validarn ningn tipo de permisos.
En cualquier caso, la mayor parte de las veces se puede conseguir esta funcionalidad simplemente escribiendo un
pequeo recubrimiento alrededor de la vista genrica. Para ms informacin sobre esta tcnica, vase el Captulo 9.
revisin 757 del 28 de julio de 2008
310
D.5.1.
Vista a importar :
django.views.generic.create_update.create_object
Esta vista presenta un formulario que permite la creacin de un objeto. Cuando se envan los datos del formulario,
la vista se vuelve a mostrar si se produce algn error de validacin (incluyendo, por supuesto, los mensajes pertinentes)
o, en caso de que no se produzca ningn error de validacin, salva el objeto en la base de datos.
Ejemplo
Si quisiramos permitir al usuario que creara nuevos libros en la base de datos, podramos hacer algo como esto:
model:
Nota
Obsrvese que esta vista espera el modelo del objeto a crear, y no un
Argumentos opcionales
post_save_redirect:
no se especica, se tomar de
object.get_absolute_url()
post_save_redirect: puede contener cadenas de formato para diccionarios, cuyos valores se interpolarn usando los nombres de los atributos del objeto. Por ejemplo, se podra usar: post_save_redirect="/polls/ %(slug)s
login_required: Un valor booleano que obliga a que la operacin la realice un usuario identicado,
ya sea para ver el formulario o para realizar la operacin de creacin del objeto. Utiliza el subsistema
de autenticacin y seguridad de Django. Por defecto, su valor es
True,
False.
/accounts/login/
Esta vista tambin acepta los siguientes argumentos comunes (Vase la Tabla D-1):
context_processors
extra_context
template_loader
template_name
Nombre de la plantilla
Si no se ha especicado ningn valor en
Contexto de la plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
form:
FormWrapper,
referirte de una forma sencilla a los campos del formulario desde la plantilla. Por ejemplo, si el modelo
consta de dos atributos,
name
address:
311
D.5.2.
Vista a importar :
django.views.generic.create_update.update_object
Esta vista es prcticamente igual al anterior, siendo la nica diferencia que esta permite la modicacin de los
atributos del objeto, en vez de su creacin.
Ejemplo
Siguiendo con el ejemplo, podemos proporcionar al usuario una interfaz de modicacin de los datos de un libro
con el siguiente cdigo en el URLconf:
model: El modelo
QuerySet.
tipo
Y, o bien un:
object_id:
o bien un:
slug: El slug
slug_field.
Argumentos opcionales
slug_field: El nombre del campo en el que se almacena el valor del slug del sujeto. Es obligado usar
slug, pero no debe especicarse si hemos optado por
identicar el objeto mediante su calve primaria, usando el argumento object_id.
Esta vista acepta los mismos argumentos opcionales que la vista de creacin y, adems, el argumento comn
template_object_name,
Nombre de la plantilla
Esta vista utiliza el mismo nombre de plantilla por defecto que la vista de creacin (<app_label>/<model_name>_form.htm
312
Contexto de la plantilla
Adems de los valores que se puedan haber denido en
extra_context,
siguientes valores:
form:
Una instancia de
FormWrapper
object:
El objeto a editar (El nombre de esta variable puede ser diferente si se ha especicado el
argumento
D.5.3.
template_object_name).
Vista a importar :
django.views.generic.create_update.delete_object
Esta vista es muy similar a la dos anteriores: crear y modicar objetos. El propsito de esta es, sin embargo,
permitir el borrado de objetos.
Si la vista es alimentada mediante
GET,
POST,
Los argumentos son los mismos que los de la vista de modicacin, as como las variables de contexto. El nombre
de la plantilla por defecto para esta vista es
<app_label>/<model_name>_confirm_delete.html.
Apndice E
Variables de conguracin
Tu archivo de conguracin contiene toda la conguracin de tu instalacin de Django. Este apndice explica cmo
funcionan las variables de conguracin y qu variables de conguracin estn disponibles.
Nota
A medida que Django crece, es ocasionalmente necesario agregar o (raramente) cambiar variables
de conguracin. Debes siempre buscar la informacin mas reciente en la documentacin de
conguracin en lnea que se encuentra en
0.96/settings/.
E.1.
http://www.djangoproject.com/documentation/
Qu es un archivo de conguracin
DEBUG = False
DEFAULT_FROM_EMAIL = '[email protected]'
TEMPLATE_DIRS = ('/home/templates/mike', '/home/templates/john')
Debido a que un archivo de conguracin es un mdulo Python, las siguientes armaciones son ciertas:
Debe ser cdigo Python vlido; no se permiten los errores de sintaxis.
El mismo puede asignar valores a las variables dinmicamente usando sintaxis normal de Python, por
ejemplo:
E.1.1.
No es necesario que un archivo de conguracin de Django dena una variable de conguracin si es que no es
necesario. Cada variable de conguracin tiene un valor por omisin sensato. Dichos valores por omisin residen en el
archivo
django/conf/global_settings.py.
Este es el algoritmo que usa Django cuando compila los valores de conguracin:
Carga las variables de conguracin desde
global_settings.
E.1.2.
global_settings,
Existe una manera fcil de ver cules de tus variables de conguracin dieren del valor por omisin. El comando
manage.py diffsettings
visualiza las diferencias entre el archivo de conguracin actual y los valores por omisin
de Django.
manage.py
314
E.1.3.
django.conf.settings,
por
ejemplo:
de conguracin individualmente.
from django.conf.settings import DEBUG # This won't work.
y variables de conguracin especcas de un sitio; presenta una nica interfaz. Tambin desacopla el cdigo que usa
variables de conguracin de la ubicacin de dicha conguracin.
E.1.4.
No debes alterar variables de conguracin en tiempo de ejecucin. Por ejemplo, no hagas esto en una vista:
# Don't do this!
E.1.5.
settings
es en un archivo de conguracin.
Seguridad
Debido que un archivo de conguracin contiene informacin importante, tal como la contrasea de la base de
datos, debes hacer lo que est e tus manos para limitar el acceso al mismo. Por ejemplo, cambia los permisos de acceso
en el sistema de archivos de manera que solo tu y el usuario de tu servidor Web puedan leerlo. Esto es especialmente
importante en un entorno de alojamiento compartido.
E.1.6.
No existe nada que impida que crees tus propias variables de conguracin, para tus propias aplicaciones Django.
Slo sigue las siguientes convenciones:
Usa nombres de variables en maysculas.
Para conguraciones que sean secuencias, usa tuplas en lugar de listas. Las variables de conguracin
deben ser consideradas inmutables y no deben ser modicadas una vez que se las ha denido. El usar
tuplas reeja esa semntica.
No reinventes una variable de conguracin que ya existe.
E.2.
Cuando usas Django tienes que indicarle qu conguracin ests usando. Haz esto mediante el uso de de la variable
de entorno
DJANGO_SETTINGS_MODULE.
DJANGO_SETTINGS_MODULE
El valor de
mysite.settings.
Notar que el mdulo de conguracin debe ser encontrarse en la ruta de bsqueda para las importaciones de Python
(PYTHONPATH).
Consejo:
Puedes
encontrar
una
buena
gua
acerca
de
PYTHONPATH`
http://diveintopython.org/getting_to_know_python/everything_is_an_object.html.
en
E.2.1.
315
La utilidad django-admin.py
Cuando usas
django-admin.py
(ver Apndice G), puedes ya sea jar el valor de la variable de entorno una vez o
export DJANGO_SETTINGS_MODULE=mysite.settings
django-admin.py runserver
Este es otro ejemplo, esta vez usando el shell de Windows:
set DJANGO_SETTINGS_MODULE=mysite.settings
django-admin.py runserver
Usa el argumento de lnea de comandos
manage.py creada por startproject como parte del esqueleto del proyecto asigna un valor a DJANGO_SETTINGS_
manage.py.
E.2.2.
En el servidor (mod_python)
En tu entorno del servidor activo, necesitars indicarle a Apache/mod_python qu archivo de conguracin debe
usar. Haz eso con
SetEnv:
<Location "/mysite/">
SetHandler python-program
PythonHandler django.core.handlers.modpython
SetEnv DJANGO_SETTINGS_MODULE mysite.settings
</Location>
Para ms informacin, revisa la documentacin en lnea de mod_python en
documentation/0.96/modpython/.
E.3.
http://www.djangoproject.com/
DJANGO_SETTINGS_MODULE.
el sistema de plantillas en forma aislada, muy probablemente no desears tener que preparar una variable de entorno
que apunte a un mdulo de conguracin.
En esos casos, puedes jar los valores de las variables de conguracin de Django manualmente. Haz esto llamando
django.conf.settings.configure().
Este es un ejemplo:
configure()
tantos argumentos de palabra clave como desees, con cada argumento representando una
variable de conguracin y su valor. Cada nombre de argumento debe estar escrito totalmente en maysculas, con
el mismo nombre que que la variable de conguracin que ya se describieron. Si una variable de conguracin no es
pasada a
configure()
El congurar Django de esta manera es en general necesario -- y, en efecto, recomendado -- cuando usas una parte
del framework dentro de una aplicacin ms grande.
En consecuencia, cuando es congurado va
porqu habra de ocurrir esto). Asumimos que en esos casos ya tienes completo control de tu entorno.
revisin 757 del 28 de julio de 2008
316
E.3.1.
Si te gustara que los valores por omisin provinieran desde otra ubicacin diferente a
django.conf.global_settings,
default_settings
puedes pasarle un mdulo o clase que provea las variables de conguracin por omisin como el argumento
(o como el primer argumento posicional) en la llamada a
configure().
DEBUG
en
True,
myapp_defaults:
independientemente de su valor en
myapp-defaults,
y se ja el valor de
myapp_defaults
django.conf.settings.global_settings
E.3.2.
DJANGO_SETTINGS_MODULE,
debes llamar a
configure()
en algn punto
E.4.
Las siguientes secciones consisten de una lista completa de todas las variables de conguracin en orden alfabtico,
y sus valores por omisin.
E.4.1.
ABSOLUTE_URL_OVERRIDES
{}
(diccionario vaco)
ABSOLUTE_URL_OVERRIDES = {
'blogs.weblog': lambda o: "/blogs/ %s/" % o.slug,
'news.story': lambda o: "/stories/ %s/ %s/" % (o.pub_year, o.slug),
}
Notar que el nombre del modelo usado en esta variable de conguracin debe estar escrito totalmente en maysculas,
con independencia de la combinacin de maysculas y minsculas del nombre real de la clase del modelo.
E.4.2.
ADMIN_FOR
()
(lista vaca)
Esta variable de conguracin es usada en mdulos de conguracin de sitios de administracin. Debe ser una
tupla de mdulos de conguracin (en el formato
'foo.bar.baz')
administracin.
El sitio de administracin usa esto en la documentacin automticamente introspeccionada de modelos, vistas y
etiquetas de plantillas.
revisin 757 del 28 de julio de 2008
E.4.3.
317
ADMIN_MEDIA_PREFIX
'/media/'
Esta variable de conguracin es el prejo de la URL para los medios del sitio de administracin: CSS, JavaScript
e imgenes. Asegrate de usar una barra al nal.
E.4.4.
ADMINS
()
(tupla vaca)
Una tupla que enumera las personas que recibirn noticaciones de errores en el cdigo. Cuando
DEBUG=False
una vista laza una excepcin, Django enviar a esta gente un e-mail con la informacin completa de la informacin.
Cada miembro de la tupla debe ser una tupla de (Nombre completo, direccin de e-mail), por ejemplo:
E.4.5.
ALLOWED_INCLUDE_ROOTS
()
(tupla vaca)
Una tupla de cadenas que representan prejos permitidos para la etiqueta de plantillas
medida de seguridad, que impide que los autores de plantillas puedan acceder a archivos a los que no deberan acceder.
Por ejemplo, si
funcionara pero
E.4.6.
APPEND_SLASH
True
Esta variable de conguracin indica si debe anexarse barras al nal de las URLs. Se usa solamente si est instalado
CommonMiddleware
E.4.7.
CACHE_BACKEND
PREPEND_WWW.
'simple://'
E.4.8.
CACHE_MIDDLEWARE_KEY_PREFIX
''
(cadena vaca)
El prejo de las claves de cache que debe usar el middleware de cache (ver Captulo 13).
E.4.9.
DATABASE_ENGINE
''
(cadena vaca)
'sqlite3'.
'postgresql_psycopg2',
DATABASE_HOST
''
(cadena vaca)
Esta variable de conguracin indica qu equipo debe usarse cuando se establezca una conexin a la base de datos.
Una cadena vaca signica
localhost.
Si este valor comienza con una barra (/) y ests usando MySQL, MySQL se conectar al socket va un socket Unix:
DATABASE_HOST = '/var/run/mysql'
Si ests usando MySQL este valor no comienza con una barra, entonces se asume que el mismo es el nombre del
equipo.
318
E.4.11.
DATABASE_NAME
''
(cadena vaca)
El nombre de la base de datos a usarse. Para SQLite, es la ruta completa al archivo de la base de datos.
E.4.12.
DATABASE_OPTIONS
{}
(diccionario vaco)
Parmetros extra a usarse cuando se establece la conexin a la base de datos. Consulta el mdulo back-end para
conocer las palabras claves disponibles.
E.4.13.
DATABASE_PASSWORD
''
(cadena vaca)
Esta variable de conguracin es la contrasea a usarse cuando se establece una conexin a la base de datos. No
se usa con SQLite.
E.4.14.
DATABASE_PORT
''
(cadena vaca)
El puerto a usarse cuando se establece una conexin a la base de datos. Una cadena vaca signica el puerto por
omisin. No se usa con SQLite.
E.4.15.
DATABASE_USER
''
(cadena vaca)
Esta variable de conguracin es el nombre de usuario a usarse cuando se establece una conexin a la base da
datos. No se usa con SQLite.
E.4.16.
DATE_FORMAT
'N j, Y'
(por ej.
Feb. 4, 2003)
El formato a usar por omisin para los campos de fecha en las pginas lista de cambios en el sitio de administracin
de Django -- y, posiblemente, por otras partes del sistema. Acepta el mismo formato que la etiqueta
F, Tabla F-2).
Ver tambin
E.4.17.
MONTH_DAY_FORMAT.
DATETIME_FORMAT
'N j, Y, P'
(por ej.
El formato a usar por omisin para los campos de fecha-hora en las pginas lista de cambios en el sitio de administracin de Django -- y, posiblemente, por otras partes del sistema. Acepta el mismo formato que la etiqueta
Apndice F, Tabla F-2).
Ver tambin
E.4.18.
now
ver
MONTH_DAY_FORMAT.
DEBUG
False
ofensivo).
Si embargo, nota que siempre existirn secciones de la salida de depuracin que son inapropiadas para el consumo
del pblico. Rutas de archivos, opciones de conguracin y similares le proveen a potenciales atacantes informacin
extra acerca de tu servidor. Nunca instales un sitio con
DEBUG
activo.
E.4.19.
319
DEFAULT_CHARSET
'utf-8'
E.4.20.
DEFAULT_CONTENT_TYPE
'text/html'
DEFAULT_CHARSET
objetos HttpResponse.
E.4.21.
HttpResponse,
si no se especica manualmente un
Content-Type.
Ver el Apndice H
DEFAULT_FROM_EMAIL
'webmaster@localhost'
La direccin de correo a usar por omisin para correspondencia automatizada enviada por el administrador del
sitio.
E.4.22.
DISALLOWED_USER_AGENTS
()
(tupla vaca)
Una lista de objetos expresiones regulares compiladas que representan cadenas User-Agent que no tiene permitido
visitar ninguna pgina del sitio, a nivel global para el sitio. Usa la misma para bloquear robots y crawlers con mal
comportamiento. Se usa nicamente si se ha instalado
E.4.23.
EMAIL_HOST
'localhost'
E.4.24.
CommonMiddleware
EMAIL_PORT.
EMAIL_HOST_PASSWORD
''
(cadena vaca)
EMAIL_HOST_USER
EMAIL_HOST.
E.4.25.
EMAIL_HOST_USER.
EMAIL_HOST_USER
''
(cadena vaca)
E.4.26.
EMAIL_HOST_PASSWORD.
EMAIL_PORT
25
E.4.27.
EMAIL_HOST.
EMAIL_HOST.
EMAIL_SUBJECT_PREFIX
'[Django] '
django.core.mail.mail_admins o django.core.mail.mail_ma
320
E.4.28.
FIXTURE_DIRS
()
(tupla vaca)
Notar que esas rutas deben usar barras de estilo Unix an en Windows. Es usado por el framework de pruebas de
Django, el cual se trata en
E.4.29.
http://www.djangoproject.com/documentation/0.96/testing/.
IGNORABLE_404_ENDS
E.4.30.
IGNORABLE_404_STARTS
Una tupla de cadenas que especican las partes iniciales de URLs que deben ser ignoradas para el envo de mensajes
de e-mail para errores 404. Ver tambin
E.4.31.
SEND_BROKEN_LINK_EMAILS
IGNORABLE_404_ENDS.
INSTALLED_APPS
()
(tupla vaca)
Una tupla de cadenas que indican todas las aplicaciones que estn activas en esta instalacin de Django. Cada
cadena debe ser una ruta completa de Python hacia un paquete Python que contiene una aplicacin Django. Ver el
Captulo 5 para ms informacin acerca de aplicaciones.
E.4.32.
INTERNAL_IPS
()
(tupla vaca)
E.4.33.
DEBUG
es
XViewMiddleware
True
(ver Captulo 15)
JING_PATH
'/usr/bin/jing'
La ruta al ejecutable Jing. Jing es un validador RELAX NG, y Django usa el mismo para validar los campos
XMLField
E.4.34.
http://www.thaiopensource.com/relaxng/jing.html.
LANGUAGE_CODE
'en-us'
Una cadena representando el cdigo de idioma para esta instalacin. Debe estar expresado usando el formato
estndar -- por ejemplo, Ingls de EUA es en-us. Ver el Captulo 18.
E.4.35.
LANGUAGES
Valor por omisin : Una tupla de todos los idiomas disponibles. Esta lista est en continuo crecimiento y cualquier
copia que incluyramos aqu inevitablemente quedara rpidamente desactualizada. Puedes ver la lista actual de idiomas
traducidos examinando
django/conf/global_settings.py.
La lista es una tupla de tuplas de dos elementos en el formato (cdigo de idioma, nombre de idioma) -- por ejemplo,
('ja', 'Japanese').
Especica qu idiomas estn disponibles para la seleccin de idioma. Ver el Captulo 18 para
gettext()
321
gettext = lambda s: s
LANGUAGES = (
('de', gettext('German')),
('en', gettext('English')),
)
Con este esquema,
make-messages.py
traduccin no ocurrir en tiempo de ejecucin -- as que tendrs que recordar envolver los idiomas con la
E.4.36.
LANGUAGES
MANAGERS
()
(tupla vaca)
SEND_BROKEN_LINK_EMAILS
E.4.37.
tiene el valor
MEDIA_ROOT
''
(cadena vaca)
Una ruta absoluta al directorio que contiene medios para esta instalacin (por ej.
Ver tambin
E.4.38.
gettext()
en tiempo de ejecucin.
MEDIA_URL.
"/home/media/media.lawrence.com/").
MEDIA_URL
''
(cadena vaca)
MEDIA_ROOT
(por ej.
"http://media.lawrence.com").
Notar que esta debe tener una barra nal si posee un componente de ruta:
Correcto :
"http://www.example.com/static/"
Incorrecto :
E.4.39.
"http://www.example.com/static"
MIDDLEWARE_CLASSES
("django.contrib.sessions.middleware.SessionMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.middleware.common.CommonMiddleware",
"django.middleware.doc.XViewMiddleware")
Una tupla de clases middleware a usarse. Ver el Captulo 15.
E.4.40.
MONTH_DAY_FORMAT
'F j'
El formato a usar por omisin para campos de fecha en las pginas de lista de cambios en la aplicacin de
administracin de Django -- y, probablemente, en otras partes del sistema -- en casos en los que slo se muestran el
mes y el da. Acepta el mismo formato que la etiqueta
now
Por ejemplo, cuando en una pgina de lista de cambios la aplicacin de administracin de Django se ltra por una
fecha, la cabecera para un da determinado muestra el da y mes. Diferentes locales tienen diferentes formatos. Por
ejemplo, el Ingls de EUA tendra January 1 mientras que Espaol podra tener 1 Enero.
Ver tambin
E.4.41.
YEAR_MONTH_FORMAT.
PREPEND_WWW
False
Esta variable de conguracin indica si se debe agregar el prejo de subdominio www. a URLs que no lo poseen.
Se usa nicamente si
CommonMiddleware
APPEND_SLASH.
322
E.4.42.
PROFANITIES_LIST
Una tupla de profanidades, como cadenas, que dispararn un error de validacin cuando se llama al validador
hasNoProfanities.
No enumeramos aqu los valores por omisin, debido a que esto podra hacer que nos cayera encima la comisin de
django/conf/global_settings.py.
clasicacin de la MPAA. Para ver los valores por omisin examina el archivo
E.4.43.
ROOT_URLCONF
"mydjangoapps.urls").
Ver Captulo 3.
E.4.44.
SECRET_KEY
startproject
E.4.45.
django-admin
crea una en forma automtica y en la mayora de los casos no ser necesario que la modiques.
SEND_BROKEN_LINK_EMAILS
False
MANAGERS
una pgina impulsada por Django que generar un error 404 y que posea una cabecera referer no vaca (en otras
palabras un enlace roto). Es solamente usado si est instalado
IGNORABLE_404_STARTS
E.4.46.
IGNORABLE_404_ENDS.
CommonMiddleware
SERIALIZATION_MODULES
http://www.djangoproject.com/documentation/0.96/serialization/
E.4.47.
si deseas ms informacin.
SERVER_EMAIL
'root@localhost'
La direccin de e-mail a usarse como remitente para los mensajes de error, tales como los enviados a
MANAGERS.
E.4.48.
ADMINS
SESSION_COOKIE_AGE
1209600
E.4.49.
SESSION_COOKIE_DOMAIN
None
El dominio a usarse para las cookies de sesin. Asigna como valor una cadena tal como
cookies inter-dominio, o usa
E.4.50.
None
".lawrence.com"
SESSION_COOKIE_NAME
'sessionid'
El nombre de la cookie a usarse para las sesiones; puede tener el valor que tu desees. Ver Captulo 12.
para
E.4.51.
323
SESSION_COOKIE_SECURE
False
Esta variable de conguracin indica si debe usarse una cookie segura para la cookie de sesin. Si tiene un valor
True, la cookie ser marcada como segura, lo que signica que los navegadores podran asegurarse que la cookie slo
se enve va una conexin HTTPS. Ver Captulo 12.
E.4.52.
SESSION_EXPIRE_AT_BROWSER_CLOSE
False
Esta variable de conguracin indica si las sesiones deben caducar cuando el usuario cierre su navegador. Ver
Captulo 12.
E.4.53.
SESSION_SAVE_EVERY_REQUEST
False
Esta variable de conguracin indica si la sesin debe ser grabada en cada peticin. Ver Captulo 12.
E.4.54.
SITE_ID
que datos de aplicacin puede conectarse en sitio(s) especco(s) y una nica base de datos pueda manejar contenido
de mltiples sitios. Ver Captulo 14.
E.4.55.
TEMPLATE_CONTEXT_PROCESSORS
("django.core.context_processors.auth",
"django.core.context_processors.debug",
"django.core.context_processors.i18n")
Una tupla de
RequestContext.
Esos
*callables* reciben
`Captulo
como argumento un objeto peticin y retornan un diccionario de items a ser fusionados con el contexto. Ver
10`_.
E.4.56.
TEMPLATE_DEBUG
False
True la pgina
TemplateSyntaxError. Este reporte contiene los fragmentos
DEBUG
es
True,
E.4.57.
DEBUG.
TEMPLATE_DIRS
()
(tupla vaca)
Un lista de ubicaciones de los archivos de cdigo fuente de plantillas, en el orden en el que sern examinadas. Notar
que esas rutas deben usar barras al estilo Unix, aun en Windows. Ver Captulos 4 y 10.
E.4.58.
TEMPLATE_LOADERS
('django.template.loaders.filesystem.load_template_source',)
*callables* (como cadenas) que saben como importar plantillas desde diferentes orgenes. Ver
`Captulo 10`_.
324
E.4.59.
TEMPLATE_STRING_IF_INVALID
''
(cadena vaca)
La salida, como una cadena, que debe usar el sistema de plantillas para variables invlidas (por ej. con errores de
sintaxis en el nombre). Ver Captulo 10.
E.4.60.
TEST_RUNNER
'django.test.simple.run_tests'
El nombre del mtodo a usarse para arrancar la batera de pruebas (por test suite ). Es usado por el framework de
pruebas de Django, el cual se describe en lnea en
E.4.61.
http://www.djangoproject.com/documentation/0.96/testing/.
TEST_DATABASE_NAME
None
El nombre de la base de datos a usarse cuando se ejecute la batera de pruebas (por test suite ). Si se especica un
None, el nombre de la base de datos de pruebas ser 'test_' + settings.DATABASE_NAME. Ver la documentacin
http://www.djangoproject.com/documentation/
0.96/testing/.
valor
E.4.62.
TIME_FORMAT
'P'
(e.g.,
4 p.m.)
El formato a usar por omisin para los campos de hora en las pginas lista de cambios en el sitio de administracin
de Django -- y, posiblemente, por otras partes del sistema. Acepta el mismo formato que la etiqueta
F, Tabla F-2).
Ver tambin
E.4.63.
MONTH_DAY_FORMAT.
TIME_ZONE
'America/Chicago'
Una cadena que representa la zona horaria para esta instalacin. Las zonas horarias se expresan en el forma-
to
zic
estndar de Unix. Puede encontrarse una lista relativamente completa de cadenas de zonas horarias en
http://www.postgresql.org/docs/8.1/static/datetime-keywords.html#DATETIME-TIMEZONE-SET-TABLE.
Esta es la zona a la cual Django convertir todas las fechas/horas -- no necesariamente la zona horaria del servidor.
Por ejemplo, un servidor podra servir mltiples sitios impulsados por Django, cada uno con una conguracin de zona
horaria separada.
Normalmente, Django ja la variable
guracin
TIME_ZONE.
os.environ['TZ']
Por lo tanto, todas tus vistas y modelos operarn automticamente en la zona horaria correcta.
Sin embargo, si ests usando el mtodo de conguracin manual (descrito arriba en la seccin Usando variables de
conguracin sin jar DJANGO_SETTINGS_MODULE ) Django no tocar la variable de entorno
TZ y quedar en
Nota
Django no puede usar en forma conable zonas horarias alternativas en un entorno Windows. Si
ests ejecutando Django en Windows debes asignar a esta variable un valor que coincida con la
zona horaria del sistema.
E.4.64.
URL_VALIDATOR_USER_AGENT
Django/<version> (http://www.djangoproject.com/)
User-Agent cuando se realizan vericaciones
verify_exists de URLField; ver Apndice B).
E.4.65.
USE_ETAGS
False
E.4.66.
325
USE_I18N
True
Este Booleano especica si debe activarse el sistema de internacionalizacin de Django (ver Captulo 18). Provee
una forma sencilla de desactivar la internacionalizacin, para mejorar el rendimiento. Si se asigna a esta variable el
valor
False Django realizar algunas optimizaciones de manera que no se cargue la maquinaria de internacionalizacin.
E.4.67.
YEAR_MONTH_FORMAT
'F Y'
El formato a usar por omisin para los campos de fecha en las pginas lista de cambios en el sitio de administracin
de Django -- y, posiblemente, por otras partes del sistema- en los casos en los que slo se muestran el mes y el ao.
Acepta el mismo formato que la etiqueta
now
Por ejemplo, cuando se est ltrando una pgina lista de cambios de la aplicacin de administracin de Django
mediante un detalle de fecha, la cabecera de un mes determinado muestra el mes y el ao. Los distintos locales
tienen diferentes formatos. Por ejemplo, el Ingls de EUA usara January 2006 mientras que otro locale podra usar
2006/January.
Ver tambin
MONTH_DAY_FORMAT.
326
Apndice F
F.1.
F.1.1.
Etiquetas predenidas
block
Dene un bloque que puede ser sobreescrito por las plantillas derivadas. Vase la seccin acerca de herencia de
plantillas en el Captulo 4 para ms informacin.
F.1.2.
comment
F.1.3.
{ % comment %}
{ % endcomment %}.
cycle
Rota una cadena de texto entre diferentes valores, cada vez que aparece la etiqueta.
Dentro de un bucle, el valor rotan entre los distintos valores disponibles en cada iteracin del bucle:
{ % for o in some_list %}
<tr class="{ % cycle row1,row2 %}">
...
</tr>
{ % endfor %}
Fuera de un bucle, hay que asignar un nombre nico la primera vez que se usa la etiqueta, y luego hay que incluirlo
ese nombre en las sucesivas llamadas:
328
F.1.4.
debug
Muestra un montn de informacin para depuracin de errores, incluyendo el contexto actual y los mdulos importados.
F.1.5.
extends
Sirve para indicar que esta plantilla extiende una plantilla padre.
Esta etiqueta se puede usar de dos maneras:
{ % extends "base.html" %} (Con las comillas) interpreta literalmente "base.html" como el nombre
de la plantilla a extender.
{ % extends variable %}
usa el valor de
variable.
Django usar dicha cadena como el nombre de la plantilla padre. Si la variable es un objeto de tipo
Template,
F.1.6.
lter
{ % filter escape|lower %}
This text will be HTML-escaped, and will appear in all lowercase.
{ % endfilter %}
F.1.7.
rstof
Presenta como salida la primera de las variables que se le pasen que evale como no falsa. La salida ser nula si
todas las variables pasadas valen
False.
He aqu un ejemplo:
{ % if var1 %}
{{ var1 }}
{ % else %}{ % if var2 %}
{{ var2 }}
{ % else %}{ % if var3 %}
{{ var3 }}
{ % endif %}{ % endif %}{ % endif %}
F.1.8.
for
Itera sobre cada uno de los elementos de un lista o array. Por ejemplo, para mostrar una lista de atletas, cuyos
nombres estn en la lista
athlete_list,
podramos hacer:
<ul>
{ % for athlete in athlete_list %}
<li>{{ athlete.name }}</li>
{ % endfor %}
</ul>
{ % for obj in list reversed %}.
for crea una serie de variables. A estas variables se puede acceder nicamente
329
Variable
Descripcin
forloop.counter
forloop.counter0
forloop.revcounter
forloop.revcounter0
forloop.first
forloop.last
forloop.parentloop
F.1.9.
True
True
si es la primera iteracin.
si es la ltima iteracin.
if
La etiqueta
{ % if %}
evalua una variable. Si dicha variable se evalua como una expresin verdadera (Es decir,
False),
{ % if athlete_list %}
Number of athletes: {{ athlete_list|length }}
{ % else %}
No athletes.
{ % endif %}
}}
Si la lista
athlete_list no est vaca, podemos mostrar el nmero de atletas con la expresin {{ athlete_list|length
if
if
and, or
not
{ % else %}
que se
if no admite, sin embargo, mezclar los operadores and y or dentro de la misma comprobacin, porque
la orden de aplicacin de los operadores lgicos sera ambigua. Por ejemplo, el siguiente cdigo es invlido:
and
or,
if
330
{ % if athlete_list %}
{ % if coach_list or cheerleader_list %}
We have athletes, and either coaches or cheerleaders!
{ % endif %}
{ % endif %}
Es perfectamente posible usar varias veces un operador lgico, siempre que sea el mismo siempre. Por ejemplo, el
siguiente cdigo es vlido:
ifchanged
ifchanged
F.1.11.
ifequal
Muestra el contenido del bloque si los dos argumentos suministrados son iguales.
He aqu un ejemplo:
{ % if %},
{ % else %}
opcional.
Los argumentos pueden ser cadenas de texto, as que el siguiente cdigo es vlido:
True
F.1.12.
False.
if
directamente.
ifnotequal
Es igual que
ifequal,
excepto que comprueba que los dos parmetros suministrados no sean iguales.
F.1.13.
331
include
Carga una plantilla y la representa usando el contexto actual. Es una forma de incluir una plantilla dentro de
otra.
El nombre de la plantilla puede o bien ser el valor de una variable o estar escrita en forma de cadena de texto,
rodeada ya sea con comillas simples o comillas dobles, a gusto del lector.
El siguiente ejemplo incluye el contenido de la plantilla
"foo/bar.html":
{ % include "foo/bar.html" %}
Este otro ejemplo incluye el contenido de la plantilla cuyo nombre sea el valor de la variable
template_name:
{ % include template_name %}
F.1.14.
load
de plantillas.
F.1.15.
now
net/date).
date()
Carc. formato
a
Descripcin
'a.m.'
'p.m.'.
Ejemplo de salida
(Obsrvese que
'a.m.'
'AM'
'PM'.
'AM'
'jan'
'01'
'31'
Da de la semana, en forma de
'Fri'
'1', '1:30'
'January'
'1' a '12'
'0'
'23'
Minutos.
'01'
'00'
'00'
a
a
a
'12'
'23'
'59'
332
Carc. formato
j
Descripcin
Ejemplo de salida
'1'
'31'
'Friday'
True o False
bisiesto.
m
'01'
'12'
'Jan'
'1' a '12'
'Jan.', 'Feb.' , 'March', 'May'
'+0200'
se
usarn
de texto especiales
'noon'
las
cadenas
'midnight'
para la medianoche y el
medioda respectivamente.
r
'th'
28 a 31
'EST', 'MDT'
'0' (Domingo)
'6'
(dos caracteres).
t
Zona horaria
Da de la semana, en forma de d-
(Sbado)
gito.
W
1, 23
Da del ao
'99'
'1999'
0 a 365
-43200 a 43200
He aqu un ejemplo:
333
como una indicacin de incluir la hora. La o, por otro lado, no necesita ser escapada, ya que no es un carcter de
formato:
F.1.16.
regroup
Person,
first_name, last_name
como el siguiente:
* Male:
* George Bush
* Bill Clinton
* Female:
* Margaret Thatcher
* Condoleezza Rice
* Unknown:
* Pat Smith
El siguiente fragmento de plantilla mostrara como realizar esta tarea:
{ % regroup %}
atributo que se quiere agrupar. Esto signica que si la lista del ejemplo no est ordenada por el sexo, debes asegurarte
de que se ordene antes correctamente, por ejemplo con el siguiente cdigo:
spaceless
Elimina los espacios en blanco entre etiquetas Html. Esto incluye tabuladores y saltos de lnea.
El siguiente ejemplo:
{ % spaceless %}
<p>
<a href="foo/">Foo</a>
</p>
{ % endspaceless %}
Retornara el siguiente cdigo HTML:
<p><a href="foo/">Foo</a></p>
revisin 757 del 28 de julio de 2008
334
Slo se eliminan los espacios entre las etiquetas, no los espacios entre la etiqueta y el texto. En el siguiente ejemplo,
no se quitan los espacios que rodean la palabra
Hello:
{ % spaceless %}
<strong>
Hello
</strong>
{ % endspaceless %}
F.1.18.
ssi
{ % ssi %} incluye el contenido de otro chero (que debe ser especicado usando
{ % ssi /home/html/ljworld.com/includes/right_generic.html %}
Si se le pasa el parmetro opcional parsed, el contenido del chero incluido se evala como si fuera cdigo de
plantilla, usando el contexto actual:
{ % ssi %},
{ % include %} funcionar mejor que { % ssi %}; esta se ha incluido slo para garantizar
F.1.19.
templatetag
Permite representar los caracteres que estn denidos como parte del sistema de plantillas.
Como el sistema de plantillas no tiene el concepto de escapar el signicado de las combinaciones de smbolos que
usa internamente, tenemos que recurrir a la etiqueta
{ % templatetag %}
Se le pasa un argumento que indica que combinacin de smbolos debe producir. Los valores posibles del argumento
se muestran en la tabla F-3.
Cuadro F.3: Argumentos vlidos de templatetag
Argumento
openblock
closeblock
openvariable
closevariable
openbrace
closebrace
opencomment
closecomment
F.1.20.
Salida
{%
%}
{{
}}
{
}
{#
#}
url
Devuelve una URL absoluta (Es decir, una URL sin la parte del dominio) que coincide con una determinada
vista, incluyendo sus parmetros opcionales. De esta forma se posibilita realizar enlaces sin violar el principio DRY,
codicando las direcciones en nuestras plantillas:
paquete.paquete.modulo.funcion.
El resto
de parmetros son opcionales y deben ir separados con comas, convirtindose en parmetros posicionales o por nombre
que se incluirn en la URL. Deben estar presentes todos los argumentos que se hayan denido como obligatorios en el
URLconf.
335
app_name.client,
un parmetro, el identicador del cliente. La lnea del URL podra ser algo as:
('^client/(\d+)/$', 'app_name.client')
Si este URLconf fuera incluido en el URLconf del proyecto bajo un directorio, como en este ejemplo:
('^clients/', include('project_name.app_name.urls'))
Podramos crear un enlace a esta vista, en nuestra plantilla, con la siguiente etiqueta:
F.1.21.
/clients/client/123/.
widthratio
Esta etiqueta es til para presentar grcos de barras y similares. Calcula la proporcin entre un valor dado y un
mximo predenido, y luego multiplica ese cociente por una constante.
Veamos un ejemplo:
<img src="bar.gif" height="10" width="{ % widthratio this_value max_value 100 %}" />
this_value
Si
vale 175 y
max_value
F.2.
F.2.1.
Filtros predenidos
add
Ejemplo:
{{ value|add:"5" }}
Suma el argumento indicado.
F.2.2.
addslashes
Ejemplo:
{{ string|addslashes }}
Aade barras invertidas antes de las comillas, ya sean simples o dobles. Es til para pasar cadenas de texto como
javascript, por ejemplo:
F.2.3.
caprst
Ejemplo:
{{ string|capfirst }}
Pasa a maysculas la primera letra de la primera palabra.
F.2.4.
center
Ejemplo:
{{ string|center:"50" }}
Centra el texto en un campo de la anchura indicada.
F.2.5.
cut
Ejemplo:
{{ string|cut:"spam" }}
Elimina todas las apariciones del valor indicado.
revisin 757 del 28 de julio de 2008
336
F.2.6.
date
Ejemplo:
{{ value|date:"F j, Y" }}
Formatea una fecha de acuerdo al formato indicado en la cadena de texto (Se usa el mismo formato que con la
etiqueta
now).
F.2.7.
default
Ejemplo:
{{ value|default:"(N/A)" }}
Si
value
F.2.8.
default_if_none
Ejemplo:
{{ value|default_if_none:"(N/A)" }}
Si
value
F.2.9.
dictsort
Ejemplo:
{{ list|dictsort:"foo" }}
Acepta una lista de diccionarios y devuelve una lista ordenada segn la propiedad indicada en el argumento.
F.2.10.
dictsortreversed
Ejemplo:
{{ list|dictsortreversed:"foo" }}
Acepta una lista de diccionarios y devuelve una lista ordenada de forma descendente segn la propiedad indicada
en el argumento.
F.2.11.
divisibleby
Ejemplo:
{ % if value|divisibleby:"2" %}
Even!
{ % else %}
Odd!
{ % else %}
Devuelve
F.2.12.
True
escape
Ejemplo:
{{ string|escape }}
Transforma un texto que est en HTML de forma que se pueda representar en una pgina web. Concretamente,
realiza los siguientes cambios:
"&" a "&"
< a "<"
> a ">"
'"' (comilla doble) a '"'
"'" (comillas simple) a '''
revisin 757 del 28 de julio de 2008
F.2.13.
337
lesizeformat
Ejemplo:
{{ value|filesizeformat }}
Representa un valor, interpretndolo como si fuera el tamao de un chero y humanizando el resultado, de forma
que sea fcil de leer. Por ejemplo, las salidas podran ser
F.2.14.
etc.
rst
Ejemplo:
{{ list|first }}
Devuelve el primer elemento de una lista.
F.2.15.
x_ampersands
Ejemplo:
{{ string|fix_ampersands }}
&.
F.2.16.
oatformat
Ejemplos:
{{ value|floatformat }}
{{ value|floatformat:"2" }}
Si se usa sin argumento, redondea un nmero en coma otante a un nico dgito decimal (pero slo si hay una
parte decimal que mostrar), por ejemplo:
36.123
36.15
36
se representara como
se representara como
se representara como
36.2.
36.
36.1234
36
36.1.
floatformat
Si el argumento pasado a
floatformat
36.123.
36.0000.
36.1234
36
Usar
floatformat
F.2.17.
36.123.
36.
get_digit
Ejemplo:
{{ value|get_digit:"1" }}
Dado un nmero, devuelve el dgito que est en la posicin indicada, siendo 1 el dgito ms a la derecha. En caso
de que la entrada sea invlida, devolver el valor original (Si la entrada o el argumento no fueran enteros, o si el
argumento fuera inferior a 1). Si la entrada es correcta, la salida siempre ser un entero.
338
F.2.18.
join
Ejemplo:
{{ list|join:", " }}
Concatena todos los elementos de una lista para formar una cadena de texto, usando como separador el texto que
se le pasa como argumento. Es equivalente a la llamada en Python
F.2.19.
str.join(list)
length
Ejemplo:
{{ list|length }}
Devuelve la longitud del valor.
F.2.20.
length_is
Ejemplo:
{ % if list|length_is:"3" %}
...
{ % endif %}
Devuelve un valor booleano que ser verdadero si la longitud de la entrada coincide con el argumento suministrado.
F.2.21.
linebreaks
Ejemplo:
{{ string|linebreaks }}
Convierte los saltos de lnea en etiquetas
F.2.22.
<p>
<br />.
linebreaksbr
Ejemplo:
{{ string|linebreaksbr }}
Convierte los saltos de lnea en etiquetas
F.2.23.
<br />.
linenumbers
Ejemplo:
{{ string|linenumbers }}
Muestra el texto de la entrada con nmeros de lnea.
F.2.24.
ljust
Ejemplo:
{{ string|ljust:"50" }}
Justica el texto de la entrada a la izquierda utilizando la anchura indicada.
F.2.25.
lower
Ejemplo:
{{ string|lower }}
Convierte el texto de la entrada a letras minsculas.
revisin 757 del 28 de julio de 2008
F.2.26.
339
make_list
Ejemplo:
{ % for i in number|make_list %}
...
{ % endfor %}
Devuelve la entrada en forma de lista. Si la entrada es un nmero entero, se devuelve una lista de dgitos. Si es
una cadena de texto, se devuelve una lista de caracteres.
F.2.27.
phone2numeric
Ejemplo:
{{ string|phone2numeric }}
Convierte un nmero de telfono (que incluso puede contener letras) a su forma numrica equivalente. Por ejemplo
'800-COLLECT'
se transformar en
'800-2655328'.
La entrada no tiene porque ser un nmero de telfono vlido. El ltro convertir alegremente cualquier texto que
se le pase.
F.2.28.
pluralize
Ejemplo:
's'.
Ejemplo:
pprint
Ejemplo:
{{ object|pprint }}
Un recubrimiento que permite llamar a la funcin de Python
pprint.pprint.
depurado de errores.
F.2.30.
random
Ejemplo:
{{ list|random }}
Devuelve un elemento elegido al azar de la lista.
340
F.2.31.
removetags
Ejemplo:
{{ string|removetags:"br p div" }}
Elimina de la entrada una o varias clases de etiquetas [X]HTML. Las etiquetas se indican en forma de texto,
separando cada etiqueta a eliminar por un espacio.
F.2.32.
rjust
Ejemplo:
{{ string|rjust:"50" }}
Justica el texto de la entrada a la derecha utilizando la anchura indicada..
F.2.33.
slice
Ejemplo:
{{ some_list|slice:":2" }}
Devuelve una seccin de la lista.
Usa la misma sintaxis que se usa en Python para seccionar una lista. Vase http://diveintopython.org/native_data_types/lists.ht
para una explicacin.
F.2.34.
slugify
Ejemplo:
{{ string|slugify }}
Convierte el texto a minsculas, elimina los caracteres que no formen palabras (caracteres alfanumricos y carcter
subrayado), y convierte los espacios en guiones. Tambin elimina los espacios que hubiera al principio y al nal del
texto.
F.2.35.
stringformat
Ejemplo:
{{ number|stringformat:"02i" }}
Formatea el valor de entrada de acuerdo a lo especicado en el formato que se le pasa como parmetro. La sintaxis
a utilizar es idntica a la de Python, con la excepcin de que el carcter % se omite.
En
de Python.
F.2.36.
striptags
Ejemplo:
{{ string|striptags }}
Elimina todas las etiquetas [X]HTML.
F.2.37.
time
Ejemplo:
{{ value|time:"P" }}
Formatea la salida asumiendo que es una fecha/hora, con el formato indicado como argumento (Lo mismo que la
etiqueta
now).
F.2.38.
341
timesince
Ejemplos:
{{ datetime|timesince }}
{{ datetime|timesince:"other_datetime" }}
Representa una fecha como un intervalo de tiempo (por ejemplo, 4 days, 6 hours).
Acepta un argumento opcional, que es una variable con la fecha a usar como punto de referencia para calcular el
F.2.39.
timeuntil
Ejemplos:
{{ datetime|timeuntil }}
{{ datetime|timeuntil:"other_datetime" }}
timesince, excepto en que mide el tiempo desde la fecha de referencia hasta la fecha dada. Por ejemplo,
conference_date es una fecha cuyo valor es igual al 29 de junio de 2006, entonces {{
conference_date|timeuntil }} devolvera 28 days.
Es similar a
Acepta un argumento opcional, que es una variable con la fecha a usar como punto de referencia para calcular el
intervalo, si se quiere usar otra distinta del momento actual. Si
conference_date|timeuntil:from_date }}
F.2.40.
from_date
{{
devolvera 7 days.
title
Ejemplo:
{{ string|titlecase }}
Representa una cadena de texto en forma de ttulo, siguiendo las convenciones del idioma ingls (todas las palabras
con la inicial en mayscula).
F.2.41.
truncatewords
Ejemplo:
{{ string|truncatewords:"15" }}
Recorta la salida de forma que tenga como mximo el nmero de palabras que se indican en el argumento.
F.2.42.
truncatewords_html
Ejemplo:
{{ string|truncatewords_html:"15" }}
Es similar a
truncatewords, excepto que es capaz de reconocer las etiquetas HTML y, por tanto, no deja etiquetas
hurfanas. Cualquier etiqueta que se hubiera abierto antes del punto de recorte es cerrada por el propio ltro.
Es menos eciente que
truncatewords,
HTML.
F.2.43.
unordered_list
Ejemplo:
<ul>
{{ list|unordered_list }}
</ul>
342
Acepta una lista, e incluso varias listas anidadas, y recorre recursivamente las mismas representndolas en forma
de listas HTML no ordenadas, sin incluir las etiquetas de inicio y n de lista (<ul> y
</ul> respectivamente).
var contiene ['States', [['Kansas',
[['Lawrence', []], ['Topeka', []]]], ['Illinois', []]]], entonces {{ var|unordered_list }} retornara
Se asume que las listas est en el formato correcto. Por ejemplo, si
lo siguiente:
<li>States
<ul>
<li>Kansas
<ul>
<li>Lawrence</li>
<li>Topeka</li>
</ul>
</li>
<li>Illinois</li>
</ul>
</li>
F.2.44.
upper
Ejemplo:
{{ string|upper }}
Convierte una string a maysculas.
F.2.45.
urlencode
Ejemplo:
F.2.46.
urlize
Ejemplo:
{{ string|urlize }}
Transforma un texto de entrada, de forma que si contiene direcciones URL en texto plano, las convierte en enlaces
HTML.
F.2.47.
urlizetrunc
Ejemplo:
{{ string|urlizetrunc:"30" }}
Convierte las direcciones URL de un texto en enlaces, recortando la representacin de la URL para que el nmero
de caracteres sea como mximo el del argumento suministrado.
F.2.48.
wordcount
Ejemplo:
{{ string|wordcount }}
Devuelve el nmero de palabras en la entrada.
F.2.49.
wordwrap
Ejemplo:
{{ string|wordwrap:"75" }}
Ajusta la longitud del texto para las lneas se adecen a la longitud especicada como argumento.
revisin 757 del 28 de julio de 2008
F.2.50.
343
yesno
Ejemplo:
{{ boolean|yesno:"Yes,No,Perhaps" }}
Dada una serie de textos que se asocian a los valores de
Valor
True
False
None
None
Argumento
"yeah,no,maybe"
"yeah,no,maybe"
"yeah,no,maybe"
"yeah,no"
Salida
yeah
no
maybe
"no" (considera None como False si no se asigna ningn
texto a None.
344
Apndice G
El utilitario django-admin
django-admin.py
django-admin.py
django-admin.py:
audos
sys.path.
DJANGO_SETTINGS_MODULE
settings.py
de tu proyecto.
django-admin.py debe estar en la ruta de tu sistema si instalaste Django mediante su utilitario setup.py.
site-packages/django/bin dentro de tu instalacin de Python. Considera
establecer un enlace simblico a l desde algn lugar en tu ruta, como en /usr/local/bin.
Los usuarios de Windows, que no disponen de la funcionalidad de los enlaces simblicos, pueden copiar django-admin.py
a una ubicacin que est en su ruta existente o editar la conguracin del PATH (bajo Conguracin ~TRA Panel de
El script
Control ~TRA Sistema ~TRA Avanzado ~TRA Entorno) para apuntar a la ubicacin de su instalacin.
Generalmente, cuando se trabaja en un proyecto Django simple, es ms fcil usar
con
DJANGO_SETTINGS_MODULE
--settings,
G.1.
manage.py.
django-admin.py
Uso
options,
django-admin.py --help para ver un mensaje de ayuda que incluye una larga lista de todas las opciones
y acciones disponibles.
La mayora de las acciones toman una lista de nombres de aplicacin. Un nombre de aplicacin es el nombre base
del paquete que contiene tus modelos. Por ejemplo, si tu
de la aplicacin es
G.2.
blog.
Acciones Disponibles
346
G.2.1.
Imprime el snippet de la plantilla de admin-index para los nombres de aplicacin dados. Usa los snippets de la
plantilla de admin-index si quiere personalizar la apariencia de la pgina del ndice del administrador.
G.2.2.
createcachetable [tablename]
tablename para usar con el back-end de cache de la base de datos. Ver el Captulo
G.2.3.
dbshell
DATABASE_ENGINE,
DATABASE_USER, DATABASE_PASSWORD, etc.
Corre el cliente de lnea de comandos del motor de base de datos especicado en tu conguracin de
con los parmetros de conexin especicados en la conguracin de
psql
mysql.
sqlite3.
programa (psql,
G.2.4.
disettings
Muestra las diferencias entre la conguracin actual y la conguracin por omisin de Django.
Las conguraciones que no aparecen en la conguracin por omisin estn seguidos por
conguracin por omisin no dene
lo hace seguido de
"###".
django.conf.global_settings,
si alguna vez
G.2.5.
Dirige a la salida estndar todos los datos de la base de datos asociados con la(s) aplicacin(es) nombrada(s).
Por omisin, la base de datos ser volcada en formato JSON. Si quieres que la salida est en otro formato, usa la
--format (ej.: format=xml). Puedes especicar cualquier back-end de serializacin de Django (incluyendo cualSERIALIZATION_MODULES
setting). La opcin --indent puede ser usada para lograr una impresin diseada de la salida.
opcin
G.2.6.
dumpdata
loaddata.
ush
Devuelve la base de datos al estado en el que estaba inmediatemente despus de que se ejecut syncdb. Esto signica
que todos los datos sern eliminados de la base de datos, todo manejador de postsinchronizacin ser reejecutado, y
el componente
G.2.7.
initial_data
ser reinstalado.
inspectdb
Realiza la introspeccin sobre las tablas de la base de datos apuntada por la conguracin
un modulo de modelo de Django (un archivo
models.py)
DATABASE_NAME y enva
a la salida estndar.
Usa esto si tienes una base de datos personalizada con la cual quieres usar Django. El script inspeccionar la base
de datos y crear un modelo para cada tabla que contenga.
Como podrs esperar, los modelos creados tendrn un atributo por cada campo de la tabla. Observa que
inspectdb
inspectdb no puede mapear un tipo de columna a un tipo de campo del modelo, usar TextField
'This field type is a guess.' junto al campo en el modelo
347
Si el nombre de columna de la base de datos es una palabra reservada de Python( como 'pass',
'class', o 'for'), inspectdb agregar '_field' al nombre de atributo. Por ejemplo, si una tabla tiene una columna 'for', el modelo generado tendr un campo 'for_field', con el atributo db_column
establecido en 'for'. inspectdb insertar el comentario Python 'Field renamed because it was
a Python reserved word.' junto al campo.
Esta caracterstica est pensada como un atajo, no como la generacin de un modelo denitivo. Despus de
ejecutarla, querrs revisar los modelos genrados para personalizarlos. En particular, necesitars reordenar los modelos
de manera tal que las relaciones esten ordenadas adecuadamente.
Las claves primarias son detectadas automticamente durante la introspeccin para PostgreSQL, MySQL, y SQLite,
G.2.8.
fixtures
En el directorio
FIXTURE_DIRS
json
xml).
mydata.
Si omites la extensin, Django buscar todos los tipos de xture disponibles para un xture coincidente. Por
ejemplo, lo siguiente:
ese xture ser cargado como un xture JSON. De todas formas, si se descubren dos xtures con el mismo nombre
pero diferente tipo (ej.: si se encuentran
mydata.json
Los xtures que son nombrados pueden incluir como componentes directorios. Estos directorios sern incluidos en
la ruta de bsqueda. Por ejemplo, lo siguiente:
Observa que el orden en que cada xture es procesado es indenido. De todas formas, todos los datos de xture
son instalados en una nica transaccin, por lo que los datos en un xture pueden referenciar datos en otro xture.
Si el back-end de la base de datos admite restricciones a nivel de registro, estas restricciones sern chequeadas al nal
de la transaccin.
El comando
dumpdata
loaddata.
348
G.2.9.
Ejecuta el equivalente de
G.2.10.
sqlreset
runfcgi [options]
Inicia un conjunto de procesos FastCGI adecuados para su uso con cualquier servidor Web que admita el protocolo
FastCGI. Ver Captulo 20 para ms informacin acerca del desarrollo bajo FastCGI.
Este comando requiere el mdulo Python FastCGI de
G.2.11.
flup (http://www.djangoproject.com/r/flup/).
Inicia un servidor Web liviano de desarollo en la mquina local. machine. Por omisin, el servidor ejecuta en el
puerto 8000 de la direccin IP 127.0.0.1. Puedes pasarle explcitamente una direccin IP y un nmero de puerto.
Si ejecutas este script como un usuario con privilegios normales (recomendado), puedes no tener acceso a iniciar
un puerto en un nmero de puerto bajo. Los nmeros de puerto bajos son reservados para el superusuario (root).
Advertencia
runserver
django-admin.py
ms de una vez.
Observa que la direccin IP por omisin, 127.0.0.1, no es accesible desde las otras mquinas de la red. Para hacer
que el servidor de desarrollo sea visible a las otras mquinas de la red, usa su propia direccin IP (ej.: 192.168.2.1) o
0.0.0.0.
Por ejemplo, para ejecutar el servidor en el puerto 7000 en la direccin IP 127.0.0.1, usa esto:
MEDIA_ROOT_URL,
etc.). Si quieres congurar Django para servir medios estticos, lee acerca de esto en
http://www.djangoproject.com/documentation/0.96/static_les/.
Deshabilitando Autoreload
Para deshabilitar la recarga automtica del cdigo mientras el servidor de desarrollo se ejecuta, usa la opcin
--noreload,
como en:
shell
Django utilizar IPython (http://ipython.scipy.org/) si no est instalado. Si tienes IPython instalado y quieres
forzar el uso del intrprete Python plano, usa la opcin
--plain,
como en:
G.2.13.
G.2.14.
349
CREATE TABLE
Busca en la descripcin de
G.2.15.
G.2.16.
DROP TABLE
<appname>/sql/<modelname>.sql,
<appname> es el nombre de la aplicacin dada y <modelname> es el nombre del modelo en minsculas. Por ejemplo, si tienes una aplicacin news que incluye un modelo Story, sqlcustom tratar de leer un archivo news/sql/story.sql
Para cada modelo en cada aplicacin especicada, este comando busca el archivo
donde
G.2.17.
G.2.18.
G.2.19.
CREATE INDEX
DROP TABLE
seguidas de las
CREATE TABLE
Imprime las sentencias SQL para reinicializar las secuencias de las aplicaciones mencionadas.
Necesitars esta SQL solo si ests usando PostgreSQL y has insertado datos a mano. Cuando haces eso, las
secuencias de las claves primarias de PostgreSQL pueden quedar fuera de sincronismo con las que estn en la base de
datos, y las SQL que genera este comando las limpiarn.
G.2.20.
startapp [appname]
Crea una estructura de directorios para una aplicacin Django con el nombre de aplicacin dado, en el directorio
actual.
G.2.21.
startproject [projectname]
Crea una estructura de directorios Django para el nombre de proyecto dado, en el directorio actual.
G.2.22.
syncdb
creadas.
Usa este comando cuando hayas agregado nuevas aplicaciones a tu proyecto y quieras instalarlas en la base de
datos. Esto incluye cualquier aplicacin incorporada en Django que est en
INSTALLED_APPS
empieces un nuevo proyecto, ejecuta este comando para instalas las aplicaciones predeterminadas.
Si ests instalando la aplicacin
mediatamente.
loaddata
syncdb
django.contrib.auth, syncdb
initial_data.
Ver la documentacin de
350
G.2.23.
test
Descubre y ejecuta las pruebas para todos los modelos instalados. El testeo an est en desarrollo mientras se escribe
este libro, as que para aprender ms necesitars leer la documentacin online en
documentation/0.96/testing/.
G.2.24.
http://www.djangoproject.com/
validate
INSTALLED_APPS)
en la salida estndar.
G.3.
Opciones Disponibles
Las secciones que siguen delinean las opciones que puede tomar
G.3.1.
django-admin.py.
--settings
Ejemplo de uso:
mysite.settings).
DJANGO_SETTINGS_MODULE.
Si no se proveen,
django-admin.py
por t.
G.3.2.
--pythonpath
Ejemplo de uso:
PYTHONPATH.
manage.py,
django-admin.py
t.
G.3.3.
--format
Ejemplo de uso:
G.3.4.
--help
Muestra un mensaje de ayuda que incluye una larga lista de todas las opciones y acciones disponibles.
G.3.5.
--indent
Ejemplo de uso:
G.3.6.
351
--noinput
Indica que no quieres que se te pida ninguna entrada. Es til cuando el script
automtica y desatendida.
G.3.7.
--noreload
G.3.8.
--version
0.9.1
0.9.1 (SVN)
G.3.9.
--verbosity
Ejemplo de uso:
G.3.10.
0 es sin salida,
--adminmedia
Ejemplo de uso:
django-admin.py --adminmedia=/tmp/new-admin-style/
Le dice a Django donde encontrar los archivos CSS y JavaScript para la interfaz de administracin cuando se
ejecuta el servidor de desarrollo. Normalmente estos archivos son servidos por fuera del arbol de fuentes Django
pero como algunos diseadores personalizan estos archivos para su sitio, esta opcin te permite testear con versiones
personalizadas.
352
Apndice H
peticin.
de vista.
Hemos usado estos objetos con frecuencia a lo largo del libro; este apndice explica las APIs completas para los
objetos
HttpRequest
H.1.
HttpResponse.
HttpRequest
HttpRequest
Mucha de la informacin importante sobre la peticin esta disponible como atributos en la instancia de
(mira la Tabla H-1). Todos los atributos excepto
session
HttpRequest
Atributo
path
Descripcin
Un string que representa la ruta completa a la pgina peticionada, no incluye
el dominio -- por ejemplo,
method
"/music/bands/the_beatles/".
if request.method == 'GET':
do_something()
elif request.method == 'POST':
do_something_else()
GET
POST
QueryDict
que sigue.
QueryDict
que sigue.
POST
if
request.POST para vericar el uso del mtodo POST; en su lugar, utiliza if
request.method == "POST" (mira la entrada method en esta tabla).
Nota: POST no incluye informacin sobre la subida de archivos. Mira FILES.
Por conveniencia, un objeto similar a un diccionario que busca en POST primero, y luego en GET. Inspirado por $_REQUEST de PHP.
Por
ejemplo,
si
GET = {"name": "john"} y POST = {"age": '34'},
REQUEST["name"] ser "john", y REQUEST["age"] ser "34".
Se sugiere encarecidamente que uses GET y POST en lugar de REQUEST, ya que
POST pero que no incluye datos de formulario. Por eso, no deberas usar
REQUEST
lo primero es ms explcito.
COOKIES
Un diccionario Python estndar que contiene todas las cookies. Las claves y
los valores son strings. Mira el Captulo 12 para ms sobre el uso de cookies.
revisin 757 del 28 de julio de 2008
354
Atributo
FILES
Descripcin
Un objeto similar a un diccionario que contiene todos los archivos subidos.
Cada clave de
/>.
FILES es
FILES
Cada valor de
el atributo
name
de
tres claves:
content-type:
content:
Nota que
FILES
el
<form>
De lo contrario,
META
POST y
enctype="multipart/form-data".
FILES
CONTENT_LENGTH
CONTENT_TYPE
QUERY_STRING:
REMOTE_ADDR:
REMOTE_HOST:
SERVER_NAME:
SERVER_PORT:
HTTP_,
META
por ejemplo:
HTTP_ACCEPT_ENCODING
HTTP_ACCEPT_LANGUAGE
HTTP_HOST:
La cabecera HTTP
HTTP_REFERER:
host
HTTP_USER_AGENT:
HTTP_X_BENDER:
El valor de la cabecera
X-Bender,
si esta es-
tablecida.
user
Un objeto
django.contrib.auth.models.User
user se jar a
django.contrib.auth.models.AnonymousUser. Puedes distinguirlos con is_authenticated(), de este modo:
if request.user.is_authenticated():
# Do something for logged-in users.
else:
# Do something for anonymous users.
user esta disponible slo si tu instalacin Django tiene activado
AuthenticationMiddleware.
tual registrado. Si el usuario no esta actualmente registrado,
una instancia de
session
H.1. HTTPREQUEST
355
Atributo
Descripcin
raw_post_data
Los datos HTTP POST en crudo. Esto es til para procesamiento avanzado.
Los objetos request tambin tienen algunos mtodos de utilidad, como se muestra en la Tabla H-2.
Cuadro H.2: Mtodos de HttpRequest
Mtodo
Descripcin
__getitem__(key)
Retorna el valor GET/POST para la clave dada, vericando POST primero, y luego GET. Emite
KeyError
si la clave no existe.
HttpRequest.
ejemplo,
request["foo"] es lo mismo que comprobar
request.POST["foo"] y luego request.GET["foo"].
Retorna True o False, sealando si request.GET o request.POST con-
Por
has_key()
get_full_path()
is_secure()
PS.
H.1.1.
Objetos QueryDict
En un objeto
HttpRequest,
los atributos
GET
POST
son instancias de
django.http.QueryDict. QueryDict
es
una clase similar a un diccionario personalizada para tratar mltiples valores con la misma clave. Esto es necesario
ya que algunos elementos de un formulario HTML, en particular
<select multiple="multiple">,
pasan mltiples
QueryDict
son inmutables, a menos que realices una copia de ellas. Esto signica que tu no puedes
request.POST y request.GET.
QueryDict implementa todos los mtodos estndar de los diccionarios, debido a que es una subclase de diccionario.
Mtodo
__getitem__
__setitem__
__getitem__()
value).
Nota que sta, como otras funciones de diccionario que tienen efectos
get()
update()
copy()).
__getitem__.
Recibe ya sea un
todo
update
QueryDict
get()
QueryDict
>>> q = QueryDict('a=1')
>>> q = q.copy() # to make it mutable
>>> q.update({'a': '2'})
>>> q.getlist('a')
['1', '2']
>>> q['a'] # returns the last
['2']
revisin 757 del 28 de julio de 2008
356
Mtodo
items()
values()
Adems,
QueryDict
Mtodo
Descripcin
copy()
copy.deepcopy()
de la
getlist(key)
Retorna los datos de la clave requerida, como una lista de Python. Retorna una lista vaca si la clave no existe. Se garantiza que
retornar una lista de algn tipo.
setlist(key, list_)
appendlist(key, item)
setlistdefault(key, l)
list_
setdefault,
__setitem__()).
asociada a key.
(a diferencia de
de un slo valor.
lists()
Similar a
>>> q = QueryDict('a=1&a=2&a=3')
>>> q.lists()
[('a', ['1', '2', '3'])]
urlencode()
H.1.2.
"a=2&b=3&b=5").
Un ejemplo completo
"John Smith"
en el campo
your_name
>>> request.GET
{}
>>> request.POST
{'your_name': ['John Smith'], 'bands': ['beatles', 'zombies']}
revisin 757 del 28 de julio de 2008
H.2. HTTPRESPONSE
357
>>> request.POST['your_name']
'John Smith'
>>> request.POST['bands']
'zombies'
>>> request.POST.getlist('bands')
['beatles', 'zombies']
>>> request.POST.get('your_name', 'Adrian')
'John Smith'
>>> request.POST.get('nonexistent_field', 'Nowhere Man')
'Nowhere Man'
Nota de implementacin:
Los atributos
user
son todos
cargados tardamente. Esto signica que Django no gasta recursos calculando los valores de estos
atributos hasta que tu cdigo los solicita.
H.2.
HttpResponse
HttpRequest, los cuales son creados automticamente por Django, los objetos HttpResponse
HttpResponse.
HttpResponse esta ubicada en django.http.HttpResponse.
son tu responsabilidad. Cada vista que escribas es responsable de instanciar, poblar, y retornar un
La clase
H.2.1.
Construccin de HttpResponses
Tpicamente, tu construirs un
de
HttpResponse:
response
archivo:
HttpResponse
HttpResponse implementa un mtodo write(), lo cual lo hace apto para usarlo en cualquier
lugar que Python espere un objeto similar a un archivo. Mira el Captulo 11 para ver algunos ejemplos de la utilizacin
de esta tcnica.
H.2.2.
358
H.2.3.
Subclases de HttpResponse
HttpResponse,
HttpResponse
django.http.
Clase
Descripcin
HttpResponseRedirect
absoluta
que esto
HttpResponsePermanentRedirect
Como
HttpResponseRedirect,
HttpResponseNotModified
HttpResponseBadRequest
Acta como
400.
HttpResponseNotFound
Acta como
404.
HttpResponseForbidden
Acta como
403.
HttpResponseNotAllowed
Como
['GET', 'POST']).
Acta como HttpResponse pero usa un cdigo de estado
permitidos (ej.,
HttpResponseGone
410.
HttpResponseServerError
Acta como
500
HttpResponse
H.2.4.
Retornar Errores
Retornar cdigos de error HTTP en Django es fcil. Ya hemos mencionado las subclases
HttpResponseForbidden, HttpResponseServerError,
subclases en lugar de una HttpResponse normal con el
HttpResponseNotFound,
def my_view(request):
# ...
if foo:
return HttpResponseNotFound('<h1>Page not found</h1>')
else:
return HttpResponse('<h1>Page was found</h1>')
Debido a que el error 404 es por mucho el error HTTP ms comn, hay una manera ms fcil de manejarlo.
Cuando retornas un error tal como
HttpResponseNotFound,
error resultante:
Http404.
Si tu emites una
Http404
atrapar y retornar la pgina de error estndar de tu aplicacin, junto con un cdigo de error HTTP 404.
revisin 757 del 28 de julio de 2008
H.2. HTTPRESPONSE
359
ste es un ejemplo:
Http404
404.html,
plantillas.
H.2.5.
Http404, Django carga una vista especial dedicada a manejar errores 404. Por
django.views.defaults.page_not_found, la cual carga y renderiza la plantilla 404.html.
que necesitas denir una plantilla 404.html en tu directorio raz de plantillas. Esta plantilla ser
page_not_found debera ser suciente para el 99 % de las aplicaciones Web, pero si tu quieres reemplazar
handler404 en tu URLconf, de la siguiente manera:
handler404.
la siguiente lnea:
handler404
esta jado a
Hay tres cosas para tener en cuenta sobre las vistas 404:
La vista 404 es llamada tambin si Django no encuentra una coincidencia despus de vericar toda
expresin regular en la URLconf.
Si no denes tu propia vista 404 -- y simplemente usas la predeterminada, lo cual es recomendado -tu an tienes una obligacin: crear una plantilla
vista 404 predeterminada usar esa plantilla para todos los errores 404.
Si
DEBUG
esta establecido a
True
H.2.6.
De manera similar, Django ejecuta comportamiento de caso especial en el caso de errores de ejecucin en el
cdigo de la vista. Si una vista resulta en una excepcin, Django llamar, de manera predeterminada, a la vista
django.views.defaults.server_error,
500.html
500.html.
360
Apndice I