diff --git a/backend/managers.py b/backend/managers.py new file mode 100644 index 0000000..42ae304 --- /dev/null +++ b/backend/managers.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +from django.contrib.auth.models import User +from django.core.exceptions import ObjectDoesNotExist +from django.db import models +from django.db.models import Q + + +class MovieManager(models.Manager): + def get_query_set(self): + return super(MovieManager, self).get_query_set() + + def find(self, q="", f="all", s="title", a="desc", l="all", o=0, n=100, p=None): + qs = self.get_query_set() + + if q: + if f == "all": + qs = qs.filter(title__icontains=q) + else: + field = str("find__%s__icontains"%f) + qs = qs.filter(**{field: q}) + + order_by = s + if a == "desc": + order_by = "-sort__" + order_by + qs = qs.order_by(order_by) + + return qs[o:n] + diff --git a/backend/models.py b/backend/models.py index 1c585c5..0453dd8 100644 --- a/backend/models.py +++ b/backend/models.py @@ -8,6 +8,7 @@ from django.contrib.auth.models import User import oxlib import utils +import managers class Movie(models.Model): @@ -15,9 +16,9 @@ class Movie(models.Model): modified = models.DateTimeField(auto_now=True) accessed = models.DateTimeField(null=True, blank=True) - movieId = models.CharField(max_length=128, blank=True) - imdbId = models.CharField(max_length=7, blank=True) - oxdbId = models.CharField(max_length=42, blank=True) + movieId = models.CharField(max_length=128, unique=True, blank=True) + imdbId = models.CharField(max_length=7, unique=True, blank=True) + oxdbId = models.CharField(max_length=42, unique=True, blank=True) title = models.CharField(max_length=1000) year = models.CharField(max_length=4) runtime = models.IntegerField(null=True, blank=True) @@ -43,6 +44,8 @@ class Movie(models.Model): #length = models.IntegerField(null=True, blank=True) duration = models.FloatField(null=True, blank=True) + objects = managers.MovieManager() + #FIXME: should this be a done via a manager for person? def directors(self): return self.people.filter(cast__role='directors').order_by('cast__position') @@ -134,6 +137,7 @@ class Movie(models.Model): 'season': 'season', 'episode': 'episode', 'filtered_reviews': 'reviews', + 'trivia': 'trivia', } def json(self, fields=None): movie = {} @@ -143,7 +147,7 @@ class Movie(models.Model): value = getattr(self, key) if key in ('directors', 'writers', 'filtered_reviews'): movie[pub_key] = tuple([v.json() for v in value()]) - elif key in ('countries', 'keywords', 'genres'): + elif key in ('countries', 'keywords', 'genres', 'trivia'): movie[pub_key] = tuple([v.json() for v in value.all()]) else: movie[pub_key] = value @@ -179,7 +183,7 @@ class Movie(models.Model): used to search movies, all search values are in here ''' class MovieFind(models.Model): - movie = models.ForeignKey('Movie') + movie = models.ForeignKey('Movie', related_name='find') title = models.CharField(max_length=1000) director = models.TextField(blank=True) @@ -221,7 +225,7 @@ class MovieFind(models.Model): used to sort movies, all sort values are in here ''' class MovieSort(models.Model): - movie = models.ForeignKey('Movie') + movie = models.ForeignKey('Movie', related_name='sort') title = models.CharField(max_length=1000) director = models.TextField(blank=True) @@ -313,7 +317,7 @@ class Person(models.Model): if imdbId: q = model.objects.filter(name=name, imdbId=imdbId) else: - q = model.objects.get(name=name) + q = model.objects.all().filter(name=name) if q.count() > 0: o = q[0] else: @@ -361,11 +365,14 @@ class Cast(models.Model): return (self.person.json(), self.character) class Country(models.Model): - name = models.CharField(max_length=200) + name = models.CharField(max_length=200, unique=True) movies = models.ManyToManyField(Movie, related_name='countries', through='MovieCountry') class Meta: - ordering = ('moviecountry__position', 'name', ) + #!! adding this to ordering, breaks: + # models.Country.objects.values("name").annotate(movies=Count('movies')) + #'moviecountry__position', + ordering = ('name', ) def __unicode__(self): return self.name @@ -403,7 +410,7 @@ class MovieCountry(models.Model): class Language(models.Model): - name = models.CharField(max_length=200) + name = models.CharField(max_length=200, unique=True) movies = models.ManyToManyField(Movie, related_name='language', through="MovieLanguage") class Meta: @@ -443,7 +450,7 @@ class MovieLanguage(models.Model): link = classmethod(link) class Keyword(models.Model): - name = models.CharField(max_length=200) + name = models.CharField(max_length=200, unique=True) movies = models.ManyToManyField(Movie, related_name='keywords') class Meta: @@ -459,7 +466,7 @@ class Keyword(models.Model): class Genre(models.Model): - name = models.CharField(max_length=200) + name = models.CharField(max_length=200, unique=True) movies = models.ManyToManyField(Movie, related_name='genres') class Meta: @@ -474,7 +481,7 @@ class Genre(models.Model): return self.name class Location(models.Model): - name = models.CharField(max_length=200) + name = models.CharField(max_length=200, unique=True) movies = models.ManyToManyField(Movie, related_name='locations') #fixme: geo data @@ -507,9 +514,9 @@ class MovieFile(models.Model): created = models.DateTimeField(auto_now_add=True) modified = models.DateTimeField(auto_now=True) - oshash = models.CharField(blank=True, max_length=16) - sha1hash = models.CharField(blank=True, max_length=40) - md5sum = models.CharField(blank=True, max_length=32) + oshash = models.CharField(blank=True, unique=True, max_length=16) + sha1hash = models.CharField(blank=True, unique=True, max_length=40) + md5sum = models.CharField(blank=True, unique=True, max_length=32) movie = models.ForeignKey('Movie', related_name="files") @@ -587,8 +594,37 @@ class Review(models.Model): def json(self): return (self.name(), self.url) - class ReviewWhitelist(models.Model): name = models.CharField(max_length=255, unique=True) url = models.CharField(max_length=255, unique=True) +class List(models.Model): + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + user = models.ForeignKey(User) + title = models.CharField(max_length=255, unique=True) + movies = models.ManyToManyField(Movie, related_name='lists', through='ListItem') + + def add(self, movie): + q = self.movies.filter(id=movie.id) + if q.count() == 0: + l = ListItem() + l.list = self + l.movie = movie + l.save() + + def remove(self, movie): + self.ListItem.objects.all().filter(movie=movie, list=self).delete() + + def __unicode__(self): + return u"%s (%s)" % (self.title, unicode(self.user)) + +class ListItem(models.Model): + created = models.DateTimeField(auto_now_add=True) + modified = models.DateTimeField(auto_now=True) + list = models.ForeignKey(List) + movie = models.ForeignKey(Movie) + + def __unicode__(self): + return u"%s in %s" % (unicode(self.movie), unicode(self.list)) + diff --git a/backend/urls.py b/backend/urls.py index f7491f5..4ecfaab 100644 --- a/backend/urls.py +++ b/backend/urls.py @@ -20,7 +20,8 @@ subtitles/add?oshash&language subtitles/remove?oshash&language ''' -urlpatterns = patterns('oxdata.api.views', +urlpatterns = patterns("oxdb.backend.views", + (r'^find', 'find'), (r'^files/find', 'find_files'), (r'^files/info', 'file_info'), (r'^files/add', 'add_file'), diff --git a/backend/views.py b/backend/views.py index c3da00f..019f914 100644 --- a/backend/views.py +++ b/backend/views.py @@ -1,4 +1,124 @@ -# Create your views here. +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +import os.path +from django.db import models +from django.db.models import Q, Avg, Count +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 django.core.paginator import Paginator + +from oxdb.utils.shortcuts import render_to_json_response + +import models + +''' +.length -> _sort + +/json/find?o=0&n=100&l=all&s=date&f=all&q=&a=desc&p=id,title,director,date,cast.length + { + movies=[ + { + "id": + "title": "fsdf", + "director": + }, + ] + } + +#get sort order for all ids +/json/find?o=0&n=1000&l=all&s=date&f=all&q=&a=desc&p=id + { + movies=[ + { + "id": id + }, + ] + } + +/json/find?l=all&s=date&f=all&q=&a=desc + { + movies: 1234, + files: 2345, + pixels: 1242345345, + size: 1235, + duration: 1235, + + } + +/json/find?o=0&n=100&l=all&s=[name, items]&f=all&q=&a=desc&g=country + { + groups = [ {name:"USA", movies: 123}, {name:"UK", movies: 1234} ] + } + +#find as you type: in table, by sort string + +#auto compleat in find box + +''' +def parse_query(get): + query = {} + query["o"] = 0 + query["n"] = 100 + query["q"] = "The" + query["f"] = "all" + query["s"] = "title" + query["a"] = "desc" + def parse_dict(s): + d = s.split(",") + return [i.strip() for i in d] + _dicts = ['p', ] + _ints = ['o', 'n'] + for key in ('q', 'f', 's', 'a', 'p', 'g', 'o', 'n'): + if key in get: + if key in _ints: + query[key] = int(get[key]) + elif key in _dicts: + query[key] = parse_dict(get[key]) + else: + query[key] = get[key] + print query + return query + +def find(request): + query = parse_query(request.GET) + response = {} + if "p" in query: + response['movies'] = [] + + qs = models.Movie.objects.find(**query) + p = Paginator(qs, 100) + for i in p.page_range: + page = p.page(i) + for m in page.object_list: + response['movies'].append(m.json(query['p'])) + elif "g" in query: + response['groups'] = [] + name = "name" + movies = "movies" + if query["g"] == "country": + qs = models.Country.objects.values("name").annotate(movies=Count('movies')) + if query["g"] == "genre": + qs = models.Genre.objects.values("name").annotate(movies=Count('movies')) + if query["g"] == "language": + qs = models.Language.objects.values("name").annotate(movies=Count('movies')) + if query["g"] == "director": + qs = models.Person.objects.filter(cast__role="directors").values("name").annotate(movies=Count('movies')) + if query["g"] == "year": + qs = models.Movie.objects.values('year').annotate(movies=Count('id')) + name="year" + qs = qs[query['o']:query['n']] + for i in qs: + group = {"name": i[name], "movies": i[movies]} + response['groups'].append(group) + else: + response['movies'] = models.Movie.objects.all().count() + response['files'] = models.MovieFile.objects.all().count() + r = models.MovieFile.objects.all().aggregate(Count('size'), Count('pixels'), Count('duration')) + response['pixels'] = r['pixels__count'] + response['size'] = r['size__count'] + response['duration'] = r['duration__count'] + return render_to_json_response(response) ''' GET info?oshash=a41cde31c581e11d diff --git a/settings.py b/settings.py index 8b91d81..3625d00 100644 --- a/settings.py +++ b/settings.py @@ -63,7 +63,7 @@ MIDDLEWARE_CLASSES = ( 'django.contrib.auth.middleware.AuthenticationMiddleware', ) -ROOT_URLCONF = 'oxdata.urls' +ROOT_URLCONF = 'oxdb.urls' TEMPLATE_DIRS = ( # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates". diff --git a/urls.py b/urls.py index e07f6a7..c6aa40c 100644 --- a/urls.py +++ b/urls.py @@ -6,7 +6,7 @@ from django.conf.urls.defaults import * urlpatterns = patterns('', # Example: - # (r'^oxdata/', include('oxdata.foo.urls')), + (r'^json/', include('backend.urls')), # Uncomment the admin/doc line below and add 'django.contrib.admindocs' # to INSTALLED_APPS to enable admin documentation: