migrate to django 1.9

This commit is contained in:
j 2016-03-06 16:05:46 +05:30
parent f7855147ce
commit e5dd8aaab7
48 changed files with 659 additions and 848 deletions

1
.gitignore vendored
View File

@ -14,3 +14,4 @@ build
*.pyc *.pyc
*~ *~
*.swp *.swp
local

View File

@ -20,7 +20,8 @@ end script
exec start-stop-daemon \ exec start-stop-daemon \
--pidfile /var/run/oxdata/oxdata.pid \ --pidfile /var/run/oxdata/oxdata.pid \
--start -c $USER -d $VENV/oxdata \ --start -c $USER -d $VENV/oxdata \
--exec $VENV/bin/gunicorn_django -- \ --exec $VENV/bin/gunicorn -- \
wsgi:application \
--bind 127.0.0.1:8087 \ --bind 127.0.0.1:8087 \
--workers 5 \ --workers 5 \
--max-requests 1000 \ --max-requests 1000 \

View File

@ -1,3 +0,0 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4

View File

@ -1,10 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>{{sitename}} API</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
<script type="text/javascript" src="/static/oxjs/build/Ox.js"></script>
<script type="text/javascript" src="/static/js/pandora.api.js"></script>
</head>
<body></body>
</html>

View File

@ -1,10 +0,0 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.conf.urls.defaults import *
urlpatterns = patterns("api.views",
(r'^$', 'api'),
)

View File

@ -5,10 +5,7 @@ from __future__ import division
import os.path import os.path
import hashlib import hashlib
from django.conf import settings
from django.db import models from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User
from django.core.files.base import ContentFile from django.core.files.base import ContentFile
from lookup.models import MovieId from lookup.models import MovieId
@ -43,6 +40,9 @@ def cover_path(url, filename):
name = "%s.%s" % (h, ext) name = "%s.%s" % (h, ext)
return os.path.join('covers', h[:2], h[2:4], h[4:6], name) return os.path.join('covers', h[:2], h[2:4], h[4:6], name)
def covercache_image_path(i, f):
return cover_path(i.url.encode('utf-8'), f)
class CoverCache(models.Model): class CoverCache(models.Model):
class Meta: class Meta:
unique_together = ("isbn", "url") unique_together = ("isbn", "url")
@ -54,7 +54,7 @@ class CoverCache(models.Model):
url = models.CharField(max_length=1024) url = models.CharField(max_length=1024)
site = models.CharField(max_length=255) site = models.CharField(max_length=255)
site_id = models.CharField(max_length=42) site_id = models.CharField(max_length=42)
image = models.ImageField(max_length=255, upload_to=lambda i, f: cover_path(i.url.encode('utf-8'), f)) image = models.ImageField(max_length=255, upload_to=covercache_image_path)
status = models.CharField(max_length=1024, default='200') status = models.CharField(max_length=1024, default='200')
failed = models.BooleanField(default=False) failed = models.BooleanField(default=False)
@ -89,10 +89,13 @@ class CoverCache(models.Model):
self.image.delete() self.image.delete()
return self.image return self.image
def cover_image_path(i, f):
return cover_path('upload/%s' % i.id, f)
class Cover(models.Model): class Cover(models.Model):
created = models.DateTimeField(auto_now_add=True) created = models.DateTimeField(auto_now_add=True)
modified = models.DateTimeField(auto_now=True) modified = models.DateTimeField(auto_now=True)
isbn = models.ForeignKey(MovieId, related_name='cover') isbn = models.ForeignKey(MovieId, related_name='cover')
cover = models.ImageField(max_length=255, upload_to=lambda i, f: cover_path('upload/%s' % i.id, f)) cover = models.ImageField(max_length=255, upload_to=cover_image_path)

View File

@ -1,6 +1,8 @@
from django.conf.urls.defaults import * from django.conf.urls import url
urlpatterns = patterns('oxdata.cover.views', import views
(r'^$', 'cover'),
) urlpatterns = [
url(r'^$', views.cover),
]

View File

@ -1,13 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
import os.path
from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from ox.django.shortcuts import render_to_json_response from oxdjango.shortcuts import render_to_json_response
import models import models

View File

@ -1,15 +1,12 @@
# -*- coding: UTF-8 -*- # -*- coding: UTF-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
import os
from django.conf import settings
from ox import find_re
import ox.web.criterion import ox.web.criterion
import ox.web.imdb import ox.web.imdb
import ox.web.impawards import ox.web.impawards
import models import models
from oxdata.poster.models import PosterCache from poster.models import PosterCache
import modules import modules
def addPoster(m, url, site, site_id): def addPoster(m, url, site, site_id):

View File

