Skip to content

Instantly share code, notes, and snippets.

@Syerram
Last active December 25, 2015 21:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Syerram/7045629 to your computer and use it in GitHub Desktop.
Save Syerram/7045629 to your computer and use it in GitHub Desktop.
Django Code workshop

Coding

Startup

#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

Writing Models

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

Configuration - One last step

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',
)

DB Sync

We need now migrate our models into tables, so we can store them somwhere

#create superuser when prompted
$ ./manage.py syncdb

Adding to Admin

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 and Todos

Views - The real magic

  • functions tied to urls.

  • Corresponding html to serve

  • Rich templating tags

  • Open up views.py in todo 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 }) 

Templates - Visual presentation

  • Create a new directory templates in todo 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>

Little more configuration

  • 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?

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