#creates a new folder.
$ django-admin.py startproject my_todo
$ cd my_todo
# you dont have to do this but its easier to run as a script
$ chmod +x manage.py
# runs on a special port 8090.
$ ./manage.py runserver 8090
#voila you got server working. Lets create the app
#create a new app. This will store our todos in the database.
#notice files it creates, views.py, models.py
$ ./manage.py startapp todo
Open up models.py
in todo
app
from django.db import models
from django.utils import timezone
class List(models.Model):
"""
For categorizing todos into list.
"""
#creates primary ID automatically for you. magic 1
#single field that will hold the title of the list. translates from db to field properly magic 2
title = models.CharField(max_length = 20, unique = True, db_index = True)
def __unicode__(self):
return self.title #string friendly text
# the magical subclass. Define how you want it to behave
class Meta:
ordering = ['title'] #everytime you pull it, it orders by title automatically. magic 3
PRIORITY_CHOICES = (
(1, 'Low'),
(2, 'Normal'),
(3, 'High'),
)
class Item(models.Model):
title = models.CharField(maxlength=250)
created_date = models.DateTimeField(default = timezone.now) #defaults to now on every creation
priority = models.IntegerField(choices = PRIORITY_CHOICES, default = 2)
completed = models.BooleanField(default = False)
todo_list = models.ForeignKey(List) #foreign key to the list
class Meta:
ordering = ['-priority', 'title']
def __unicode__(self):
return self.title
Change your settings.py
configuration option for DATABASES
and INSTALLED_APPS
#lets add a path to this folder.
SITE_ROOT = os.path.dirname(os.path.realpath(__file__)) #python y u know simple
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
'NAME': 'my_todo', # Or path to database file if using sqlite3.
'OPTIONS': {
'timeout': 5,
}
}
}
...
...
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
'django.contrib.admin',
#Your app
'todo',
)
We need now migrate our models into tables, so we can store them somwhere
#create superuser when prompted
$ ./manage.py syncdb
Create a new module admin.py
in todo
folder
from django.contrib import admin
from todo.models import List, Item
admin.site.register(List)
admin.site.register(Item)
Open up urls.py
in my_todo.py
. Uncomment the line below
# Uncomment the next line to enable the admin:
url(r'^admin/', include(admin.site.urls)), #--> remove the # in the front
- Run the server again
$ ./manage.py runserver 8090
- Goto
http://localhost:8090/admin/
- Create new
List
andTodo
s
-
functions tied to
url
s. -
Corresponding
html
to serve -
Rich templating tags
-
Open up
views.py
intodo
app
def stat_report(request): # a simple function accepting the `request`
"""
The function accepts a `request` object that represents the information pertaining to the current request.
As you can see no HTML whatsoever. Just pure objects.
"""
todos = []
for todo_list in List.objects.all(): #fetches everything
todo_dict = {}
todo_dict['list'] = todo_list
todo_dict['count'] = todo_list.item_set.count() #magic method. reverse relationship
todo_dict['complete'] = todo_list.item_set.filter(completed = True).count() #filter method to restrict results
todo_dict['percent_complete'] = int(float(todo_dict['complete']) / todo_dict['count'] * 100)
todos.append(todo_dict)
#whatever you pass, you can access this in the HTML. See below. You will notice all of the above dictionary values will be used
return render_to_response('stat_report.html', { 'todos': todos })
- Create a new directory
templates
intodo
directory. - Create a file named
stat_report.html
in it
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>To-do Status Report</title>
</head>
<body>
<h1>To-do status report</h1>
<!--
Django tags are represented by {% ... %}. for e.. {% for %}... {% endfor %} is built in tags.
you can create your own tags as well. More on that later.
-->
{% for todo in todos %} <!-- remember the `todos` in the view we sent. its the same object list -->
<h2>{{ todo.list.title }}</h2> <!-- remember the `list` object we stuffed in the dictionary -->
<ul>
<li>Number of items: {{ todo.count }}</li>
<li>Number completed: {{ todo.complete }} ({{ list_dict.percent_complete }}%)</li>
</ul>
{% endfor %}
</body>
</html>
-
This is primarily for the templates to work, why you ask? Well it needs to know where the templates are.
-
Also, we need a URL to show this. Duh!
-
in
settings.py
TEMPLATE_DIRS = (
os.path.join(SITE_ROOT, 'templates'), #Now you know why we had that `SITE_ROOT` thingy. Dont forget the comma at the end.
)
* in `my_todo/urls.py`
```python
urlpatterns = patterns('',
url(r'^admin/', include(admin.site.urls)), #you already had this
url(r'^report/$', 'my_todo.views.stat_report'),
- run it again and goto
http://127.0.0.1:8090/report/
$ ./manage.py runserver 8090
Ok then you're first Django app. Alright. Can we do better. How about adding Add/Remove Todo, Due dates?