@ -1,78 +1,38 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-03-06 10:11
from __future__ import unicode_literals
from south.db import db from django.db import migrations, models
from django.db import models
from oxdata.lookup.models import *
class Migration:
class Migration(migrations.Migration):
def forwards(self, orm):
initial = True
# Adding model 'MovieId'
db.create_table('lookup_movieid', ( dependencies = [
('id', orm['lookup.MovieId:id']), ]
('created', orm['lookup.MovieId:created']),
('modified', orm['lookup.MovieId:modified']), operations = [
('title', orm['lookup.MovieId:title']), migrations.CreateModel(
('year', orm['lookup.MovieId:year']), name='MovieId',
('director', orm['lookup.MovieId:director']), fields=[
('series_title', orm['lookup.MovieId:series_title']), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('episode_title', orm['lookup.MovieId:episode_title']), ('created', models.DateTimeField(auto_now_add=True)),
('season', orm['lookup.MovieId:season']), ('modified', models.DateTimeField(auto_now=True)),
('episode', orm['lookup.MovieId:episode']), ('title', models.CharField(blank=True, default=b'', max_length=1000)),
('oxdb_id', orm['lookup.MovieId:oxdb_id']), ('year', models.CharField(blank=True, default=b'', max_length=4)),
('imdb_id', orm['lookup.MovieId:imdb_id']), ('director', models.CharField(blank=True, default=b'', max_length=1000)),
('amg_id', orm['lookup.MovieId:amg_id']), ('series_title', models.CharField(blank=True, default=b'', max_length=1000)),
('wikipedia_id', orm['lookup.MovieId:wikipedia_id']), ('episode_title', models.CharField(blank=True, default=b'', max_length=1000)),
('criterion_id', orm['lookup.MovieId:criterion_id']), ('season', models.IntegerField(default=-1)),
('impawards_id', orm['lookup.MovieId:impawards_id']), ('episode', models.IntegerField(default=-1)),
)) ('oxdb_id', models.CharField(blank=True, default=None, max_length=42, null=True, unique=True)),
db.send_create_signal('lookup', ['MovieId']) ('imdb_id', models.CharField(blank=True, default=None, max_length=7, null=True, unique=True)),
('amg_id', models.IntegerField(blank=True, default=None, null=True, unique=True)),
# Adding model 'Karagarga' ('archiveorg_id', models.CharField(blank=True, default=None, max_length=255, null=True, unique=True)),
db.create_table('lookup_karagarga', ( ('wikipedia_id', models.CharField(blank=True, default=None, max_length=255, null=True, unique=True)),
('id', orm['lookup.Karagarga:id']), ('criterion_id', models.IntegerField(blank=True, default=None, null=True, unique=True)),
('movie_id', orm['lookup.Karagarga:movie_id']), ('impawards_id', models.CharField(blank=True, default=None, max_length=255, null=True, unique=True)),
('karagarga_id', orm['lookup.Karagarga:karagarga_id']), ],
)) ),
db.send_create_signal('lookup', ['Karagarga']) ]
def backwards(self, orm):
# Deleting model 'MovieId'
db.delete_table('lookup_movieid')
# Deleting model 'Karagarga'
db.delete_table('lookup_karagarga')
models = {
'lookup.karagarga': {
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'karagarga_id': ('django.db.models.fields.IntegerField', [], {'unique': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'karagarga_ids'", 'to': "orm['lookup.MovieId']"})
},
'lookup.movieid': {
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
}
}
complete_apps = ['lookup']

View File

@ -1,47 +0,0 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Deleting model 'karagarga'
db.delete_table('lookup_karagarga')
def backwards(self, orm):
# Adding model 'karagarga'
db.create_table('lookup_karagarga', (
('movie_id', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='karagarga_ids', to=orm['lookup.MovieId'])),
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('karagarga_id', self.gf('django.db.models.fields.IntegerField')(unique=True)),
))
db.send_create_signal('lookup', ['karagarga'])
models = {
'lookup.movieid': {
'Meta': {'object_name': 'MovieId'},
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
}
}
complete_apps = ['lookup']

View File

@ -1,16 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
import os import os
import hashlib
from urllib import quote from urllib import quote
from django.db import models from django.db import models
from django.db.models import Q, Max
from django.contrib.auth.models import User
import ox import ox
from ox.normalize import canonical_name, normalize_path, strip_accents from ox.normalize import canonical_name
from ox import strip_tags
import ox.web.archive import ox.web.archive
import ox.web.imdb import ox.web.imdb
import ox.web.wikipedia import ox.web.wikipedia

View File

@ -1,7 +1,8 @@
from django.conf.urls.defaults import * from django.conf.urls import url
urlpatterns = patterns('oxdata.lookup.views', import views
(r'^$', 'ids'),
(r'^urls$', 'urls'),
)
urlpatterns = [
url(r'^$', views.ids),
url(r'^urls$', views.urls),
]

View File

@ -1,13 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
import os.path from oxdjango.shortcuts import render_to_json_response, json_response
from django.db import models from oxdjango.api import actions
from django.db.models import Q
from django.contrib.auth.models import User
from ox.django.shortcuts import render_to_json_response, json_response
from ox.utils import json
from api.actions import actions
import models import models

View File

@ -1,5 +1,6 @@
#!/usr/bin/env python #!/usr/bin/env python
import os import os
import sys
root_dir = os.path.normpath(os.path.abspath(os.path.dirname(__file__))) root_dir = os.path.normpath(os.path.abspath(os.path.dirname(__file__)))
os.chdir(root_dir) os.chdir(root_dir)
@ -8,13 +9,8 @@ os.chdir(root_dir)
activate_this = os.path.join(root_dir, '..', 'bin', 'activate_this.py') activate_this = os.path.join(root_dir, '..', 'bin', 'activate_this.py')
execfile(activate_this, dict(__file__=activate_this)) execfile(activate_this, dict(__file__=activate_this))
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__": if __name__ == "__main__":
execute_manager(settings) os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
from django.core.management import execute_from_command_line
execute_from_command_line(sys.argv)

View File

@ -11,7 +11,7 @@ import base64
from django.db import models from django.db import models
from django.conf import settings from django.conf import settings
import ox import ox
from ox.django.fields import DictField from oxdjango.fields import DictField
from lookup.models import get_movie_id from lookup.models import get_movie_id
from poster.models import getPosters from poster.models import getPosters
@ -238,10 +238,11 @@ def get_new_ids(timeout=-1):
ids = re.compile('<loc>http://www.imdb.com/title/tt(\d{7})/combined</loc>').findall(s) ids = re.compile('<loc>http://www.imdb.com/title/tt(\d{7})/combined</loc>').findall(s)
added = 0 added = 0
for i in frozenset(ids) - known_ids: for i in frozenset(ids) - known_ids:
m = Imdb(imdb=i) m, created = Imdb.objects.get_or_create(imdb=i)
m.update() m.update()
print m print m
added += 1 if created:
added += 1
if added: if added:
print url, added print url, added

View File

@ -2,12 +2,11 @@
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division from __future__ import division
import re
from ox.django.shortcuts import render_to_json_response, json_response from oxdjango.shortcuts import render_to_json_response, json_response
import ox.web.imdb import ox.web.imdb
from api.actions import actions from oxdjango.api import actions
import models import models
def getId(request, data): def getId(request, data):

View File

@ -0,0 +1 @@
from actions import actions

View File

@ -1,17 +1,16 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
import sys from __future__ import division, with_statement
import inspect import inspect
import sys
from django.conf import settings from django.conf import settings
from ox.django.shortcuts import render_to_json_response, json_response from ..shortcuts import render_to_json_response, json_response
from ox.utils import json
def autodiscover(): def autodiscover():
#register api actions from all installed apps # Register api actions from all installed apps
from django.utils.importlib import import_module from importlib import import_module
from django.utils.module_loading import module_has_submodule from django.utils.module_loading import module_has_submodule
for app in settings.INSTALLED_APPS: for app in settings.INSTALLED_APPS:
if app != 'api': if app != 'api':
@ -50,62 +49,75 @@ def trim(docstring):
class ApiActions(dict): class ApiActions(dict):
properties = {} properties = {}
versions = {}
def __init__(self): def __init__(self):
def api(request, data): def api(request, data):
''' '''
returns list of all known api actions Returns a list of all api actions
param data { takes {
docs: bool code: boolean, // if true, return source code (optional)
} docs: boolean // if true, return doc strings (optional)
if docs is true, action properties contain docstrings }
return { returns {
status: {'code': int, 'text': string}, actions: {
data: { name: {
actions: { cache: boolean, // if false, don't cache results
'api': { code: string, // source code
cache: true, doc: string // doc strings
doc: 'recursion' },
}, ... // more actions
'hello': {
cache: true,
..
}
...
}
}
} }
}
''' '''
docs = data.get('docs', False) docs = data.get('docs', False)
code = data.get('code', False) code = data.get('code', False)
_actions = self.keys() version = getattr(request, 'version', None)
if version:
_actions = self.versions.get(version, {}).keys()
_actions = list(set(_actions + self.keys()))
else:
_actions = self.keys()
_actions.sort() _actions.sort()
actions = {} actions = {}
for a in _actions: for a in _actions:
actions[a] = self.properties[a] actions[a] = self.properties[a]
if docs: if docs:
actions[a]['doc'] = self.doc(a) actions[a]['doc'] = self.doc(a, version)
if code: if code:
actions[a]['code'] = self.code(a) actions[a]['code'] = self.code(a, version)
response = json_response({'actions': actions}) response = json_response({'actions': actions})
return render_to_json_response(response) return render_to_json_response(response)
self.register(api) self.register(api)
def doc(self, f): def doc(self, name, version=None):
return trim(self[f].__doc__) if version:
f = self.versions[version].get(name, self.get(name))
else:
f = self[name]
return trim(f.__doc__)
def code(self, name): def code(self, name, version=None):
f = self[name] if version:
f = self.versions[version].get(name, self.get(name))
else:
f = self[name]
if name != 'api' and hasattr(f, 'func_closure') and f.func_closure: if name != 'api' and hasattr(f, 'func_closure') and f.func_closure:
f = f.func_closure[0].cell_contents fc = filter(lambda c: hasattr(c.cell_contents, '__call__'), f.func_closure)
f = fc[len(fc)-1].cell_contents
info = f.func_code.co_filename[len(settings.PROJECT_ROOT)+1:] info = f.func_code.co_filename[len(settings.PROJECT_ROOT)+1:]
info = u'%s:%s' % (info, f.func_code.co_firstlineno) info = u'%s:%s' % (info, f.func_code.co_firstlineno)
return info, trim(inspect.getsource(f)) return info, trim(inspect.getsource(f))
def register(self, method, action=None, cache=True): def register(self, method, action=None, cache=True, version=None):
if not action: if not action:
action = method.func_name action = method.func_name
self[action] = method if version:
if not version in self.versions:
self.versions[version] = {}
self.versions[version][action] = method
else:
self[action] = method
self.properties[action] = {'cache': cache} self.properties[action] = {'cache': cache}
def unregister(self, action): def unregister(self, action):
@ -114,3 +126,10 @@ class ApiActions(dict):
actions = ApiActions() actions = ApiActions()
def error(request, data):
'''
This action is used to test API error codes. It should return a 503 error.
'''
success = error_is_success
return render_to_json_response({})
actions.register(error)

View File

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.conf.urls import url
import views
import actions
actions.autodiscover()
urlpatterns = [
url(r'^$', views.api),
]

View File

@ -2,20 +2,16 @@
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, with_statement from __future__ import division, with_statement
import os import json
import copy
from django.shortcuts import render_to_response from django.shortcuts import render_to_response
from django.template import RequestContext from django.template import RequestContext
from django.conf import settings from django.conf import settings
from django.db.models import Max, Sum
from ox.django.shortcuts import render_to_json_response, json_response from ..shortcuts import render_to_json_response, json_response
from ox.utils import json
from actions import actions from actions import actions
def api(request): def api(request):
if request.META['REQUEST_METHOD'] == "OPTIONS": if request.META['REQUEST_METHOD'] == "OPTIONS":
response = render_to_json_response({'status': {'code': 200, response = render_to_json_response({'status': {'code': 200,
@ -30,8 +26,11 @@ def api(request):
for f in sorted(methods): for f in sorted(methods):
api.append({'name': f, api.append({'name': f,
'doc': actions.doc(f).replace('\n', '<br>\n')}) 'doc': actions.doc(f).replace('\n', '<br>\n')})
context = RequestContext(request, {'api': api, context = RequestContext(request, {
'sitename': settings.SITENAME}) 'api': api,
'settings': settings,
'sitename': settings.SITENAME
})
return render_to_response('api.html', context) return render_to_response('api.html', context)
if request.META.get('CONTENT_TYPE') == 'application/json': if request.META.get('CONTENT_TYPE') == 'application/json':
r = json.loads(request.body) r = json.loads(request.body)
@ -40,8 +39,11 @@ def api(request):
else: else:
action = request.POST['action'] action = request.POST['action']
data = json.loads(request.POST.get('data', '{}')) data = json.loads(request.POST.get('data', '{}'))
version = getattr(request, 'version', None)
f = actions.get(action) if version:
f = actions.versions.get(version, {}).get(action, actions.get(action))
else:
f = actions.get(action)
if f: if f:
response = f(request, data) response = f(request, data)
else: else:
@ -50,14 +52,3 @@ def api(request):
response['Access-Control-Allow-Origin'] = '*' response['Access-Control-Allow-Origin'] = '*'
return response return response
def init(request, data):
return render_to_json_response(json_response())
actions.register(init)
def error(request, data):
'''
this action is used to test api error codes, it should return a 503 error
'''
success = error_is_success
return render_to_json_response({})
actions.register(error)

View File

@ -0,0 +1,32 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
try:
from django.contrib.auth.decorators import wraps
except:
from django.utils.functional import wraps
from shortcuts import render_to_json_response
def login_required_json(function=None):
"""
Decorator for views that checks that the user is logged in
return json error if not logged in.
"""
def _wrapped_view(request, *args, **kwargs):
if request.user.is_authenticated():
return function(request, *args, **kwargs)
return render_to_json_response({'status': {'code': 401, 'text': 'login required'}})
return wraps(function)(_wrapped_view)
def admin_required_json(function=None):
"""
Decorator for views that checks that the user is logged in
return json error if not logged in.
"""
def _wrapped_view(request, *args, **kwargs):
if request.user.is_authenticated() and request.user.profile.get_level() == 'admin':
return function(request, *args, **kwargs)
return render_to_json_response({'status': {'code': 403, 'text': 'permission denied'}})
return wraps(function)(_wrapped_view)

99
oxdata/oxdjango/fields.py Normal file
View File

@ -0,0 +1,99 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import time
import datetime
import copy
from django.db import models
from django.utils import datetime_safe
from six import string_types
from ox.utils import json
def to_json(python_object):
if isinstance(python_object, datetime.datetime):
if python_object.year < 1900:
tt = python_object.timetuple()
value = '%d-%02d-%02dT%02d:%02d%02dZ' % tuple(list(tt)[:6])
else:
value = python_object.strftime('%Y-%m-%dT%H:%M:%SZ')
return {'__class__': 'datetime.datetime',
'__value__': value}
if isinstance(python_object, datetime_safe.datetime):
return {'__class__': 'datetime.datetime',
'__value__': python_object.strftime('%Y-%m-%dT%H:%M:%SZ')}
if isinstance(python_object, time.struct_time):
return {'__class__': 'time.asctime',
'__value__': time.asctime(python_object)}
try:
if isinstance(python_object, bytes):
return {'__class__': 'bytes',
'__value__': list(python_object)}
except:
pass
raise TypeError(repr(python_object) + ' is not JSON serializable')
def from_json(json_object):
if '__class__' in json_object:
if json_object['__class__'] == 'bytes':
return bytes(json_object['__value__'])
if json_object['__class__'] == 'datetime_safe.datetime' \
or json_object['__class__'] == 'datetime.datetime':
return datetime_safe.datetime.strptime(json_object['__value__'], '%Y-%m-%dT%H:%M:%SZ')
if json_object['__class__'] == 'time.asctime':
return time.strptime(json_object['__value__'])
return json_object
class DictField(models.TextField):
_type = dict
def loads(self, value):
return json.loads(value, object_hook=from_json)
def dumps(self, obj):
return json.dumps(obj, default=to_json, ensure_ascii=False)
def from_db_value(self, value, expression, connection, context):
if value is None:
return value
if isinstance(value, self._type):
return value
try:
value = self.loads(value)
except:
raise Exception('failed to parse value: %s' % value)
if value is not None:
assert isinstance(value, self._type)
return value
def get_prep_value(self, value):
if isinstance(value, self._type):
value = self.dumps(value)
if value is not None:
assert isinstance(value, string_types)
value = models.TextField.get_prep_value(self, value)
return value
def get_default(self):
if self.has_default():
if callable(self.default):
return self.default()
return copy.deepcopy(self.default)
return super(DictField, self).get_default()
class TupleField(DictField):
_type = (tuple, list)
def loads(self, value):
value = DictField.loads(self, value)
if isinstance(value, list):
value = tuple(value)
return value
try:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^oxdjango\.fields\.DictField"])
add_introspection_rules([], ["^oxdjango\.fields\.TupleField"])
except:
pass

58
oxdata/oxdjango/http.py Normal file
View File

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import os
import mimetypes
from datetime import datetime, timedelta
from six.moves.urllib.parse import quote
from django.http import HttpResponse, Http404
from django.conf import settings
def HttpFileResponse(path, content_type=None, filename=None):
if not os.path.exists(path):
raise Http404
if not content_type:
content_type = mimetypes.guess_type(path)[0]
if not content_type:
content_type = 'application/octet-stream'
if getattr(settings, 'XACCELREDIRECT', False):
response = HttpResponse()
response['Content-Length'] = os.stat(path).st_size
for PREFIX in ('STATIC', 'MEDIA'):
root = getattr(settings, PREFIX+'_ROOT', '')
url = getattr(settings, PREFIX+'_URL', '')
if root and path.startswith(root):
path = url + path[len(root)+1:]
if not isinstance(path, bytes):
path = path.encode('utf-8')
response['X-Accel-Redirect'] = path
if content_type:
response['Content-Type'] = content_type
elif getattr(settings, 'XSENDFILE', False):
response = HttpResponse()
if not isinstance(path, bytes):
path = path.encode('utf-8')
response['X-Sendfile'] = path
if content_type:
response['Content-Type'] = content_type
response['Content-Length'] = os.stat(path).st_size
else:
response = HttpResponse(open(path), content_type=content_type)
if filename:
if not isinstance(filename, bytes):
filename = filename.encode('utf-8')
response['Content-Disposition'] = "attachment; filename*=UTF=8''%s" % quote(filename)
response['Expires'] = datetime.strftime(datetime.utcnow() + timedelta(days=1), "%a, %d-%b-%Y %H:%M:%S GMT")
def allow_access():
for key in ('X-Accel-Redirect', 'X-Sendfile'):
if key in response:
del response[key]
response['Access-Control-Allow-Origin'] = '*'
response.allow_access = allow_access
return response

View File

@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from .shortcuts import HttpErrorJson, render_to_json_response
class ExceptionMiddleware(object):
def process_exception(self, request, exception):
if isinstance(exception, HttpErrorJson):
return render_to_json_response(exception.response)
return None
class ChromeFrameMiddleware(object):
def process_response(self, request, response):
response['X-UA-Compatible'] = 'chrome=1'
return response

58
oxdata/oxdjango/query.py Normal file
View File

@ -0,0 +1,58 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.db.models.sql import Query
from django.db.models.sql.compiler import SQLCompiler
from django.db import connections
import django.db.models.query
'''
models.py:
-----------------------------------
from oxdjango.query import QuerySet
class Manager(models.Manager):
def get_query_set(self):
return QuerySet(self.model)
class Model(models.Model):
...
objects = Manager()
'''
class NullLastSQLCompiler(SQLCompiler):
def get_order_by(self):
result = super(NullLastSQLCompiler, self).get_order_by()
if self.query.nulls_last and result \
and self.connection.vendor == 'postgresql':
return [(expr, (sql + ' NULLS LAST', params, is_ref))
for (expr, (sql, params, is_ref)) in result]
return result
class NullsLastQuery(Query):
nulls_last = False
def clone(self, *args, **kwargs):
obj = super(NullsLastQuery, self).clone(*args, **kwargs)
obj.nulls_last = self.nulls_last
return obj
def get_compiler(self, using=None, connection=None):
if using is None and connection is None:
raise ValueError("Need either using or connection")
if using:
connection = connections[using]
return NullLastSQLCompiler(self, connection, using)
class QuerySet(django.db.models.query.QuerySet):
def __init__(self, model=None, query=None, using=None, **kwargs):
super(QuerySet, self).__init__(model=model, query=query, using=None, **kwargs)
self.query = query or NullsLastQuery(self.model)
def order_by(self, *args, **kwargs):
nulls_last = kwargs.pop('nulls_last', False)
obj = super(QuerySet, self).order_by(*args, **kwargs)
obj.query.nulls_last = nulls_last
return obj

View File

@ -0,0 +1,49 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import print_function
import datetime
from django.utils import datetime_safe
from django.http import HttpResponse, Http404
import json
from django.conf import settings
class HttpErrorJson(Http404):
def __init__(self, response):
self.response = response
def json_response(data=None, status=200, text='ok'):
if not data:
data = {}
return {'status': {'code': status, 'text': text}, 'data': data}
def _to_json(python_object):
if isinstance(python_object, datetime.datetime):
if python_object.year < 1900:
tt = python_object.timetuple()
return '%d-%02d-%02dT%02d:%02d%02dZ' % tuple(list(tt)[:6])
return python_object.strftime('%Y-%m-%dT%H:%M:%SZ')
if isinstance(python_object, datetime_safe.datetime):
return python_object.strftime('%Y-%m-%dT%H:%M:%SZ')
raise TypeError(u'%s %s is not JSON serializable' % (repr(python_object), type(python_object)))
def render_to_json_response(dictionary, content_type="text/json", status=200):
indent=None
if settings.DEBUG:
content_type = "text/javascript"
indent = 2
if getattr(settings, 'JSON_DEBUG', False):
print(json.dumps(dictionary, indent=2, default=_to_json, ensure_ascii=False).encode('utf-8'))
return HttpResponse(json.dumps(dictionary, indent=indent, default=_to_json,
ensure_ascii=False).encode('utf-8'), content_type=content_type, status=status)
def get_object_or_404_json(klass, *args, **kwargs):
from django.shortcuts import _get_queryset
queryset = _get_queryset(klass)
try:
return queryset.get(*args, **kwargs)
except queryset.model.DoesNotExist:
response = {'status': {'code': 404,
'text': '%s not found' % queryset.model._meta.object_name}}
raise HttpErrorJson(response)

47
oxdata/oxdjango/utils.py Normal file
View File

@ -0,0 +1,47 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.http import HttpResponse,Http404
from django.core.servers.basehttp import FileWrapper
from django.conf import settings
import mimetypes
import os
def basic_sendfile(fname,download_name=None):
if not os.path.exists(fname):
raise Http404
wrapper = FileWrapper(open(fname,"r"))
content_type = mimetypes.guess_type(fname)[0]
response = HttpResponse(wrapper, content_type=content_type)
response['Content-Length'] = os.path.getsize(fname)
if download_name:
response['Content-Disposition'] = "attachment; filename=%s"%download_name
return response
def x_sendfile(fname,download_name=None):
if not os.path.exists(fname):
raise Http404
content_type = mimetypes.guess_type(fname)[0]
response = HttpResponse('', content_type=content_type)
response['Content-Length'] = os.path.getsize(fname)
response['X-Sendfile'] = fname
if download_name:
response['Content-Disposition'] = "attachment; filename=%s"%download_name
return response
try:
__sendfile = getattr(settings,'SENDFILE',False) == 'x_sendfile'
except:
__sendfile = False
if __sendfile == 'x_sendfile':
sendfile = x_sendfile
else:
sendfile = basic_sendfile

View File

@ -1,90 +1,38 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# Generated by Django 1.9.4 on 2016-03-06 10:11
from __future__ import unicode_literals
from south.db import db from django.db import migrations, models
from django.db import models import django.db.models.deletion
from oxdata.poster.models import * import poster.models
class Migration:
class Migration(migrations.Migration):
def forwards(self, orm):
initial = True
# Adding model 'PosterCache'
db.create_table('poster_postercache', ( dependencies = [
('id', orm['poster.PosterCache:id']), ('lookup', '0001_initial'),
('created', orm['poster.PosterCache:created']), ]
('modified', orm['poster.PosterCache:modified']),
('movie_id', orm['poster.PosterCache:movie_id']), operations = [
('url', orm['poster.PosterCache:url']), migrations.CreateModel(
('site', orm['poster.PosterCache:site']), name='PosterCache',
('site_id', orm['poster.PosterCache:site_id']), fields=[
('image', orm['poster.PosterCache:image']), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('failed', orm['poster.PosterCache:failed']), ('created', models.DateTimeField(auto_now_add=True)),
)) ('modified', models.DateTimeField(auto_now=True)),
db.send_create_signal('poster', ['PosterCache']) ('url', models.CharField(max_length=1024)),
('site', models.CharField(max_length=255)),
# Adding model 'Poster' ('site_id', models.CharField(max_length=1024)),
db.create_table('poster_poster', ( ('image', models.ImageField(max_length=255, upload_to=poster.models.postercache_path)),
('id', orm['poster.Poster:id']), ('status', models.CharField(default=b'200', max_length=1024)),
('created', orm['poster.Poster:created']), ('failed', models.BooleanField(default=False)),
('modified', orm['poster.Poster:modified']), ('movie_id', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='postercache', to='lookup.MovieId')),
('movie_id', orm['poster.Poster:movie_id']), ],
('poster', orm['poster.Poster:poster']), ),
('upload', orm['poster.Poster:upload']), migrations.AlterUniqueTogether(
('oxdb', orm['poster.Poster:oxdb']), name='postercache',
)) unique_together=set([('movie_id', 'url')]),
db.send_create_signal('poster', ['Poster']) ),
]
def backwards(self, orm):
# Deleting model 'PosterCache'
db.delete_table('poster_postercache')
# Deleting model 'Poster'
db.delete_table('poster_poster')
models = {
'lookup.movieid': {
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
},
'poster.poster': {
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'poster'", 'to': "orm['lookup.MovieId']"}),
'oxdb': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'poster': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['poster.PosterCache']", 'blank': 'True'}),
'upload': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'})
},
'poster.postercache': {
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postercache'", 'to': "orm['lookup.MovieId']"}),
'site': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'site_id': ('django.db.models.fields.CharField', [], {'max_length': '42'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['poster']

View File

@ -1,92 +0,0 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding field 'PosterCache.status'
db.add_column('poster_postercache', 'status', self.gf('django.db.models.fields.CharField')(default='200', max_length=1024), keep_default=False)
# Deleting field 'poster.upload'
db.delete_column('poster_poster', 'upload')
# Deleting field 'poster.oxdb'
db.delete_column('poster_poster', 'oxdb')
# Renaming column for 'Poster.poster' to match new field type.
db.rename_column('poster_poster', 'poster_id', 'poster')
# Changing field 'Poster.poster'
db.add_column('poster_poster', 'poster', self.gf('django.db.models.fields.files.ImageField')(max_length=255))
# Removing index on 'poster', fields ['poster']
db.delete_index('poster_poster', ['poster_id'])
def backwards(self, orm):
# Deleting field 'PosterCache.status'
db.delete_column('poster_postercache', 'status')
# Adding field 'poster.upload'
db.add_column('poster_poster', 'upload', self.gf('django.db.models.fields.files.ImageField')(default=None, max_length=255), keep_default=False)
# Adding field 'poster.oxdb'
db.add_column('poster_poster', 'oxdb', self.gf('django.db.models.fields.files.ImageField')(default=None, max_length=255), keep_default=False)
# Renaming column for 'Poster.poster' to match new field type.
db.rename_column('poster_poster', 'poster', 'poster_id')
# Changing field 'Poster.poster'
db.alter_column('poster_poster', 'poster_id', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['poster.PosterCache'], blank=True))
# Adding index on 'poster', fields ['poster']
db.create_index('poster_poster', ['poster_id'])
models = {
'lookup.movieid': {
'Meta': {'object_name': 'MovieId'},
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
},
'poster.poster': {
'Meta': {'object_name': 'Poster'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'poster'", 'to': "orm['lookup.MovieId']"}),
'poster': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'})
},
'poster.postercache': {
'Meta': {'object_name': 'PosterCache'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postercache'", 'to': "orm['lookup.MovieId']"}),
'site': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'site_id': ('django.db.models.fields.CharField', [], {'max_length': '42'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'200'", 'max_length': '1024'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['poster']

View File

@ -1,64 +0,0 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding unique constraint on 'PosterCache', fields ['url']
db.create_unique('poster_postercache', ['url'])
def backwards(self, orm):
# Removing unique constraint on 'PosterCache', fields ['url']
db.delete_unique('poster_postercache', ['url'])
models = {
'lookup.movieid': {
'Meta': {'object_name': 'MovieId'},
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
},
'poster.poster': {
'Meta': {'object_name': 'Poster'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'poster'", 'to': "orm['lookup.MovieId']"}),
'poster': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'})
},
'poster.postercache': {
'Meta': {'object_name': 'PosterCache'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postercache'", 'to': "orm['lookup.MovieId']"}),
'site': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'site_id': ('django.db.models.fields.CharField', [], {'max_length': '42'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'200'", 'max_length': '1024'}),
'url': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '1024'})
}
}
complete_apps = ['poster']

View File

@ -1,70 +0,0 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Removing unique constraint on 'PosterCache', fields ['url']
db.delete_unique('poster_postercache', ['url'])
# Adding unique constraint on 'PosterCache', fields ['url', 'movie_id']
db.create_unique('poster_postercache', ['url', 'movie_id_id'])
def backwards(self, orm):
# Adding unique constraint on 'PosterCache', fields ['url']
db.create_unique('poster_postercache', ['url'])
# Removing unique constraint on 'PosterCache', fields ['url', 'movie_id']
db.delete_unique('poster_postercache', ['url', 'movie_id_id'])
models = {
'lookup.movieid': {
'Meta': {'object_name': 'MovieId'},
'amg_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'criterion_id': ('django.db.models.fields.IntegerField', [], {'default': 'None', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'director': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'episode': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'episode_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'imdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '7', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'impawards_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'oxdb_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '42', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'season': ('django.db.models.fields.IntegerField', [], {'default': '-1'}),
'series_title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'title': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '1000', 'blank': 'True'}),
'wikipedia_id': ('django.db.models.fields.CharField', [], {'default': 'None', 'max_length': '255', 'unique': 'True', 'null': 'True', 'blank': 'True'}),
'year': ('django.db.models.fields.CharField', [], {'default': "''", 'max_length': '4', 'blank': 'True'})
},
'poster.poster': {
'Meta': {'object_name': 'Poster'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'poster'", 'to': "orm['lookup.MovieId']"}),
'poster': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'})
},
'poster.postercache': {
'Meta': {'unique_together': "(('movie_id', 'url'),)", 'object_name': 'PosterCache'},
'created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'failed': ('django.db.models.fields.BooleanField', [], {'default': 'False', 'blank': 'True'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'image': ('django.db.models.fields.files.ImageField', [], {'max_length': '255'}),
'modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
'movie_id': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'postercache'", 'to': "orm['lookup.MovieId']"}),
'site': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'site_id': ('django.db.models.fields.CharField', [], {'max_length': '42'}),
'status': ('django.db.models.fields.CharField', [], {'default': "'200'", 'max_length': '1024'}),
'url': ('django.db.models.fields.CharField', [], {'max_length': '1024'})
}
}
complete_apps = ['poster']

View File

@ -7,11 +7,7 @@ import hashlib
import socket import socket
import urllib2 import urllib2
from django.conf import settings
from django.db import models from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User
from django.core.files.base import ContentFile
import ox import ox
import ox.web.criterion import ox.web.criterion
@ -21,7 +17,7 @@ import ox.web.impawards
import ox.web.apple import ox.web.apple
import ox.web.piratecinema import ox.web.piratecinema
from oxdata.lookup.models import MovieId from lookup.models import MovieId
def getPosters(movie_id, url_prefix='', limit=lambda x, y: 0.3 < x/y < 1): def getPosters(movie_id, url_prefix='', limit=lambda x, y: 0.3 < x/y < 1):
if not movie_id: if not movie_id:
@ -55,6 +51,9 @@ def poster_path(url, filename):
name = "%s.%s" % (h, ext) name = "%s.%s" % (h, ext)
return os.path.join('posters', h[:2], h[2:4], h[4:6], name) return os.path.join('posters', h[:2], h[2:4], h[4:6], name)
def postercache_path(i, f):
return poster_path(i.url.encode('utf-8'), f)
class PosterCache(models.Model): class PosterCache(models.Model):
class Meta: class Meta:
unique_together = ("movie_id", "url") unique_together = ("movie_id", "url")
@ -66,7 +65,7 @@ class PosterCache(models.Model):
url = models.CharField(max_length=1024) url = models.CharField(max_length=1024)
site = models.CharField(max_length=255) site = models.CharField(max_length=255)
site_id = models.CharField(max_length=1024) site_id = models.CharField(max_length=1024)
image = models.ImageField(max_length=255, upload_to=lambda i, f: poster_path(i.url.encode('utf-8'), f)) image = models.ImageField(max_length=255, upload_to=postercache_path)
status = models.CharField(max_length=1024, default='200') status = models.CharField(max_length=1024, default='200')
failed = models.BooleanField(default=False) failed = models.BooleanField(default=False)

View File

@ -1,6 +1,8 @@
from django.conf.urls.defaults import * from django.conf.urls import url
urlpatterns = patterns('oxdata.poster.views', import views
(r'^$', 'poster'),
)
urlpatterns = [
url(r'^$', views.poster),
]

View File

@ -1,19 +1,12 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
import os.path from oxdjango.shortcuts import render_to_json_response
from django.db import models
from django.db.models import Q
from django.contrib.auth.models import User
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404
from django.template import RequestContext
from ox.django.shortcuts import render_to_json_response from lookup.views import get_movie_id
from oxdata.lookup.models import MovieId
from oxdata.lookup.views import get_movie_id
import models import models
def poster(request): def poster(request):
movie_id = get_movie_id(request) movie_id = get_movie_id(request)
json = models.getPosters(movie_id, request.build_absolute_uri('/')) json = models.getPosters(movie_id, request.build_absolute_uri('/'))

View File

@ -2,11 +2,13 @@
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
# Django settings for oxdata project. # Django settings for oxdata project.
import os import os
from os.path import join from os.path import join, normpath, dirname
import djcelery
djcelery.setup_loader()
SITENAME = 'oxdata' SITENAME = 'oxdata'
PROJECT_ROOT = os.path.normpath(os.path.dirname(__file__)) BASE_DIR = PROJECT_ROOT = normpath(dirname(__file__))
DEBUG = False DEBUG = False
TEMPLATE_DEBUG = DEBUG TEMPLATE_DEBUG = DEBUG
@ -30,7 +32,7 @@ DATABASES = {
# although not all choices may be available on all operating systems. # although not all choices may be available on all operating systems.
# If running in a Windows environment this must be set to the same as your # If running in a Windows environment this must be set to the same as your
# system time zone. # system time zone.
TIME_ZONE = 'Europe/Berlin' TIME_ZONE = 'UTC'
# Language code for this installation. All choices can be found here: # Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html # http://www.i18nguy.com/unicode/language-identifiers.html
@ -58,6 +60,23 @@ STATIC_ROOT = join(PROJECT_ROOT, 'static')
DATA_ROOT = join(PROJECT_ROOT, 'data') DATA_ROOT = join(PROJECT_ROOT, 'data')
CACHE_ROOT = join(PROJECT_ROOT, 'cache') CACHE_ROOT = join(PROJECT_ROOT, 'cache')
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',
)
os.environ['oxCACHE'] = 'fs:' + CACHE_ROOT os.environ['oxCACHE'] = 'fs:' + CACHE_ROOT
@ -71,38 +90,45 @@ MEDIA_URL = '/media/'
# Examples: "http://foo.com/media/", "/media/". # Examples: "http://foo.com/media/", "/media/".
ADMIN_MEDIA_PREFIX = '/admin/media/' ADMIN_MEDIA_PREFIX = '/admin/media/'
# List of callables that know how to import templates from various sources. TEMPLATES = [
TEMPLATE_LOADERS = ( {
'django.template.loaders.filesystem.Loader', 'BACKEND': 'django.template.backends.django.DjangoTemplates',
'django.template.loaders.app_directories.Loader', 'DIRS': [
'django.template.loaders.eggs.Loader', join(PROJECT_ROOT, 'templates'),
) ],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
MIDDLEWARE_CLASSES = ( MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware', 'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
) )
ROOT_URLCONF = 'oxdata.urls' ROOT_URLCONF = 'urls'
TEMPLATE_DIRS = (
join(PROJECT_ROOT, 'templates'),
)
INSTALLED_APPS = ( INSTALLED_APPS = (
'django.contrib.auth', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.contenttypes',
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.sites', 'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
'django.contrib.admin', 'django.contrib.admin',
'django.contrib.humanize', 'django.contrib.humanize',
'south',
'django_extensions', 'django_extensions',
'djcelery', 'djcelery',
'api',
'lookup', 'lookup',
'movie', 'movie',
'poster', 'poster',
@ -112,12 +138,12 @@ INSTALLED_APPS = (
LOGIN_REDIRECT_URL='/' LOGIN_REDIRECT_URL='/'
CELERY_RESULT_BACKEND = "database" CELERY_RESULT_BACKEND = 'database'
BROKER_HOST = "127.0.0.1" CELERY_TASK_SERIALIZER = 'json'
BROKER_PORT = 5672 CELERY_RESULT_SERIALIZER = 'json'
BROKER_USER = "oxdata" CELERY_ACCEPT_CONTENT = ['json']
BROKER_PASSWORD = "ox"
BROKER_VHOST = "/oxdata" BROKER_URL = 'amqp://oxdata:ox@localhost:5672//odata'
#Movie related settings #Movie related settings
REVIEW_WHITELIST = { REVIEW_WHITELIST = {

File diff suppressed because one or more lines are too long

View File

@ -1,157 +0,0 @@
/***
Pandora API
***/
Ox.load('UI', {
hideScreen: false,
showScreen: true,
theme: 'classic'
}, function() {
var app = new Ox.App({
apiURL: '/api/',
}).bindEvent('load', function(data) {
app.default_info = '<div class="OxSelectable"><h2>Pan.do/ra API Overview</h2>use this api in the browser with <a href="/static/oxjs/demos/doc2/index.html#Ox.App">Ox.app</a> or use <a href="http://code.0x2620.org/pandora_client">pandora_client</a> it in python. Further description of the api can be found <a href="https://wiki.0x2620.org/wiki/pandora/API">on the wiki</a></div>';
app.$body = $('body');
app.$document = $(document);
app.$window = $(window);
//app.$body.html('');
Ox.UI.hideLoadingScreen();
app.$ui = {};
app.$ui.actionList = constructList();
app.$ui.actionInfo = Ox.Container().css({padding: '16px'}).html(app.default_info);
app.api.api({docs: true, code: true}, function(results) {
app.actions = results.data.actions;
if(document.location.hash) {
app.$ui.actionList.triggerEvent('select', {ids: document.location.hash.substring(1).split(',')});
}
});
var $left = new Ox.SplitPanel({
elements: [
{
element: new Ox.Element().append(new Ox.Element()
.html('API').css({
'padding': '4px',
})).css({
'background-color': '#ddd',
'font-weight': 'bold',
}),
size: 24
},
{
element: app.$ui.actionList
}
],
orientation: 'vertical'
});
var $main = new Ox.SplitPanel({
elements: [
{
element: $left,
size: 160
},
{
element: app.$ui.actionInfo,
}
],
orientation: 'horizontal'
});
$main.appendTo(app.$body);
});
function constructList() {
return new Ox.TextList({
columns: [
{
align: "left",
id: "name",
operator: "+",
title: "Name",
unique: true,
visible: true,
width: 140
},
],
columnsMovable: false,
columnsRemovable: false,
id: 'actionList',
items: function(data, callback) {
function _sort(a, b) {
if(a.name > b.name)
return 1;
else if(a.name == b.name)
return 0;
return -1;
}
if (!data.keys) {
app.api.api(function(results) {
var items = [];
Ox.forEach(results.data.actions, function(v, k) {
items.push({'name': k})
});
items.sort(_sort);
var result = {'data': {'items': items.length}};
callback(result);
});
} else {
app.api.api(function(results) {
var items = [];
Ox.forEach(results.data.actions, function(v, k) {
items.push({'name': k})
});
items.sort(_sort);
var result = {'data': {'items': items}};
callback(result);
});
}
},
scrollbarVisible: true,
sort: [
{
key: "name",
operator: "+"
}
]
}).bindEvent({
select: function(data) {
var info = $('<div>').addClass('OxSelectable'),
hash = '#';
if(data.ids.length)
data.ids.forEach(function(id) {
info.append($("<h2>").html(id));
var $doc =$('<pre>')
.html(app.actions[id].doc.replace('/\n/<br>\n/g'))
.appendTo(info);
var $code = $('<code class="python">')
.html(app.actions[id].code[1].replace('/\n/<br>\n/g'))
.hide();
var $button = new Ox.Button({
title: [
{id: "one", title: "right"},
{id: "two", title: "down"},
],
type: "image"
})
.addClass("margin")
.click(function() { $code.toggle()})
.appendTo(info)
var f = app.actions[id].code[0];
$('<span>').html(' View Source ('+f+')').appendTo(info)
$('<pre>').append($code).appendTo(info)
hash += id + ','
});
else
info.html(app.default_info);
document.location.hash = hash.substring(0, hash.length-1);
app.$ui.actionInfo.html(info);
}
});
}
});

View File

@ -0,0 +1 @@
404 not found

View File

@ -0,0 +1 @@
api

View File

@ -2,49 +2,50 @@
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
import os import os
from django.conf.urls.defaults import * from django.conf.urls import url, include
from ox.django.http import HttpFileResponse from oxdjango.http import HttpFileResponse
from django.conf import settings from django.conf import settings
import django.views.static
# Uncomment the next two lines to enable the admin: # Uncomment the next two lines to enable the admin:
from django.contrib import admin from django.contrib import admin
admin.autodiscover() admin.autodiscover()
from api import actions import oxdjango.api.urls
actions.autodiscover()
import views
import poster.urls
import lookup.urls
def serve_static_file(path, location, content_type): def serve_static_file(path, location, content_type):
return HttpFileResponse(location, content_type=content_type) return HttpFileResponse(location, content_type=content_type)
urlpatterns = patterns('',
(r'^$', 'oxdata.views.index'),
(r'^api/$', include('api.urls')),
(r'^poster/', include('oxdata.poster.urls')),
(r'^still/$', 'oxdata.poster.views.still'),
(r'^id/', include('oxdata.lookup.urls')),
(r'^get/', include('oxdata.lookup.urls')),
(r'^robots.txt$', serve_static_file, { urlpatterns = [
url(r'^$', views.index),
url(r'^api/?', include(oxdjango.api.urls)),
url(r'^poster/', include(poster.urls)),
url(r'^still/$', poster.views.still),
url(r'^id/', include(lookup.urls)),
url(r'^get/', include(lookup.urls)),
url(r'^robots.txt$', serve_static_file, {
'location': os.path.join(settings.STATIC_ROOT, 'robots.txt'), 'location': os.path.join(settings.STATIC_ROOT, 'robots.txt'),
'content_type': 'text/plain' 'content_type': 'text/plain'
}), }),
(r'^favicon.ico$', serve_static_file, { url(r'^favicon.ico$', serve_static_file, {
'location': os.path.join(settings.STATIC_ROOT, 'favicon.ico'), 'location': os.path.join(settings.STATIC_ROOT, 'favicon.ico'),
'content_type': 'image/x-icon'}), 'content_type': 'image/x-icon'}),
# Uncomment the next line to enable the admin: url(r'^admin/', include(admin.site.urls)),
(r'^admin/', include(admin.site.urls)), ]
)
if settings.DEBUG: if settings.DEBUG:
urlpatterns += patterns('', urlpatterns += [
(r'^media/(?P<path>.*)$', 'django.views.static.serve', url(r'^media/(?P<path>.*)$', django.views.static.serve,
{'document_root': settings.MEDIA_ROOT}), {'document_root': settings.MEDIA_ROOT}),
(r'^static/(?P<path>.*)$', 'django.views.static.serve', url(r'^static/(?P<path>.*)$', django.views.static.serve,
{'document_root': settings.STATIC_ROOT}), {'document_root': settings.STATIC_ROOT}),
) ]
#load local urls if present #load local urls if present
try: try:

View File

@ -1,10 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4 # vi:si:et:sw=4:sts=4:ts=4
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404 from django.shortcuts import render
from django.template import RequestContext
def index(request): def index(request):
context = RequestContext(request, {}) return render(request, 'index.html', {})
return render_to_response('index.html', context)

16
oxdata/wsgi.py Normal file
View File

@ -0,0 +1,16 @@
"""
WSGI config for fixme project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.9/howto/deployment/wsgi/
"""
import os
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
application = get_wsgi_application()

View File

@ -1,7 +1,6 @@
Django>=1.3.0,<1.4 Django==1.9.4
South celery==3.1.20
-e bzr+http://code.0x2620.org/python-ox/#egg=python-ox django-celery==3.1.17
chardet django-extensions==1.6.1
django-celery gunicorn==19.4.5
gunicorn -e git+http://git.0x2620.org/python-ox.git#egg=python-ox
-e git://github.com/bit/django-extensions.git#egg=django_extensions

View File

@ -1,28 +0,0 @@
# django.wsgi
import os
import sys
import site
project_module = 'oxdata'
root_dir = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
#using virtualenv's activate_this.py to reorder sys.path
activate_this = os.path.join(root_dir, 'bin', 'activate_this.py')
execfile(activate_this, dict(__file__=activate_this))
sys.path.append(root_dir)
sys.path.append(os.path.join(root_dir, project_module))
#reload if this django.wsgi gets touched
from oxdjango import monitor
monitor.start(interval=1.0)
monitor.track(os.path.abspath(os.path.dirname(__file__)))
os.environ['DJANGO_SETTINGS_MODULE'] = project_module + '.settings'
import django.core.handlers.wsgi
application = django.core.handlers.wsgi.WSGIHandler()