Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
Tutor:
- Holger Dinkel
Tutees:
- Petr Strnad
- Charles Girardot
- Joachim Weischenfeld
- Guangyou Duan
- Matthias Monfort
- Serge Dmitrieff
- Lucas Tafur
- Jin Wang
- Maia Segura Wang
- Thomas Schwarzl
- Sajoscha Sauer
# Django Introductory Tutorial
These steps are pretty much taken and adapted from the official [Django Tutorial](https://docs.djangoproject.com/en/1.7/intro/tutorial01/)
In this tutorial we want to create a simple webpage which allows users to
register to certain events by providing some information about themselves and
choosing a an event from a list of created entries. We also want to use the
builtin django-admin system to easily create/edit/remove entries in our
database.
First, we start by creating a new project using the django-admin tool:
django-admin.py startproject mysite
This will create the folder 'mysite' along with some files in it.
mysite/
manage.py
mysite/
__init__.py
settings.py
urls.py
wsgi.py
These files are:
* The outer **mysite**/ root directory is just a container for your project. Its name doesn't matter to Django; you can rename it to anything you like.
* **manage.py**: A command-line utility that lets you interact with this Django project in various ways.
* The inner **mysite**/ directory is the actual Python package for your project. Its name is the Python package name you'll need to use to import anything inside it (e.g. mysite.urls).
* **mysite/__init__.py**: An empty file that tells Python that this directory should be considered a Python package.
* **mysite/settings.py** : Settings/configuration for this Django project. Django settings will tell you all about how settings work.
* **mysite/urls.py**: The URL declarations for this Django project; a 'table of contents' of your Django-powered site.
* **mysite/wsgi.py**: An entry-point for WSGI-compatible web servers to serve your project.
Let's have a look at the settings.py file first and in particular inspect the database settings (we will be using sqlite for now):
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
}
}
Now we initialize the database by running the migrate command:
python manage.py migrate
## Running Django
Finally let's see if we can run the development server to verify everything worked as expected.
Change into the outer mysite directory, if you haven't already, and run the following commands:
python manage.py runserver
## Creating apps
Projects vs. apps
What's the difference between a project and an app? An app is a Web application
that does something - e.g., a Weblog system, a database of public records or a
simple registrations app. A project is a collection of configuration and apps for a
particular Web site. A project can contain multiple apps. An app can be in
multiple projects.
To create your app, make sure you're in the same directory as manage.py and type this command:
python manage.py startapp registrations
That'll create a directory registrations, which is laid out like this:
registrations/
__init__.py
admin.py
migrations/
__init__.py
models.py
tests.py
views.py
### Philosophy
A model is the single, definitive source of data about your data. It contains
the essential fields and behaviors of the data you're storing. Django follows
the DRY Principle. The goal is to define your data model in one place and
automatically derive things from it.
This includes the migrations - unlike in Ruby On Rails, for example, migrations
are entirely derived from your models file, and are essentially just a history
that Django can roll through to update your database schema to match your
current models.
## Creating models
In our simple registrations app, we'll create two models:
Events and Registrations. An Event has a date, a title and a description. A Registration has three fields: First & lastname and a relational field to registrations.
These concepts are represented by simple Python classes. Edit the registrations/models.py file so it looks like this:
registrations/models.py
from django.db import models
class Event(models.Model):
id = models.AutoField(primary_key=True)
title = models.CharField(max_length=128)
description = models.TextField(blank=True)
date = models.DateTimeField()
class Registration(models.Model):
id = models.AutoField(primary_key=True)
firstname = models.CharField(max_length=128)
lastname = models.CharField(max_length=128)
event = models.ForeignKey(Event)
Note that Events has to be declared before Registrations as the latter references the former...
(see the django documentation on the list of possible [field types](https://docs.djangoproject.com/en/1.7/ref/models/fields/#field-types)
Each model will be represented in the database by an individual table. Django
will create these for us when we invoke the migration commands, but first we
need to tell django that it should actually search for and use these new
models. We do this by adding our app 'registrations' to the list of
"INSTALLED_APPS" in the settings.py
mysite/settings.py
INSTALLED_APPS = (
...
'django.contrib.staticfiles',
'registrations',
)
Now we can run the migration steps which in the background will create all the necessary complicated SQL statements to populate the database:
python manage.py makemigrations registrations
If you want, you can run a sanity check to see if django is ok with your configurations
python manage.py check
before you actually commit the migration:
python manage.py migrate
## Playing with the API
Now, with the database in place, let's drop into the interactive Python shell and play around with the free API Django gives you. To invoke the Python shell, use this command:
python manage.py shell
Once you're in the shell, explore the database API:
>>> from registrations.models import Registration, Event
>>> print Event.objects.all()
[]
>>> e = Event(title="HUB15", description="User Experience workshop")
>>> e.save()
>>> e.id
1
>>> print Event.objects.all()
[Event object <...>]
>>> r = Registration(firstname='Holger', lastname='Dinkel', even=e)
>>> r.save()
## Modifying models
Let's beautify the way that models are printed.
For this we can add a function "\_\_str\_\_" to each model:
class Event(models.Model):
...
def __str__(self):
return "%s" % self.title
class Registration(models.Model):
...
def __str__(self):
return "%s %s" % (self.firstname, self.lastname)
So next time we print an object we will get something more readable. Note how
with this easy way you just effectively added a method to a database structure
(both represented in Django).
## Using the admin interface
python manage.py createsuperuser
Now start the development server like so:
python manage.py runserver
and navigate your browser to http://127.0.0.1:8000/admin/ and provide your newly created credentials.
However our two models, Event & Registration do not show up!?
We first need to tell django to automatically include these in the admin interface:
registrations/admin.py
from django.contrib import admin
from registrations.models import Event, Registration
admin.site.register(Event)
Reload the admin page in your browser and both models should be there.
Feel free to add/edit more entries for each...
## Write your first view
Let's write the first view. Open the file registrations/views.py and put the following Python code in it:
registrations/views.py
from django.http import HttpResponse
def index(request):
return HttpResponse("Hello, world. You're at the registrations index.")
This is the simplest view possible in Django. To call the view, we need to map it to a URL - and for this we need a URLconf.
To create a URLconf in the registrations directory, create a file called urls.py. Your app directory should now look like:
registrations/
__init__.py
admin.py
models.py
tests.py
urls.py
views.py
In the registrations/urls.py file include the following code:
registrations/urls.py
from django.conf.urls import patterns, url
from registrations import views
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
)
The next step is to point the root URLconf at the registrations.urls module. In mysite/urls.py insert an include(), leaving you with:
mysite/urls.py
from django.conf.urls import patterns, include, url
from django.contrib import admin
urlpatterns = patterns('',
url(r'^registrations/', include('registrations.urls')),
url(r'^admin/', include(admin.site.urls)),
)
registrations/views.py
from django.http import HttpResponse
from registrations.models import Event
def index(request):
latest_event_list = Event.objects.order_by('-date')[:5]
output = ', '.join([p.title for p in latest_event_list])
return HttpResponse(output)
There's a problem here, though: the page's design is hard-coded in the view. If
you want to change the way the page looks, you'll have to edit this Python
code. So let's use Django's template system to separate the design from Python
by creating a template that the view can use.
First, create a directory called templates in your registrations directory. Django will look for templates in there.
Django's TEMPLATE_LOADERS setting contains a list of callables that know how to
import templates from various sources. One of the defaults is
django.template.loaders.app_directories.Loader which looks for a 'templates'
subdirectory in each of the INSTALLED_APPS - this is how Django knows to find
the registrations templates even though we didn't modify TEMPLATE_DIRS.
Within the templates directory you have just created, create another directory
called registrations, and within that create a file called index.html. In other words,
your template should be at registrations/templates/registrations/index.html. Because of how the
app_directories template loader works as described above, you can refer to this
template within Django simply as registrations/index.html.
Put the following code in that template:
registrations/templates/registrations/index.html
{% if latest_event_list %}
<ul>
{% for event in latest_event_list %}
<li><a href="/registrations/{{ event.id }}/">{{ event.title }}</a></li>
{% endfor %}
</ul>
{% else %}
<p>No registrations are available.</p>
{% endif %}
registrations/views.py
from django.http import HttpResponse
from django.template import RequestContext, loader
from registrations.models import Event
def index(request):
latest_event_list = Event.objects.order_by('-date')[:5]
template = loader.get_template('registrations/index.html')
context = RequestContext(request, {
'latest_event_list': latest_event_list,
})
return HttpResponse(template.render(context))
It's a very common idiom to load a template, fill a context and return an
HttpResponse object with the result of the rendered template. Django provides a
shortcut:
The 'render()' function takes the request object as its first argument, a
template name as its second argument and a dictionary as its optional third
argument. It returns an HttpResponse object of the given template rendered with
the given context.
the 'get_object_or_404' function is handy to retrieve an object from the database
or automatically return a 404 error message saying 'object not found'.
registrations/views.py
from django.http import HttpResponse
from django.template import RequestContext, loader
from django.shortcuts import get_object_or_404, render
from registrations.models import Event
(...)
def detail(request, event_id):
event = get_object_or_404(Event, pk=event_id)
# Equivalent to:
# try:
# event = Event.objects.get(pk=event_id)
# except Event.DoesNotExist:
# raise Http404
return render(request, 'registrations/detail.html', {'event': event})
Next, we create a very simple 'detail' page like so:
registrations/templates/registrations/detail.html
{{ event }}
In order for this detail view to work, we need to update the urls.py
url(r'^(?P<event_id>\d+)/$', views.detail, name='detail'),
## Writing a simple form
In order to be able to interact with the page, we'll create a simple form to enter data into the database:
registrations/detail.html
<h1>{{ event.title }}</h1>
{{ event.title }}: {{ event.description }} on {{ event.date}}
{% if error_message %}<p><strong>{{ error_message }}</strong></p>{% endif %}
<p>
Registered People:
<ul>
{% for registration in event.registration_set.all %}
<li>{{ registration }}</li>
{% endfor %}
</ul>
</p>
<p>
<form action="{% url 'register' event.id %}" method="post">
{% csrf_token %}
Firstname:<input type="text" name="firstname" /><br/>
Lastname:<input type="text" name="lastname" /><br/>
<input type="submit" value="Register" />
</form>
</p>
Add another url to urls.py:
url(r'^(?P<event_id>\d+)/register$', views.register, name='register'),
and add another view to views.py:
def register(request, event_id):
event = get_object_or_404(Event, pk=event_id)
firstname=request.POST['firstname']
lastname=request.POST['lastname']
try:
selected_registration = event.registration_set.get(firstname=firstname, lastname=lastname)
# Redisplay the question voting form.
return render(request, 'registrations/detail.html', {
'event': event,
'error_message': "Already registered",
})
except (KeyError, Registration.DoesNotExist):
r = Registration(event = event, firstname = firstname, lastname= lastname)
r.save()
return render(request, 'registrations/detail.html', {'event': event})