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): 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 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 if 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): 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': 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