Skip to content

Commit

Permalink
Kevin's 1.0 version
Browse files Browse the repository at this point in the history
  • Loading branch information
rock committed Dec 11, 2008
0 parents commit 6301f82
Show file tree
Hide file tree
Showing 19 changed files with 494 additions and 0 deletions.
4 changes: 4 additions & 0 deletions .gitignore
@@ -0,0 +1,4 @@
*.pyc
*.bak
*.db
local_settings.py
19 changes: 19 additions & 0 deletions README
@@ -0,0 +1,19 @@

Djangop-FAQ v.1.0
============

An extremely simple faq application for your Django powered site. I also made note to provide this app as an example of creating
a reusable app following best practices - allowing for template overrides, extra_context arguments, etc. So
in theory you should be able to drop it on your Python path and get going pretty easy. I noted where appropriate some of the details. Search for '#NOTE' to see where I left those tidbits of info that provide some more details within the code.

Installation
============

1. add 'faq' directory to your Python path.
2. add 'faq' to your INSTALLED_APPS tuple found in your settings file.
3. If you want to customize the templates then either create an 'faq' directory in your projects templates location, or you can also pass along custom 'template_name' arguments by creating your own view wrappers around the 'faq' app views. I show how to do the latter in the 'example' project included - look at the views.py file to see the details.

Example Site
============

I included an example site in the /example directory. You should be able to simply execute './manage.py syncdb' and then './manage.py runserver' and have the example site up and running. I assume your system has sqlite3 available - it is set as the default database with the DATABASE_NAME = 'faq.db'
Empty file added example/__init__.py
Empty file.
17 changes: 17 additions & 0 deletions example/manage.py
@@ -0,0 +1,17 @@
#!/usr/bin/env python

#add faq app to python path
import sys
from os.path import abspath, dirname, join
sys.path.append(abspath(join(dirname(__file__), '..')))

from django.core.management import execute_manager
try:
import settings # Assumed to be in the same directory.
except ImportError:
import sys
sys.stderr.write("Error: Can't find the file 'settings.py' in the directory containing %r. It appears you've customized things.\nYou'll have to run django-admin.py, passing it your settings module.\n(If the file settings.py does indeed exist, it's causing an ImportError somehow.)\n" % __file__)
sys.exit(1)

if __name__ == "__main__":
execute_manager(settings)
96 changes: 96 additions & 0 deletions example/settings.py
@@ -0,0 +1,96 @@
# Django settings for [name] project.
import os, os.path, sys

#set DEBUG = False and django will send exception emails
DEBUG = True
TEMPLATE_DEBUG = DEBUG
PROJECT_DIR = os.path.dirname(__file__)

DATABASE_ENGINE = 'sqlite3' # 'postgresql_psycopg2', 'postgresql', 'mysql', 'sqlite3' or 'oracle'.
DATABASE_NAME = 'faq.db' # Or path to database file if using sqlite3.
DATABASE_USER = '' # Not used with sqlite3.
DATABASE_PASSWORD = '' # Not used with sqlite3.
DATABASE_HOST = '' # Set to empty string for localhost. Not used with sqlite3.
DATABASE_PORT = '' # Set to empty string for default. Not used with sqlite3.

# Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
# although not all choices may be avilable on all operating systems.
# If running in a Windows environment this must be set to the same as your
# system time zone.
TIME_ZONE = 'America/New_York'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
LANGUAGE_CODE = 'en-us'

SITE_ID = 1

# If you set this to False, Django will make some optimizations so as not
# to load the internationalization machinery.
USE_I18N = True

# Absolute path to the directory that holds media.
# Example: "/home/media/media.lawrence.com/"
MEDIA_ROOT = os.path.join(PROJECT_DIR, 'media')

# URL that handles the media served from MEDIA_ROOT. Make sure to use a
# trailing slash if there is a path component (optional in other cases).
# Examples: "http://media.lawrence.com", "http://example.com/media/"
#MEDIA_URL = 'http://127.0.0.1:8000/site_media/'
MEDIA_URL = '/media/' #

# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
# trailing slash.
# Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/admin_media/'

# Make this unique, and don't share it with anybody.
SECRET_KEY = 'c#zi(mv^n+4te_sy$hpb*zdo7#f7ccmp9ro84yz9bmmfqj9y*c'

# List of callables that know how to import templates from various sources.
TEMPLATE_LOADERS = (
'django.template.loaders.filesystem.load_template_source',
'django.template.loaders.app_directories.load_template_source',
)

TEMPLATE_CONTEXT_PROCESSORS = (
'django.core.context_processors.auth',
'django.core.context_processors.media',
)

MIDDLEWARE_CLASSES = (
#'django.middleware.cache.CacheMiddleware',
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.middleware.doc.XViewMiddleware',
)

ROOT_URLCONF = 'example.urls'

INTERNAL_IPS = (
'127.0.0.1',
)

TEMPLATE_DIRS = (
# Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
# Always use forward slashes, even on Windows.
# Don't forget to use absolute paths, not relative paths.
[os.path.join(PROJECT_DIR, "templates")]
)

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.admin',
'faq',
)


try:
from local_settings import *
except ImportError:
pass
27 changes: 27 additions & 0 deletions example/templates/faq/base.html
@@ -0,0 +1,27 @@
<html>
<head>
<title>{% block title %}Django FAQ {% endblock %}</title>

<style>

.answer
{
color: #CC0000;
}

body
{
background-color: #CCC;
}

</style>

</head>
<body>

{% block content %}
{% endblock %}

</body>

</html>
40 changes: 40 additions & 0 deletions example/templates/faq/faq_list.html
@@ -0,0 +1,40 @@
{% extends "faq/base.html" %}

