split models into apps, new api interface

This commit is contained in:
j 2010-11-26 16:07:24 +01:00
commit b8e5764f3d
32 changed files with 2033 additions and 488 deletions

View file

13
pandora/place/admin.py Normal file
View file

@ -0,0 +1,13 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from django.contrib import admin
import models
class PlaceAdmin(admin.ModelAdmin):
search_fields = ['name']
admin.site.register(models.Place, PlaceAdmin)

40
pandora/place/managers.py Normal file
View file

@ -0,0 +1,40 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
import re
from ox.utils import json
from django.contrib.auth.models import User
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Q, Manager
import models
class PlaceManager(Manager):
def get_query_set(self):
return super(PlaceManager, self).get_query_set()
def find(self, q='', f="globe", sw_lat=-180.0, sw_lng=-180.0, ne_lat=180.0, ne_lng=180.0):
qs = self.get_query_set()
qs = qs.filter(Q(
Q(Q(sw_lat__gt=sw_lat)|Q(sw_lat__lt=ne_lat)|Q(sw_lng__gt=sw_lng)|Q(sw_lng__lt=ne_lng)) &
Q(Q(sw_lat__gt=sw_lat)|Q(sw_lat__lt=ne_lat)|Q(sw_lng__lt=ne_lng)|Q(ne_lng__gt=ne_lng)) &
Q(Q(ne_lat__gt=sw_lat)|Q(ne_lat__lt=ne_lat)|Q(sw_lng__gt=sw_lng)|Q(sw_lng__lt=ne_lng)) &
Q(Q(ne_lat__gt=sw_lat)|Q(ne_lat__lt=ne_lat)|Q(ne_lng__gt=sw_lng)|Q(ne_lng__lt=ne_lng))
))
if q:
qs = qs.filter(name_find__icontains, q)
return qs
'''
#only return locations that have layers of videos visible to current user
if not identity.current.anonymous:
user = identity.current.user
if not user.in_group('admin'):
query = AND(query,
id == Layer.q.locationID, Layer.q.videoID == Video.q.id,
OR(Video.q.public == True, Video.q.creatorID == user.id)
)
else:
query = AND(query,
id == Layer.q.locationID, Layer.q.videoID == Video.q.id,
Video.q.public == True)
'''

66
pandora/place/models.py Normal file
View file

@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division, with_statement
from django.db import models
from django.db.models import Q
from django.conf import settings
from ox.django import fields
import managers
class Place(models.Model):
'''
Places are named locations, they should have geographical information attached to them.
'''
name = models.CharField(max_length=200, unique=True)
name_sort = models.CharField(max_length=200)
name_find = models.TextField(default='', editable=False)
geoname = models.CharField(max_length=1024, unique=True)
geoname_reverse = models.CharField(max_length=1024, unique=True)
wikipediaId = models.CharField(max_length=1000, blank=True)
aliases = fields.TupleField(default=[])
sw_lat = models.FloatField(default=0)
sw_lng = models.FloatField(default=0)
ne_lat = models.FloatField(default=0)
ne_lng = models.FloatField(default=0)
center_lat = models.FloatField(default=0)
center_lng = models.FloatField(default=0)
area = models.FloatField(default=-1)
objects = managers.PlaceManager()
class Meta:
ordering = ('name_sort', )
def __unicode__(self):
return self.name
def json(self):
j = {}
for key in ('name', 'name_sort', 'aliases', 'geoname', 'geoname_reversed',
'sw_lat', 'sw_lng', 'ne_lat', 'ne_lng',
'center_lat', 'center_lng'):
j[key] = getattr(self, key)
def save(self, *args, **kwargs):
if not self.name_sort:
self.name_sort = self.name
self.geoname_reverse = ', '.join(reversed(self.geoname.split(', ')))
self.name_find = '|%s|'%'|'.join([self.name] + self.aliases)
#update center
self.lat_center = ox.location.center(self.lat_sw, self.lat_ne)
self.lng_center = ox.location.center(self.lng_sw, self.lng_ne)
#update area
self.area = location.area(self.lat_sw, self.lng_sw, self.lat_ne, self.lng_ne)
super(Place, self).save(*args, **kwargs)

