Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

buongiorno walt !

  • Loading branch information...
commit 99cbb37b51e37c01d206b33b9b7a31c5f7661045 1 parent ffc9ea0
@danieleguido authored
View
199 glue/__init__.py
@@ -0,0 +1,199 @@
+import json, os, inspect
+
+from django.db.models.query import QuerySet, RawQuerySet
+from django.conf import settings
+from django.http import HttpResponse, HttpRequest
+from django.forms import Form, IntegerField
+from django.core import serializers
+
+#
+# CONSTS
+# ======
+#
+API_DEFAULT_OFFSET = 0
+API_DEFAULT_LIMIT = 50
+API_AVAILABLE_METHODS = [ 'DELETE', 'POST', 'GET' ]
+API_EXCEPTION = 'GenericException'
+API_EXCEPTION_INTEGRITY = 'IntegrityError'
+API_EXCEPTION_DOESNOTEXIST = 'DoesNotExist'
+API_EXCEPTION_DUPLICATED = 'Duplicated'
+API_EXCEPTION_FORMERRORS = 'FormErrors'
+API_EXCEPTION_INCOMPLETE = 'Incomplete'
+API_EXCEPTION_EMPTY = 'Empty'
+API_EXCEPTION_INVALID = 'Invalid'
+API_EXCEPTION_OSERROR = 'OsError'
+
+#
+# MISC FUNCTIONS
+# ==============
+#
+def whosdaddy( level=2 ):
+ return inspect.stack()[level][3]
+
+
+#
+# REQUEST VALIDATION
+# ==================
+#
+class OffsetLimitForm( Form ):
+ offset = IntegerField( min_value=0, required=False, initial=0 )
+ limit = IntegerField( min_value=1, max_value=100, required=False, initial=25 )
+
+
+#
+# EPOXY
+# =====
+#
+# Helper to handle json response.
+#
+# Basic usage
+# -----------
+# In a django view:
+# <code>
+# def view_with_json_output( request ):
+# response = Epoxy( request ).json()
+# return response.json()
+# </code>
+#
+# Advanced usage
+# --------------
+# queryset =
+#
+class Epoxy:
+ """
+ Understand requet.REQUEST meta params like django filters, limit/offset
+
+ Usage:
+
+ queryset = <Model>.objects.filter( **kwargs )
+ return Epoxy( request ).get_response( queryset=queryset )
+
+ """
+ def __init__(self, request, method='GUESS' ):
+ self.request = request
+ self.response = { 'status':'ok' } # a ditionary of things
+ self.filters = {}
+ self.method = method
+ self.limit = API_DEFAULT_LIMIT
+ self.offset = API_DEFAULT_OFFSET
+ self.order_by = []
+ self.process()
+
+ def warning( self, key, message ):
+ if 'warnings' not in self.response['meta']:
+ self.response['meta']['warnings'] = {}
+ self.response['meta']['warnings'][ key ] = message
+
+ def process( self ):
+ self.response['meta'] = {}
+ self.response['meta']['action'] = whosdaddy(3)
+ self.response['meta']['user'] = self.request.user.username
+ # understand method via REQUEST params only if desired.
+ if self.method == 'GUESS':
+
+ if 'method' in self.request.REQUEST: # simulation
+ method = self.request.REQUEST.get('method')
+ if method not in API_AVAILABLE_METHODS:
+ self.warnings( 'order_by', "Method: %s is not available " % self.request.REQUEST.get('method') )
+ else:
+ self.response['meta']['method'] = method
+ self.method = method
+ else:
+ self.method = self.response['meta']['method'] = self.request.method
+
+
+ if self.method == 'GET' and 'filters' in self.request.REQUEST:
+ try:
+ self.filters = json.loads( self.request.REQUEST.get('filters') )
+ except Exception, e:
+ self.warnings( 'filters', "Exception: %s" % e )
+
+ # order by
+ if self.method == 'GET' and 'order_by' in self.request.REQUEST:
+ try:
+ self.order_by = j['meta']['order_by'] = json.loads( self.request.REQUEST.get('order_by') ) # json array
+ except Exception, e:
+ self.warnings( 'order_by', "Exception: %s" % e )
+
+ # limit / offset
+ if self.method=='GET' and ( 'offset' in self.request.REQUEST or 'limit' in self.request.REQUEST ) :
+ form = OffsetLimitForm( self.request.REQUEST )
+ if form.is_valid():
+ self.offset = form.cleaned_data['offset'] if form.cleaned_data['offset'] else self.offset
+ self.limit = form.cleaned_data['limit'] if form.cleaned_data['limit'] else self.limit
+ else:
+ self.warnings( 'offsets', form.errors )
+ self.response['meta']['offset'] = self.offset
+ self.response['meta']['limit'] = self.limit
+
+ # set limit of offset
+ self.response['meta']['next'] = {
+ 'offset': self.offset + self.limit,
+ 'limit': self.limit
+ }
+
+ # next / previous
+ if self.offset > 0:
+ self.response['meta']['previous'] = {
+ 'offset': max( self.offset - self.limit, 0 ),
+ 'limit': self.limit
+ }
+
+ return self
+
+ def single( self, model, kwargs ):
+ self.response['meta']['model'] = model.__name__
+ try:
+ self.response['object'] = model.objects.get( **kwargs ).json()
+ except model.DoesNotExist, e:
+ return self.throw_error( error="%s" % e, code=API_EXCEPTION_EMPTY )
+ return self
+
+ def queryset( self, queryset, model_name=None ):
+ if type( queryset ) == QuerySet:
+ self.response['meta']['total_count'] = queryset.filter( **self.filters ).count()
+ qs = queryset.filter( **self.filters ).order_by( *self.order_by )
+
+ elif type( queryset ) == RawQuerySet:
+ # Special exceptions for RawQuerySets (cannot filter, does not have count() method)
+ self.response['meta']['total_count'] = sum( 1 for r in queryset )
+ qs = queryset
+ else:
+ qs = queryset.filer()
+
+ # apply limits
+ qs = qs[ self.offset : self.offset + self.limit ]
+
+ if model_name is not None:
+ self.response['meta']['model'] = model_name # @todo: guess from queryset/rawqueryset ?
+
+
+ # "easier to ask for forgiveness than permission" (EAFP) rather than "look before you leap" (LBYL)
+ try:
+ self.response['objects'] = [ o.json() for o in qs ]
+
+ except AttributeError:
+ kwargs = { 'format': 'python', 'queryset': qs }
+ self.response['objects'] = []#serializers.serialize(**kwargs)
+
+ except Exception, e:
+ return self.throw_error( error="Exception: %s" % e, code=API_EXCEPTION_INVALID )
+
+ return self
+
+ def json( self, mimetype="application/json" ):
+ if self.request is not None and self.request.REQUEST.has_key('indent'):
+ return HttpResponse( json.dumps( self.response, indent=4), mimetype=mimetype)
+ return HttpResponse( json.dumps( self.response ), mimetype=mimetype)
+
+ def add( self, key, value, jsonify=False):
+ self.response[ key ] = value.json() if jsonify else value
+ return value
+
+ def throw_error( self, error="", code=API_EXCEPTION ):
+ self.response[ 'status' ] = 'error'
+ self.response[ 'error' ] = error
+ self.response[ 'code' ] = code
+
+ return self
+
View
226 glue/api.py
@@ -0,0 +1,226 @@
+import logging, os, mimetypes
+import datetime as dt
+
+from django.conf import settings
+from django.db.models.loading import get_model
+from django.db import IntegrityError
+from django.utils.translation import ugettext as _
+from django.template.defaultfilters import slugify
+
+from glue import Epoxy, API_EXCEPTION_FORMERRORS, API_EXCEPTION_INTEGRITY, API_EXCEPTION_DOESNOTEXIST, API_EXCEPTION_OSERROR
+from glue.models import Page, Pin
+from glue.forms import AddPageForm, AddPinForm, EditPinForm, UploadPinForm
+
+
+logger = logging.getLogger(__name__)
+
+def index(request):
+ # logger.info("Welcome to GLUEBOX api")
+ return Epoxy( request ).json()
+
+def manage_objects( request, model_name ):
+ # logger.info("Welcome to GLUEBOX api")
+ return Epoxy( request ).queryset( get_model( "glue", model_name ).objects.filter(), model_name=model_name ).json()
+
+def manage_single_object( request, model_name, pk ):
+ # logger.info("Welcome to GLUEBOX api")
+ return Epoxy( request ).single( Page, {'pk':pk} ).json()
+
+def test( request ):
+ response = Epoxy( request )
+ return response.json()
+
+def pages(request):
+ # logger.info("Welcome to GLUEBOX api")
+ response = Epoxy( request )
+ if response.method =='POST':
+ form = AddPageForm( request.REQUEST )
+ if not form.is_valid():
+ return response.throw_error( error=form.errors, code=API_EXCEPTION_FORMERRORS).json()
+ try:
+ p_en = Page( title=form.cleaned_data['title_en'], language='EN', slug=form.cleaned_data['slug'])
+ p_en.save()
+
+ p_fr = Page( title=form.cleaned_data['title_fr'], language='FR', slug=form.cleaned_data['slug'])
+ p_fr.save()
+ except IntegrityError, e:
+ return response.throw_error( error="%s" % e, code=API_EXCEPTION_INTEGRITY).json()
+
+ response.add('object',[ p_en.json(), p_fr.json() ])
+
+ return response.queryset( Page.objects.filter() ).json()
+
+
+def page( request, page_id ):
+ return Epoxy( request ).single( Page, {'id':page_id} ).json()
+
+def page_by_slug( request, page_slug, page_language ):
+ return Epoxy( request ).single( Page, {'slug':page_slug,'language':page_language} ).json()
+
+def pins( request ):
+ response = Epoxy( request )
+ if response.method =='POST':
+ form = AddPinForm( request.REQUEST )
+ if not form.is_valid():
+ return response.throw_error( error=form.errors, code=API_EXCEPTION_FORMERRORS).json()
+
+ if len(form.cleaned_data['page_slug']) > 0:
+ # attacch new pin to a selected page (both languages)
+ response.add('page_slug',form.cleaned_data['page_slug'])
+
+ try:
+ page_en = Page.objects.get( slug=form.cleaned_data['page_slug'],language='EN')
+ page_fr = Page.objects.get( slug=form.cleaned_data['page_slug'],language='FR')
+ except Page.DoesNotExist:
+ return response.throw_error( error=_("selected page does not exists"), code=API_EXCEPTION_FORMERRORS).json()
+
+ response.add('page', [ page_en.json(), page_fr.json() ] )
+
+ if len(form.cleaned_data['parent_pin_slug']) > 0:
+ # attacch new pin to a selected pin (pin children, usually displayed on the right side, both languages)
+ response.add('parent_pin_slug',form.cleaned_data['parent_pin_slug'])
+
+ try:
+ pin_en = Pin.objects.get( slug=form.cleaned_data['parent_pin_slug'],language='EN')
+ pin_fr = Pin.objects.get( slug=form.cleaned_data['parent_pin_slug'],language='FR')
+ except Pin.DoesNotExist, e:
+ return response.throw_error( error=_("selected pin does not exists. Exception: %s" % e), code=API_EXCEPTION_FORMERRORS).json()
+
+ response.add('pin', [ pin_en.json(), pin_fr.json() ] )
+
+ #return response.queryset( Pin.objects.filter() ).json()
+
+ try:
+ p_en = Pin( title=form.cleaned_data['title_en'], language='EN', slug=form.cleaned_data['slug'])
+ p_fr = Pin( title=form.cleaned_data['title_fr'], language='FR', slug=form.cleaned_data['slug'])
+
+ if len(form.cleaned_data['parent_pin_slug']) > 0:
+ p_en.parent = pin_en
+ p_fr.parent = pin_fr
+
+
+ p_en.save()
+ p_fr.save()
+ except IntegrityError, e:
+ return response.throw_error( error={'slug':"Exception %s" % e}, code=API_EXCEPTION_INTEGRITY).json()
+
+ if len(form.cleaned_data['page_slug']) > 0:
+ page_en.pins.add( p_en )
+ page_en.save()
+ page_fr.pins.add( p_fr )
+ page_fr.save()
+
+ response.add('object',[ p_en.json(), p_fr.json() ])
+
+ return response.queryset( Pin.objects.filter() ).json()
+
+
+def pin( request, pin_id ):
+ # @todo: check pin permissions
+ response = Epoxy( request )
+ if response.method == 'POST':
+ form = EditPinForm( request.REQUEST )
+ if form.is_valid():
+ try:
+ pin = Pin.objects.get( id=pin_id )
+ pin.title = form.cleaned_data['title']
+ pin.abstract = form.cleaned_data['abstract']
+ pin.content = form.cleaned_data['content']
+ pin.save()
+ except Pin.DoesNotExist, e:
+ return response.throw_error( error="%s" % e, code=API_EXCEPTION_DOESNOTEXIST).json()
+ else:
+ return response.throw_error( error=form.errors, code=API_EXCEPTION_FORMERRORS).json()
+
+ elif response.method=='DELETE':
+ try:
+ Pin.objects.filter(slug=Pin.objects.get(id=pin_id).slug).delete()
+ except Pin.DoesNotExist, e:
+ return response.throw_error( error="%s" % e, code=API_EXCEPTION_DOESNOTEXIST).json()
+ return response.json()
+
+ return response.single( Pin, {'id':pin_id} ).json()
+
+def pin_by_slug( request, pin_slug, pin_language ):
+ return Epoxy( request ).single( Pin, {'slug':pin_slug,'language':pin_language} ).json()
+
+def publish_pin( request, pin_id ):
+ response = Epoxy( request )
+ new_status = request.POST.get("new_status")
+
+ try:
+ if new_status in dict(Pin.PIN_STATUS_CHOICES):
+ p=Pin.objects.get( id=pin_id )
+ p.status=new_status
+ p.save()
+ return response.json()
+ else:
+ return response.throw_error( error="status %s incorrect" % new_status).json()
+
+ except Pin.DoesNotExist, e:
+ return response.throw_error( error="%s" % e, code=API_EXCEPTION_DOESNOTEXIST).json()
+
+
+def pin_upload( request ):
+ response = Epoxy( request )
+ d = dt.datetime.now()
+
+ form = UploadPinForm( request.REQUEST )
+ if not form.is_valid():
+ return response.throw_error(error=form.errors, code=API_EXCEPTION_FORMERRORS)
+
+ if len(form.cleaned_data['page_slug']) > 0:
+ # attacch new pin to a selected page (both languages)
+ response.add('page_slug',form.cleaned_data['page_slug'])
+
+ try:
+ page_en = Page.objects.get( slug=form.cleaned_data['page_slug'],language='EN')
+ page_fr = Page.objects.get( slug=form.cleaned_data['page_slug'],language='FR')
+ except Page.DoesNotExist:
+ return response.throw_error( error=_("selected page does not exists"), code=API_EXCEPTION_FORMERRORS).json()
+
+ response.add('page', [ page_en.json(), page_fr.json() ] )
+
+ pin_path = response.add('path', "pins/%s-%s" % ( d.year, ( d.month if d.month >10 else "0%s" % d.month ) ) )
+ absolute_pin_path = os.path.join( settings.MEDIA_ROOT, pin_path )
+
+ try:
+ if not os.path.exists( absolute_pin_path ):
+ os.makedirs( absolute_pin_path ) # throw an OS ERROR if exists... OR if it is not writable!
+ except OSError, e:
+ return response.throw_error( error="%s" % e, code=API_EXCEPTION_OSERROR ).json()
+
+ for f in request.FILES.getlist('files[]'):
+ if f.size == 0:
+ return response.throw_error( error="uploaded file is empty", code=API_EXCEPTION_EMPTY ).json()
+
+ filename = os.path.join( absolute_pin_path, f.name)
+ pinup = open( filename , 'w' )
+
+ for chunk in f.chunks():
+ pinup.write( chunk )
+
+ pinup.close()
+
+ # guess mimetype
+ pin_mimetype = mimetypes.guess_type( filename )[0]
+
+ filetitle, extension = os.path.splitext( f.name )
+
+ try:
+ p_en = Pin( title=filetitle, language='EN', slug=slugify( "-".join( filetitle.split("_") ) ), mimetype=pin_mimetype, local=os.path.join( pin_path, os.path.basename( filename ) ) )
+ p_fr = Pin( title=filetitle, language='FR', slug=slugify( "-".join( filetitle.split("_") ) ), mimetype=pin_mimetype, local=os.path.join( pin_path, os.path.basename( filename ) ) )
+ p_en.save()
+ p_fr.save()
+
+ except IntegrityError, e:
+ return response.throw_error( error="%s" % e, code=API_EXCEPTION_INTEGRITY ).json()
+
+ if page_en and page_fr:
+ page_en.pins.add( p_en )
+ page_fr.pins.add( p_fr )
+ page_en.save()
+ page_fr.save()
+
+ return response.json()
+
View
88 glue/models.py
@@ -0,0 +1,88 @@
+from django.db import models
+from django.contrib.auth.models import User
+
+LANGUAGE_CHOICES = (
+ ('EN', 'EN'),
+ ('FR', 'FR')
+)
+
+class Geo( models.Model): # geo spot, with zoom
+ lat = models.FloatField() # map center LAT
+ lon = models.FloatField() # map center LON
+ zoom = models.IntegerField() # start zoom
+ content = models.TextField( default="", blank=True, null=True ) # textual GEO description
+
+class Pin( models.Model ):
+ published='P'
+ draft='D'
+
+ PIN_STATUS_CHOICES = ( (published,"published"),(draft,"draft") )
+
+ slug = models.SlugField()
+ title = models.CharField( max_length=160, default="", blank=True, null=True )
+ abstract = models.TextField( default="", blank=True, null=True )
+ content = models.TextField( default="", blank=True, null=True )
+ language = models.CharField( max_length=2, default='EN', choices=LANGUAGE_CHOICES ) # magic admin features: create a pin for the same language
+
+ mimetype = models.CharField( max_length=255, default="", blank=True, null=True )
+ sort = models.IntegerField( default=0 )
+
+ date = models.DateField( blank=True, null=True ) # main date, manually added
+ date_last_modified = models.DateField( auto_now=True ) # date last save()
+
+ local = models.FileField( upload_to='pins/%Y-%m/', blank=True, null=True ) # local stored file
+ permalink = models.TextField( default="", blank=True, null=True ) # remote link
+
+ related = models.ManyToManyField("self", symmetrical=True, null=True, blank=True)
+ parent = models.ForeignKey("self", null=True, blank=True, related_name="children" )
+ status = models.CharField( max_length=2, default="D",choices=PIN_STATUS_CHOICES)
+
+ geos = models.ManyToManyField( Geo, blank=True, null=True ) # add geographic point
+ users = models.ManyToManyField( User, blank=True, null=True )
+
+ class Meta:
+ unique_together = ( "slug", "language" )
+ ordering = ('sort','id')
+
+ def __unicode__(self):
+ return "%s (%s) a.k.a. %s" % (self.slug, self.language, self.title)
+
+ def json( self ):
+ return{
+ 'id': self.id,
+ 'slug':self.slug,
+ 'title': self.title,
+ 'abstract': self.abstract,
+ 'content': self.content,
+ 'language': self.language,
+ 'mimetype': self.mimetype
+ }
+
+
+class PageAbstract( models.Model ):
+ slug = models.SlugField()
+ title = models.CharField( max_length=160, default="", blank=True, null=True )
+ abstract = models.TextField( default="", blank=True, null=True )
+ content = models.TextField( default="", blank=True, null=True )
+
+ language = models.CharField( max_length=2, default='EN', choices=LANGUAGE_CHOICES ) # magic admin features: create a pin for the same language
+ sort = models.IntegerField( default=0 )
+
+ class Meta:
+ unique_together = ( "slug", "language" )
+ abstract = True
+
+ def __unicode__(self):
+ return "%s (%s) a.k.a. %s" % (self.slug, self.language, self.title)
+ def json( self ):
+ return{
+ 'id': self.id,
+ 'slug':self.slug,
+ 'title': self.title,
+ 'abstract': self.abstract,
+ 'content': self.content,
+ 'language': self.language
+ }
+
+class Page( PageAbstract ):
+ pins = models.ManyToManyField( Pin, null=True, blank=True, related_name="page")
View
22 glue/urls.py
@@ -0,0 +1,22 @@
+from django.conf.urls.defaults import patterns, include, url
+
+
+urlpatterns = patterns('',
+
+ url(r'^$', 'glue.api.index', name='glue_api_index'),
+
+ url(r'^api/manage/(?P<model_name>[a-zA-Z_]+)/$', 'glue.api.manage_objects', name='glue_api_manage_objects'),
+ url(r'^api/manage/(?P<model_name>[a-zA-Z_]+)/(?P<pk>\d+)$', 'glue.api.manage_single_object', name='glue_api_manage_single_object'),
+
+ url(r'^api/test/$', 'glue.api.test', name='glue_api_test'), # get list, post single page
+
+ url(r'^api/page/$', 'glue.api.pages', name='glue_api_pages'), # get list, post single page
+ url(r'^api/page/(?P<page_id>\d+)/$', 'glue.api.page', name='glue_api_page'),
+ url(r'^api/page/(?P<page_slug>[a-zA-Z\d\-]+)/(?P<page_language>[a-zA-Z]{2})/$', 'glue.api.page_by_slug', name='glue_api_page_by_slug'),
+
+ url(r'^api/pin/$', 'glue.api.pins', name='glue_api_pins'), # get list, post single page
+ url(r'^api/pin/(?P<pin_id>\d+)/$', 'glue.api.pin', name='glue_api_pin'),
+ url(r'^api/pin/(?P<pin_slug>[a-zA-Z\d\-]+)/(?P<pin_language>[a-zA-Z]{2})/$', 'glue.api.pin_by_slug', name='glue_api_pin_by_slug'),
+ url(r'^api/pin/(?P<pin_id>\d+)/publish/$', 'glue.api.publish_pin', name='glue_api_publish_pin'),
+ url(r'^api/pin/upload/$', 'glue.api.pin_upload', name='glue_api_pin_upload'),
+)
View
10 manage.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+ os.environ.setdefault("DJANGO_SETTINGS_MODULE", "walt.settings")
+
+ from django.core.management import execute_from_command_line
+
+ execute_from_command_line(sys.argv)
View
3  requirements.txt
@@ -0,0 +1,3 @@
+Django==1.4.5
+argparse==1.2.1
+wsgiref==0.1.2
View
0  walt/__init__.py
No changes.
View
162 walt/settings.py
@@ -0,0 +1,162 @@
+# Django settings for walt project.
+import local_settings
+
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+
+ADMINS = (
+ # ('Your Name', 'your_email@example.com'),
+)
+
+MANAGERS = ADMINS
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3', # Add 'postgresql_psycopg2', 'mysql', 'sqlite3' or 'oracle'.
+ 'NAME': '', # Or path to database file if using sqlite3.
+ 'USER': '', # Not used with sqlite3.
+ 'PASSWORD': '', # Not used with sqlite3.
+ 'HOST': '', # Set to empty string for localhost. Not used with sqlite3.
+ 'PORT': '', # Set to empty string for default. Not used with sqlite3.
+ }
+}
+
+# Hosts/domain names that are valid for this site; required if DEBUG is False
+# See https://docs.djangoproject.com/en/1.4/ref/settings/#allowed-hosts
+ALLOWED_HOSTS = []
+
+# 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 available on all operating systems.
+# In a Windows environment this must be set to your system time zone.
+TIME_ZONE = 'Europe/Rome'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'it-it'
+
+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
+
+# If you set this to False, Django will not format dates, numbers and
+# calendars according to the current locale.
+USE_L10N = True
+
+# If you set this to False, Django will not use timezone-aware datetimes.
+USE_TZ = True
+
+# Absolute filesystem path to the directory that will hold user-uploaded files.
+# Example: "/home/media/media.lawrence.com/media/"
+MEDIA_ROOT = local_settings.MEDIA_ROOT
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash.
+# Examples: "http://media.lawrence.com/media/", "http://example.com/media/"
+MEDIA_URL = ''
+
+# Absolute path to the directory static files should be collected to.
+# Don't put anything in this directory yourself; store your static files
+# in apps' "static/" subdirectories and in STATICFILES_DIRS.
+# Example: "/home/media/media.lawrence.com/static/"
+STATIC_ROOT = ''
+
+# URL prefix for static files.
+# Example: "http://media.lawrence.com/static/"
+STATIC_URL = '/static/'
+
+# Additional locations of static files
+STATICFILES_DIRS = (
+ # Put strings here, like "/home/html/static" or "C:/www/django/static".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+)
+
+# List of finder classes that know how to find static files in
+# various locations.
+STATICFILES_FINDERS = (
+ 'django.contrib.staticfiles.finders.FileSystemFinder',
+ 'django.contrib.staticfiles.finders.AppDirectoriesFinder',
+# 'django.contrib.staticfiles.finders.DefaultStorageFinder',
+)
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = local_settings.SECRET_KEY
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.Loader',
+ 'django.template.loaders.app_directories.Loader',
+# 'django.template.loaders.eggs.Loader',
+)
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.middleware.csrf.CsrfViewMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ # Uncomment the next line for simple clickjacking protection:
+ # 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+)
+
+ROOT_URLCONF = 'walt.urls'
+
+# Python dotted path to the WSGI application used by Django's runserver.
+WSGI_APPLICATION = 'walt.wsgi.application'
+
+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.
+)
+
+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',
+ # Uncomment the next line to enable admin documentation:
+ # 'django.contrib.admindocs',
+ 'glue'
+)
+
+# A sample logging configuration. The only tangible logging
+# performed by this configuration is to send an email to
+# the site admins on every HTTP 500 error when DEBUG=False.
+# See http://docs.djangoproject.com/en/dev/topics/logging for
+# more details on how to customize your logging configuration.
+LOGGING = {
+ 'version': 1,
+ 'disable_existing_loggers': False,
+ 'filters': {
+ 'require_debug_false': {
+ '()': 'django.utils.log.RequireDebugFalse'
+ }
+ },
+ 'handlers': {
+ 'mail_admins': {
+ 'level': 'ERROR',
+ 'filters': ['require_debug_false'],
+ 'class': 'django.utils.log.AdminEmailHandler'
+ }
+ },
+ 'loggers': {
+ 'django.request': {
+ 'handlers': ['mail_admins'],
+ 'level': 'ERROR',
+ 'propagate': True,
+ },
+ }
+}
+
+
+# walt ad hoc settings
+LOCALE_PATHS = local_settings.LOCALE_PATHS
+LANGUAGES = local_settings.LANGUAGES
View
17 walt/urls.py
@@ -0,0 +1,17 @@
+from django.conf.urls import patterns, include, url
+
+# Uncomment the next two lines to enable the admin:
+# from django.contrib import admin
+# admin.autodiscover()
+
+urlpatterns = patterns('',
+ # Examples:
+ # url(r'^$', 'walt.views.home', name='home'),
+ # url(r'^walt/', include('walt.foo.urls')),
+
+ # Uncomment the admin/doc line below to enable admin documentation:
+ # url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
+
+ # Uncomment the next line to enable the admin:
+ # url(r'^admin/', include(admin.site.urls)),
+)
View
28 walt/wsgi.py
@@ -0,0 +1,28 @@
+"""
+WSGI config for walt project.
+
+This module contains the WSGI application used by Django's development server
+and any production WSGI deployments. It should expose a module-level variable
+named ``application``. Django's ``runserver`` and ``runfcgi`` commands discover
+this application via the ``WSGI_APPLICATION`` setting.
+
+Usually you will have the standard Django WSGI application here, but it also
+might make sense to replace the whole Django WSGI application with a custom one
+that later delegates to the Django one. For example, you could introduce WSGI
+middleware here, or combine a Django application with an application of another
+framework.
+
+"""
+import os
+
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "walt.settings")
+
+# This application object is used by any WSGI server configured to use this
+# file. This includes Django's development server, if the WSGI_APPLICATION
+# setting points here.
+from django.core.wsgi import get_wsgi_application
+application = get_wsgi_application()
+
+# Apply WSGI middleware here.
+# from helloworld.wsgi import HelloWorldApplication
+# application = HelloWorldApplication(application)
Please sign in to comment.
Something went wrong with that request. Please try again.