{% block title %}{{ block.super }}: Example {% endblock %}

{% block content %}
<h1>{{ page_title }}</h1>

<p>
Demo typical faq page. Created on: {{ created_on|date:"M d, Y" }}
</p>

<h3>Questions</h3>

<ol>
{% for question in object_list %}

<li>
<a href="#{{ question.slug }}">{{ question.text }}</a>
<br>
<span class="answer">answer: {{ question.answer }}</span>
</li>

{% endfor %}
</ol>


<h3 style="margin-top: 1000px">Answers</h3>

<ol style="margin-bottom: 1000px">
{% for question in object_list %}
<li>
<a id="{{ question.slug }}">
<h3>{{ question.text }}</h3>
{{ question.answer }}
</li>
{% endfor %}
</ol>


{% endblock %}
24 changes: 24 additions & 0 deletions example/urls.py
@@ -0,0 +1,24 @@
from django.conf.urls.defaults import *
from django.contrib import admin
from django.conf import settings
from views import faq_list

admin.autodiscover()

urlpatterns = patterns('',

(r'^admin/(.*)', admin.site.root),
url (
regex = r'^faq/$',
view = faq_list,
name = 'faq_list',
),

(r'^faq/(.*)', include('faq.urls'))

)


urlpatterns += patterns('',
(r'^static/(?P<path>.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
)
18 changes: 18 additions & 0 deletions example/views.py
@@ -0,0 +1,18 @@
from django.views.generic.list_detail import object_detail, object_list
from faq.views import question_list

def faq_list( request ):
'''
Display a typical FAQ view but more importantly an example of a basic way to "extend" or
"override" an existing view from a "reusable apps".
'''

#NOTE:
#Again just for example - we pass along a custom extra_context dict so even if the view we're reusing sets it's own
#we are still allowed to provide further details we may need by passing along this argument.
extra = { 'page_title': 'FAQ Details' }

#NOTE:
#we also pass along our own custom template_name to override the existing one that's set.
return question_list(request, template_name='faq/faq_list.html', extra_context=extra)
Empty file added faq/__init__.py
Empty file.
24 changes: 24 additions & 0 deletions faq/admin.py
@@ -0,0 +1,24 @@
from django.contrib import admin
from models import Question
from datetime import datetime


class QuestionAdmin(admin.ModelAdmin):

list_display = ['text', 'sort_order', 'created_by', 'created_on', 'updated_by', 'updated_on', 'status']

def save_model(self, request, obj, form, change):
'''
Overrided because I want to also set who created this instance.
'''
instance = form.save( commit=False )
if instance.id is None:
new = True
instance.created_by = request.user

instance.updated_by = request.user
instance.save()

return instance

admin.site.register(Question, QuestionAdmin)
13 changes: 13 additions & 0 deletions faq/enums.py
@@ -0,0 +1,13 @@

"""
Home base for all application enums.
"""

STATUS_ACTIVE = 1
STATUS_INACTIVE = 0

QUESTION_STATUS_CHOICES = (
(STATUS_ACTIVE, 'Active'),
(STATUS_INACTIVE, 'Inactive')
)
40 changes: 40 additions & 0 deletions faq/managers.py
@@ -0,0 +1,40 @@
from django.db import models
from django.db.models.query import QuerySet
import datetime
import enums


class QuestionQuerySet(QuerySet):
"""
A basic ''QuerySet'' subclass, provides query functionality and some helper methods for an intuitive interface.
"""

def active(self, **kwargs):
"""
A utility method that filters results based on ''Question'' models that are only ''Active''.
"""

if kwargs.get('slug'):
slug = kwargs['slug']
return self.filter(status__exact=enums.STATUS_ACTIVE, slug__exact=slug)
else:
return self.filter(status__exact=enums.STATUS_ACTIVE,)


class QuestionManager(models.Manager):
"""
A basic ''Manager'' subclass which returns a ''QuestionQuerySet''. It provides simple access
to helpful utility methods.
"""

def get_query_set(self):
return QuestionQuerySet(self.model)

def active(self, slug=None):
return self.get_query_set().active(slug=slug)



44 changes: 44 additions & 0 deletions faq/models.py
@@ -0,0 +1,44 @@
from django.db import models
from datetime import datetime
from django.utils.translation import ugettext_lazy as _
from django.contrib.auth.models import User
from managers import QuestionManager
import enums

class FaqBase(models.Model):
'''
Base class for models.
'''
created_by = models.ForeignKey(User, null=True, editable=False, related_name="%(class)s_created_by" )
created_on = models.DateTimeField( _('created on'), default=datetime.now, editable=False, )
updated_on = models.DateTimeField( _('updated on'), editable=False )
updated_by = models.ForeignKey(User, null=True, editable=False )

class Meta:
abstract = True

class Question(FaqBase):
"""
Represents a frequently asked question.
"""

slug = models.SlugField( max_length=100, help_text="This is a unique identifier that allows your questions to display its detail view, ex 'how-can-i-contribute'", )
text = models.TextField(_('question'), help_text='The actual question itself.')
answer = models.TextField( _('answer'), help_text='The answer text.' )
status = models.IntegerField( choices=enums.QUESTION_STATUS_CHOICES, default=enums.STATUS_INACTIVE, help_text="Only questions with their status set to 'Active' will be displayed. " )
sort_order = models.IntegerField(_('sort order'), default=0, help_text='The order you would like the question to be displayed.')

objects = QuestionManager()

class Meta:
ordering = ['sort_order', 'created_on', ]

def __unicode__(self):
return self.text

def save(self):
self.updated_on = datetime.now()
super(Question, self).save()

0 comments on commit 6301f82

Please sign in to comment.