23
pandora/place/tests.py Normal file
View file

@ -0,0 +1,23 @@
"""
This file demonstrates two different styles of tests (one doctest and one
unittest). These will both pass when you run "manage.py test".
Replace these with more appropriate tests for your application.
"""
from django.test import TestCase
class SimpleTest(TestCase):
def test_basic_addition(self):
"""
Tests that 1 + 1 always equals 2.
"""
self.failUnlessEqual(1 + 1, 2)
__test__ = {"doctest": """
Another way to test that 1 + 1 is equal to 2.
>>> 1 + 1 == 2
True
"""}

131
pandora/place/views.py Normal file
View file

@ -0,0 +1,131 @@
# -*- coding: utf-8 -*-
# vi:si:et:sw=4:sts=4:ts=4
from __future__ import division
import os.path
import re
from datetime import datetime
from urllib2 import unquote
import mimetypes
from django import forms
from django.core.paginator import Paginator
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.db.models import Q, Avg, Count, Sum
from django.http import HttpResponse, Http404
from django.shortcuts import render_to_response, get_object_or_404, get_list_or_404, redirect
from django.template import RequestContext
from django.conf import settings
from ox.utils import json
from ox.django.decorators import login_required_json
from ox.django.shortcuts import render_to_json_response, get_object_or_404_json, json_response
from ox.django.http import HttpFileResponse
import ox
import models
'''
fixme, require admin
'''
@login_required_json
def api_addPlace(request):
'''
param data
{
'place': dict
}
place contains key/value pairs with place propterties
'''
data = json.loads(request.POST['data'])
exists = False
names = [data['place']['name']] + data['place']['aliases']
for name in names:
if models.Place.objects.filter(name_find__icontains=u'|%s|'%data['name']).count() != 0:
exists = True
if not exists:
place = models.Place()
for key in data['place']:
setattr(place, key, data['place'][key])
place.save()
response = json_response(status=200, text='created')
else:
response = json_response(status=403, text='place name exists')
return render_to_json_response(response)
@login_required_json
def api_editPlace(request):
'''
param data
{
'id': placeid,
'place': dict
}
place contains key/value pairs with place propterties
'''
data = json.loads(request.POST['data'])
place = get_object_or_404_json(models.Place, pk=data['id'])
if place.editable(request.user):
conflict = False
names = [data['place']['name']] + data['place']['aliases']
for name in names:
if models.Place.objects.filter(name_find__icontains=u'|%s|'%data['name']).exclude(id=place.id).count() != 0:
conflict = True
if not conflict:
for key in data['place']:
setattr(place, key, data['place'][key])
place.save()
response = json_response(status=200, text='updated')
else:
response = json_response(status=403, text='place name/alias conflict')
else:
response = json_response(status=403, text='permission denied')
return render_to_json_response(response)
@login_required_json
def api_removePlace(request):
response = json_response(status=501, text='not implemented')
return render_to_json_response(response)
def api_findPlace(request):
'''
param data
{'query': query, 'sort': array, 'range': array, 'area': array}
query: query object, more on query syntax at
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
sort: array of key, operator dics
[
{
key: "year",
operator: "-"
},
{
key: "director",
operator: ""
}
]
range: result range, array [from, to]
area: [sw_lat, sw_lng, ne_lat, ne_lng] only return places in that square
with keys, items is list of dicts with requested properties:
return {'status': {'code': int, 'text': string},
'data': {items: array}}
Positions
param data
{'query': query, 'ids': []}
query: query object, more on query syntax at
https://wiki.0x2620.org/wiki/pandora/QuerySyntax
ids: ids of places for which positions are required
'''
data = json.loads(request.POST['data'])
response = json_response(status=200, text='ok')
response['data']['places'] = []
#FIXME: add coordinates to limit search
for p in Places.objects.find(data['query']):
response['data']['places'].append(p.json())
return render_to_json_response(response)