3 February 2008

Online games portal in Django - tutorial, part 2

Today we are going to concentrate on creating data model for game portal. Requirements:

  • we want to run several sites with the same or similar data, for example general portal or specialized portal for girls
  • the difference will be in used categories, so we link them with sites
  • to get better user experience (faster looking for interesting games), we will create three levels: categories, subcategories and games
  • subcategory can be connected to only one category but game can be in many subcategories (to get things harder)
  • game can be of three different types (Flash, Shockwave or external). External behaves differently than two first because it is just a link to other site (once more to get things harder)
  • we will use screenshots for subcategories and games, ratings (but not user editable) and hit counter to measure popularity

This should suffice as an introduction. Go to games4all folder. Last time we created there new application named gampor. Look into this folder and then open models.py file. The file is going to contain our model and admin configuration data. It is almost empty, but we are going to change that in a second. Add below code to it:

from django.db import models
from django.contrib.sites.models import Site

GAME_TYPES = (
('F', 'Flash'),
('S', 'Shockwave'),
('E', 'External'),
)

We are importing base model classes and also Site model that we will use with categories. The GAME_TYPES tuple contains choices for game types for use in admin and also in the future in templates.

The next step will be creating category model. It is rather simple, but we want to have connections to many sites and also want to use pretty urls. Here it is:

class Category(models.Model):
url_name = models.SlugField(prepopulate_from=('list_name',), unique=True) # For pretty urls
list_name = models.CharField(max_length=60, unique=True) # Cat name in lists
title_name = models.CharField(max_length=60) # Cat name in titles
sites = models.ManyToManyField(Site, null=True, blank=True) # M-N linkage to sites

class Meta:
ordering = ('list_name',) # Default ordering
verbose_name_plural = 'categories' # To get proper name in admin panel

class Admin:
list_display = ('list_name',) # What to display on admin list
search_fields = ('list_name',) # What fields should be searchable
list_filter = ('sites',) # By what we want to filter categories in admin

# Defines nice string value for category (used by admin panel)
def __unicode__(self):
return self.list_name

I'm not going to explain here all the details of model classes except commented parts. For this just go to Django model doc.

The next thing is to define subcategories. They are very similar to categories except that they use one to many linkage and have screenshot field. Here is the code:

class Subcategory(models.Model):
url_name = models.SlugField(prepopulate_from=('list_name',), unique=True)
list_name = models.CharField(max_length=60)
title_name = models.CharField(max_length=60)
category = models.ForeignKey(Category, null=True, blank=True) # 1-N link with category.
# Field for screenshots that support uploading to folder
screenshot = models.ImageField(upload_to='img/b/%Y', help_text='Preferred size: 120x90px')

class Meta:
ordering = ('list_name',)
verbose_name_plural = 'subcategories'

class Admin:
list_display = ('list_name','category')
search_fields = ('list_name',)
list_filter = ('category',)

def __unicode__(self):
return self.list_name

Not that hard! Notice that we can create subcategory without assigning it to category so effectively we can prepare many categories and do not show them if we do not want to :)

Last thing is game model which will be the most complicated one, but as you will see we are going to use many already known elements. First of all there will be game_type field with limited choice of game types, url field with external game URL, publish_date field with publication date what we will use for ordering and showing only game with publish date in the past. Also please look at more complicated Admin class because we want to modify the edit view in admin panel.

class Game(models.Model):
title = models.CharField(max_length=60, unique=True)
url_name = models.SlugField(prepopulate_from=('title',), unique=True)
active = models.BooleanField() # To temporary disabling the game
subcategories = models.ManyToManyField(Subcategory, null=True, blank=True, related_name='games_in', filter_interface=models.HORIZONTAL)

screenshot = models.ImageField(upload_to='img/s/%Y', help_text='Preferred size: 120x90px')
game_type = models.CharField(max_length=1, choices=GAME_TYPES) # Limited game types
width = models.PositiveSmallIntegerField(null=True, blank=True)
height = models.PositiveSmallIntegerField(null=True, blank=True)
local_file = models.FileField(null=True, blank=True, upload_to='data/%Y')
url = models.URLField(null=True, blank=True)
description = models.TextField()
how_to_play = models.TextField()
rating = models.PositiveSmallIntegerField()

publish_date = models.DateField()
hit_count = models.PositiveIntegerField()

class Meta:
ordering = ('-publish_date','title')
get_latest_by = 'publish_date'

class Admin:
list_display = ('title','publish_date','game_type','active')
search_fields = ('title','url_name')
# What field to use for additional filtering by date
date_hierarchy = 'publish_date'
list_filter = ('active','subcategories')
# This elements gives us great control over edit page design
fields = (
(None, {
'fields': ('url_name', 'title', 'active')
}),
('Game details', {
'classes': 'collapse',
'fields' : ('screenshot', 'game_type', ('width', 'height'), 'local_file', 'url', 'description', 'how_to_play', 'rating')
}),
('Publishing details', {
'classes': 'collapse',
'fields' : ('publish_date', 'hit_count')
}),
)

def __unicode__(self):
return self.title

If you need more explanation about some field types, look into Django model documentation.

That's it! Simple data model is ready. To test it, run python manage.py syncdb and then start development server with python manage.py runserver 8080. Test your model using admin panel.

Within next few days I'm going to show how to use model API to populate database with dummy data for use in future tests.

0 komentarze:

Post a Comment