354 lines
9.3 KiB
Python
Executable File
354 lines
9.3 KiB
Python
Executable File
from django.db import models
|
|
import operator
|
|
from django.db.models import Q
|
|
from ox.text import smartSplit
|
|
from ox.django.fields import DictField
|
|
from django.core.paginator import Paginator, InvalidPage, EmptyPage
|
|
from django.template.loader import render_to_string
|
|
from django.contrib.contenttypes.models import ContentType
|
|
from insidepages.models import ModuleTab, ModelExtra
|
|
from os.path import exists
|
|
from sorl.thumbnail import get_thumbnail
|
|
from django.template import RequestContext
|
|
import datetime
|
|
|
|
def splitSearch(string):
|
|
ret = []
|
|
for s in smartSplit(string):
|
|
word = s.replace("'", "").replace('"', '')
|
|
ret.append(word)
|
|
return ret
|
|
|
|
#i see the point of this function, but please clean it up: refer to 'except MultipleObjectsReturned' to see why this is here.
|
|
def get_real_ctype(module_name):
|
|
for c in ContentType.objects.filter(model=module_name):
|
|
try:
|
|
if c.model_class().is_itf_model == True:
|
|
return c
|
|
except:
|
|
pass
|
|
return None
|
|
|
|
class ItfModel(models.Model):
|
|
fts_fields = []
|
|
fk_filters = []
|
|
# related_models = []
|
|
sort_fields = []
|
|
hasComments = True
|
|
title_field = "title"
|
|
is_itf_model = True
|
|
changed = models.DateTimeField(null=True, editable=False)
|
|
created = models.DateTimeField(null=True, editable=False)
|
|
|
|
def save(self, *args, **kwargs):
|
|
''' On save, update timestamps '''
|
|
if not self.id:
|
|
self.created = datetime.datetime.today()
|
|
self.changed = datetime.datetime.today()
|
|
if self.created == None:
|
|
self.created = self.changed
|
|
super(ItfModel, self).save(*args, **kwargs)
|
|
|
|
class Meta:
|
|
abstract = True
|
|
|
|
def list_dict(self):
|
|
return {}
|
|
|
|
def info_dict(self):
|
|
return self.get_dict()
|
|
|
|
def get_title(self):
|
|
return self.get(self.title_field)
|
|
|
|
def get_tab(self):
|
|
modelextra = self.get_modelextra()
|
|
tab = ModuleTab.objects.filter(model=modelextra)[0]
|
|
return tab
|
|
|
|
@classmethod
|
|
def get_add_form(cls):
|
|
try:
|
|
formStr = cls.add_form
|
|
# cls = default_tab.model_class()
|
|
app_label = cls._meta.app_label
|
|
module = __import__(app_label + ".forms")
|
|
add_form = module.forms.__getattribute__(formStr)
|
|
return add_form
|
|
except:
|
|
return None
|
|
|
|
|
|
def get_modelextra(self):
|
|
try:
|
|
ctype = ContentType.objects.get(model=self.__class__._meta.module_name)
|
|
except:#FIXME: ideally catch only MultipleObjectsReturned (figure out where to import that from :/ ) #FUCKING way ugly hack to get clashing model ctype names with django internal models working (get_real_ctypes simply checks, if there are multiple content objects with the same 'module_name', which one is_itf_model, and returns that).
|
|
ctype = get_real_ctype(self.__class__._meta.module_name)
|
|
# modelextra = ModelExtra.objects.filter(model=ctype)[0]
|
|
modelextra = ctype.modelextra_set.all()[0]
|
|
return modelextra
|
|
|
|
def get_absolute_url(self):
|
|
return "%s/?tab=%s&object_id=%d" % (self.get_module().get_absolute_url(), self.get_tab().slug, self.id)
|
|
|
|
def get_module(self):
|
|
tab = self.get_tab()
|
|
if tab:
|
|
return tab.module
|
|
else:
|
|
return None
|
|
|
|
|
|
|
|
def get_main_image(self, size="142x150"):
|
|
if hasattr(self, 'main_image'):
|
|
main_image_getter = self.main_image
|
|
if type(main_image_getter).__name__ == 'instancemethod':
|
|
imgfield = main_image_getter()
|
|
else:
|
|
imgfield = main_image_getter
|
|
else:
|
|
imgfield = self.get_modelextra().default_image #FIXME!!
|
|
|
|
if imgfield is None or imgfield.name == '':
|
|
imgfield = self.get_modelextra().default_image
|
|
|
|
if imgfield:
|
|
try:
|
|
thumb = get_thumbnail(imgfield, size, crop="center").url
|
|
except:
|
|
thumb = ''
|
|
else:
|
|
thumb = '' # Add default image for site
|
|
return {
|
|
'thumb': thumb
|
|
}
|
|
|
|
'''
|
|
def main_image(self):
|
|
return None
|
|
'''
|
|
|
|
def get_template_path(self):
|
|
kls = self.__class__
|
|
return "modules/%s/%s.html" % (kls._meta.app_label, kls._meta.module_name)
|
|
|
|
def get_dict(self):
|
|
return self.get(self._get_fields().keys())
|
|
|
|
def insidepage_dict(self, request):
|
|
context = RequestContext(request, self.info_dict())
|
|
html = render_to_string(self.get_template_path(), context)
|
|
return {
|
|
'url': self.get_absolute_url(),
|
|
'title': self.get_title(),
|
|
'main_image': self.get_main_image(),
|
|
'html': html
|
|
}
|
|
|
|
|
|
|
|
def get(self, props):
|
|
typ = type(props)
|
|
if typ == list:
|
|
ret = {}
|
|
for p in props:
|
|
ret[p] = self._get_property(p)
|
|
return ret
|
|
elif typ == str:
|
|
return self._get_property(props)
|
|
else:
|
|
return False
|
|
|
|
def _get_property(self, prop):
|
|
fields = self._get_fields()
|
|
if prop in fields.keys():
|
|
field_type = fields[prop]
|
|
if field_type in ["TextField", "CharField", "IntegerField"]:
|
|
return self.__getattribute__(prop)
|
|
elif field_type == "ImageField":
|
|
imagefield = self.__getattribute__(prop)
|
|
return imagefield.url if imagefield.name != '' else ''
|
|
elif field_type == "ForeignKey":
|
|
return self._get_fk(prop)
|
|
elif field_type == "ManyToMany":
|
|
return self._get_m2m(prop)
|
|
elif prop.lower() in self.related_models:
|
|
return self._get_related(prop)
|
|
else:
|
|
try:
|
|
val = self.__getattribute__(prop)
|
|
if type(val).__name__ == 'instancemethod' and prop in self.getters:
|
|
return val()
|
|
else:
|
|
return val
|
|
except:
|
|
return False #FIXME
|
|
|
|
def _get_fk(self, prop):
|
|
prop = prop.replace("_id", "")
|
|
return self.__getattribute__(prop).get_dict()
|
|
|
|
# def _get_related_objects(self, fk_field):
|
|
def _get_m2m(self, prop):
|
|
ret = []
|
|
for o in self.__getattribute__(prop).all():
|
|
ret.append(o.get_dict())
|
|
return ret
|
|
|
|
def _get_related(self, prop):
|
|
attr = prop.lower() + "_set"
|
|
ret = []
|
|
for o in self.__getattribute__(attr).all():
|
|
ret.append(o.get_dict())
|
|
return ret
|
|
|
|
@classmethod
|
|
def _get_fields(kls):
|
|
ret = {}
|
|
for f in kls._meta.fields:
|
|
ret[f.get_attname()] = type(f).__name__
|
|
return ret
|
|
|
|
|
|
|
|
@classmethod
|
|
def fts(kls, qset, search):
|
|
terms = splitSearch(search)
|
|
qobjects = []
|
|
for t in terms:
|
|
for f in kls.fts_fields:
|
|
qstring = f + '__icontains'
|
|
qobject = Q(**{qstring:t})
|
|
qobjects.append(qobject)
|
|
return qset.filter(reduce(operator.or_, qobjects))
|
|
|
|
'''
|
|
eg. fks = {
|
|
'somefield': [1, 5, 7],
|
|
'someotherfield': [3]
|
|
}
|
|
'''
|
|
@classmethod
|
|
def filter_by_fks(kls, qset, fks):
|
|
qobjects = []
|
|
for key in fks.keys():
|
|
field = getField(kls._meta.fields, key)
|
|
if field:
|
|
# rel_class = field.related.parent_model
|
|
for i in fks[key]:
|
|
qobject = Q(**{field.name: i})
|
|
qobjects.append(qobject)
|
|
return qset.filter(reduce(operator.or_, qobjects))
|
|
|
|
|
|
@classmethod
|
|
def get_fk_objects(kls):
|
|
ret = {}
|
|
for f in kls.fk_filters:
|
|
ret[f] = []
|
|
field = getField(kls._meta.fields, f)
|
|
rel_class = field.related.parent_model
|
|
for o in rel_class.objects.all():
|
|
ret[f].append({
|
|
'id': o.id,
|
|
'title': unicode(o)
|
|
})
|
|
return ret
|
|
|
|
|
|
@classmethod
|
|
def get_list(kls, data):
|
|
options = {
|
|
'page': 1,
|
|
'count': 20,
|
|
'search': '',
|
|
'sort': [],
|
|
'range': [0,50],
|
|
'object_id': False
|
|
}
|
|
options.update(data)
|
|
ret = []
|
|
page_no = options['page']
|
|
list_size = options['count']
|
|
try:
|
|
qset = kls.get_qset()
|
|
except:
|
|
qset = kls.objects.all()
|
|
|
|
|
|
search = options['search']
|
|
if search != '':
|
|
qset = kls.fts(qset, search)
|
|
|
|
sort = options['sort']
|
|
|
|
if sort != []:
|
|
for s in sort:
|
|
if s['operator'] == '-':
|
|
operator = '-'
|
|
else:
|
|
operator = ''
|
|
sort = operator + s['key']
|
|
qset = qset.order_by(sort)
|
|
|
|
|
|
#FIXME: object_id needs to do something more graceful, this breaks sort.
|
|
if options['object_id'] != False and options['object_id'] != '':
|
|
object_id = options['object_id']
|
|
qset = qset.exclude(pk=object_id)
|
|
try:
|
|
obj = kls.objects.get(pk=object_id)
|
|
ret.append(obj.list_dict())
|
|
except:
|
|
pass
|
|
|
|
'''
|
|
r0 = options['range'][0]
|
|
r1 = options['range'][1]
|
|
results = qset[r0:r1]
|
|
'''
|
|
paginator = Paginator(qset, list_size)
|
|
|
|
|
|
try:
|
|
results = paginator.page(page_no)
|
|
except (EmptyPage, InvalidPage):
|
|
results = paginator.page(paginator.num_pages)
|
|
|
|
for r in results.object_list:
|
|
ret.append(r.list_dict())
|
|
|
|
|
|
return {
|
|
'page_no': page_no,
|
|
'num_pages': paginator.num_pages,
|
|
'items': ret
|
|
}
|
|
|
|
@classmethod
|
|
def get_qset(kls):
|
|
'''
|
|
Override this method in your model class to define a custom queryset instead of objects.all(), for instance, to always exclude unpublished items.
|
|
'''
|
|
raise NotImplementedError
|
|
|
|
def getField(fields, name):
|
|
for f in fields:
|
|
if f.name == name:
|
|
return f
|
|
return False
|
|
|
|
|
|
|
|
def site_config():
|
|
with open(settings.SITE_CONFIG) as f:
|
|
site_config = json.load(f)
|
|
site_config['keys'] = {}
|
|
for key in site_config['itemKeys']:
|
|
site_config['keys'][key['id']] = key
|
|
site_config['_findKeys'] = {}
|
|
for key in site_config['findKeys']:
|
|
site_config['_findKeys'][key['id']] = key
|
|
return site_config
|