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 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): if c.model_class().is_itf_model == True: return c return None class ItfModel(models.Model): fts_fields = [] fk_filters = [] # related_models = [] sort_fields = [] hasComments = True title_field = "title" is_itf_model = True 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 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): main_image = self.main_image() if main_image is not None: imgfield = main_image.image elif self.get_modelextra().default_image: imgfield = self.get_modelextra().default_image else: imgfield = None if imgfield is not None: try: thumb = get_thumbnail(imgfield, "150x142", crop="center").url except: thumb = '' else: thumb = '' 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): try: html = render_to_string(self.get_template_path(), self.info_dict()) except: html = "Template path not found at : " + self.get_template_path() 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': 12, 'search': '', 'sort': [], 'range': [0,50] } 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) ''' 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