def _get_value(self): primitive_models_dict = MetaModel.get_primitive_models_dict() mtype = primitive_models_dict.get(self.model_id, None) if mtype: mtype = mtype.name if mtype == 'BooleanField': return bool(self.decimal_value) if mtype == 'CharField': return self.unicode_value if mtype == 'DateField': return date.fromordinal(self.decimal_value) if mtype == 'DateTimeField': epoch = datetime.utcfromtimestamp(0) delta = timedelta(seconds=int(self.decimal_value)) return epoch + delta if mtype == 'DecimalField': return self.decimal_value if mtype == 'FileField': return FieldFile(default_storage.open(self.unicode_value), FileField(), self.unicode_value) if mtype == 'IntegerField': return int(self.decimal_value) return self.__getattr__('value')
class ModelEditView(DetailView): queryset = MetaModel.get_non_primitive() template_name = 'metamodel/model_edit.html' def get_context_data(self, **kwargs): context = super(ModelEditView, self).get_context_data(**kwargs) form = MetaModelForm(instance=self.object) context['form'] = form return context def post(self, request, pk, *args, **kwargs): meta_model = self.get_object() form = MetaModelForm(request.POST, instance=meta_model) if form.is_valid(): form.save() return HttpResponseRedirect( reverse('metamodel_model_meta', kwargs={'pk': self.get_object().pk})) else: self.object = meta_model context = self.get_context_data(**kwargs) context['form'] = form return self.render_to_response(context)
def delete(self, *args, **kwargs): primitive_instance_fields = self.fields.filter( value__model__in=MetaModel.get_primitive()) for field in primitive_instance_fields: field.value.delete() return super(InstanceModel, self).delete(*args, **kwargs)
class ModelDeleteView(DetailView): queryset = MetaModel.get_non_primitive() template_name = 'metamodel/model_delete.html' def post(self, request, pk, *args, **kwargs): meta_model = self.get_object() meta_model.delete() return HttpResponseRedirect(reverse('metamodel_model_list'))
def _set_value(self, new_value): mtype = MetaModel.get_primitive_models_dict()[self.model_id].name if mtype == 'BooleanField': if not isinstance(new_value, bool): raise ValueError self.decimal_value = int(new_value) self.unicode_value = None if mtype == 'CharField': if not isinstance(new_value, str): raise ValueError self.unicode_value = str(new_value) self.decimal_value = None if mtype == 'DateField': if not isinstance(new_value, date): raise ValueError self.decimal_value = new_value.toordinal() self.unicode_value = None if mtype == 'DateTimeField': if not isinstance(new_value, datetime): raise ValueError epoch = datetime.utcfromtimestamp(0) self.decimal_value = (new_value.replace(tzinfo=None) - epoch).total_seconds() self.unicode_value = None if mtype == 'DecimalField': self.decimal_value = Decimal(new_value) self.unicode_value = None if mtype == 'FileField': if isinstance(new_value, File): self.unicode_value = new_value.name self.decimal_value = None return if not isinstance(new_value, str): raise ValueError self.unicode_value = str(new_value) self.decimal_value = None if mtype == 'IntegerField': if not isinstance(new_value, int): raise ValueError self.decimal_value = new_value self.unicode_value = None
def unicode_function(im): m = MetaModel.get_model_by_id(im.model_id).name if m == 'VideoCardMemoryQuantity': value = im.value if value % 1024 == 0: return '{} GB'.format(value / 1024) elif value > 512 and (value - 512) % 1024 == 0: return '{}.5 GB'.format((value - 512) / 1024) else: return '{} MB'.format(value)
class ModelAddInstance(DetailView): queryset = MetaModel.get_non_primitive() template_name = 'metamodel/model_add_instance.html' def is_popup(self): return bool(self.request.GET.get('popup', False)) def get_context_data(self, **kwargs): context = super(ModelAddInstance, self).get_context_data(**kwargs) context['form'] = self.object.get_form()() is_popup = self.is_popup() form_action = reverse('metamodel_model_add_instance', kwargs={'pk': self.object.pk}) if is_popup: form_action += '?popup=1' context['hide_nav'] = is_popup context['form_action'] = form_action return context def post(self, request, pk, *args, **kwargs): meta_model = self.get_object() form = meta_model.get_form()(request.POST, request.FILES) if form.is_valid(): instance_model = InstanceModel() instance_model.model = meta_model instance_model.save(initial=True) instance_model.update_fields(form.cleaned_data, request.POST, creator_id=request.user.id) if self.is_popup(): return HttpResponseRedirect( reverse('metamodel_instance_popup_redirect', kwargs={'pk': instance_model.pk})) else: messages.success( request, u'<a href={0}>{1}</a> creada correctamente'.format( reverse('metamodel_instance_detail', kwargs={'pk': instance_model.pk}), str(instance_model))) return HttpResponseRedirect( reverse('metamodel_model_detail', kwargs={'pk': meta_model.pk})) else: self.object = meta_model context = self.get_context_data(**kwargs) context['form'] = form return self.render_to_response(context)
class ModelMetaView(DetailView): queryset = MetaModel.get_non_primitive() template_name = 'metamodel/model_meta.html' def post(self, request, pk, *args, **kwargs): meta_model = self.get_object() for field in meta_model.fields.all(): if field.name in request.POST: field.ordering = int(request.POST[field.name]) field.save() return HttpResponseRedirect( reverse('metamodel_model_meta', kwargs={'pk': meta_model.pk}))
def get_or_create_with_value(cls, parent, field, value): from metamodel.models import MetaModel primitive_models_dict = MetaModel.get_primitive_models_dict() if field.multiple: raise Exception('This method is only consistent for ' 'non-multiple fields') try: instance_field = cls.objects.get(parent=parent, field=field) if value is None or value == '': instance_field.delete() return None if field.model_id in primitive_models_dict: instance_field.value.value = value instance_field.value.save() return instance_field except cls.DoesNotExist: if value is None or value == '': return instance_field = InstanceField(parent=parent, field=field) if field.model_id in primitive_models_dict: instance_value = InstanceModel(model=field.model) instance_value.value = value instance_value.save() value = instance_value instance_field.value = value instance_field.save() return instance_field
def unicode_function(im): m = MetaModel.get_model_by_id(im.model_id).name if m == 'LightTube': specs = [str(im.l_type)] if im.consumption: if im.equivalent_power: specs.append(u'{} - {}W'.format( im.consumption.quantize(0), im.equivalent_power.quantize(0))) else: specs.append(u'{}W'.format(im.consumption.quantize(0))) else: if im.equivalent_power: specs.append(u'{}W Equivalente'.format( im.equivalent_power.quantize(0))) specs.append(str(im.light_type)) specs.append(str(im.length)) name_value = im.name if name_value is None: name_value = '' result = u'{} {} {} ({})'.format(im.technology, im.brand, name_value, ' / '.join(specs)) return ' '.join(result.split()) if m == 'LightProjector': specs = [] if im.consumption: if im.equivalent_power: specs.append(u'{} - {}W'.format( im.consumption.quantize(0), im.equivalent_power.quantize(0))) else: specs.append(u'{}W'.format(im.consumption.quantize(0))) else: if im.equivalent_power: specs.append(u'{}W Equivalente'.format( im.equivalent_power.quantize(0))) specs.append(str(im.light_type)) if im.has_movement_sensor: specs.append(u'Con sensor de movimimiento') name_value = im.name if name_value is None: name_value = '' result = u'{} {} {} ({})'.format(im.technology, im.brand, name_value, ' / '.join(specs)) return ' '.join(result.split()) if m == 'Lamp': specs = [str(im.socket), im.format.short_name] if im.consumption: if im.equivalent_power: specs.append(u'{} - {}W'.format( im.consumption.quantize(0), im.equivalent_power.quantize(0))) else: specs.append(u'{}W'.format(im.consumption.quantize(0))) else: if im.equivalent_power: specs.append(u'{}W Equivalente'.format( im.equivalent_power.quantize(0))) specs.append(str(im.light_type)) name_value = im.name if name_value is None: name_value = '' result = u'{} {} {} ({})'.format(im.l_type, im.brand, name_value, ' / '.join(specs)) return ' '.join(result.split()) if m == 'MemoryCardCapacity': if im.value % 1000 == 0: return u'{} TB'.format(im.value / 1000) elif im.value > 1000 and (im.value - 500) % 1000 == 0: return u'{}.5 TB'.format((im.value - 500) / 1000) else: return u'{} GB'.format(im.value) if m == 'MemoryCard': name_value = im.name if name_value is None: name_value = '' result = u'{} {} {} {}'.format(im.brand, name_value, im.type, im.capacity) if im.rated_speed.value: result += u' {}'.format(im.rated_speed) elif im.x_speed.value: result += u' {}'.format(im.x_speed) if im.sku: result += u' ({})'.format(im.sku) return result if m == 'UsbFlashDriveCapacity': if im.value % 1000 == 0: return u'{} TB'.format(im.value / 1000) elif im.value > 1000 and (im.value - 500) % 1000 == 0: return u'{}.5 TB'.format((im.value - 500) / 1000) else: return u'{} GB'.format(im.value) if m == 'UsbFlashDrive': if im.sku: return u'{} {} {} ({})'.format(im.line, im.name, im.capacity, im.sku) else: return u'{} {} {}'.format(im.line, im.name, im.capacity)
def delete_non_used_primitives(cls): cls.objects.filter(model__in=MetaModel.get_primitive(), fields_usage__isnull=True).delete()
def __setattr__(self, name, value): if name in [ 'id', 'decimal_value', 'unicode_value', 'unicode_representation', 'model_id', 'model' ]: return super(InstanceModel, self).__setattr__(name, value) primitive_models_dict = MetaModel.get_primitive_models_dict() if name == 'value' and self.model_id in primitive_models_dict: self._set_value(value) return if name.startswith('_'): return super(InstanceModel, self).__setattr__(name, value) from metamodel.models import InstanceField try: mf = MetaField.objects.get(parent=self.model, name=name) is_primitive = mf.model_id in primitive_models_dict if not mf.nullable and not mf.multiple and not is_primitive: if value is None: raise IntegrityError('This field cannot be None') InstanceField.get_or_create_with_value(self, mf, value) if not mf.nullable and not mf.multiple and is_primitive: if value is None: raise IntegrityError('This field cannot be None') InstanceField.get_or_create_with_value(self, mf, value) if mf.multiple and not is_primitive: InstanceField.objects.filter(field=mf, parent=self).delete() for individual_value in value: new_field = InstanceField( parent=self, field=mf, ) new_field.value = individual_value new_field.save() if mf.multiple and is_primitive: existing_fields = InstanceField.objects.filter(field=mf, parent=self) for field in existing_fields: field.value.delete() for individual_value in value: im = InstanceModel(model=mf.model) im.value = individual_value im.save() new_field = InstanceField( parent=self, field=mf, ) new_field.value = im new_field.save() if mf.nullable and not mf.multiple and not is_primitive: InstanceField.get_or_create_with_value(self, mf, value) if mf.nullable and not mf.multiple and is_primitive: InstanceField.get_or_create_with_value(self, mf, value) except MetaField.DoesNotExist: return object.__setattr__(self, name, value)
def elasticsearch_document(self): """ Generates the elasticsearch document of the given InstanceModel based on its fields and unicode representation and automatically following all of its relations. """ def sanitize_value(value): serialized_value = value if type(value) == Decimal: serialized_value = float(value) if type(value) == FieldFile: serialized_value = value.name try: json.dumps(serialized_value) return serialized_value except TypeError: raise if not self: return {}, [] result = {u'id': self.id, u'unicode': str(self)} keywords = result[u'unicode'].split() meta_fields = MetaModel.get_metafields_by_model_id(self.model_id) instance_fields = self.fields.select_related() instance_values_dict = { instance_field.field: instance_field.value for instance_field in instance_fields } for meta_field in meta_fields: if meta_field.multiple: m2m_documents = [] m2m_instance_fields = instance_fields.filter( field=meta_field).select_related() if not m2m_instance_fields: continue for m2m_instance_field in m2m_instance_fields: m2m_document = m2m_instance_field.value\ .elasticsearch_document() m2m_documents.append(m2m_document[0]) keywords.extend(m2m_document[1]) keys = m2m_documents[0].keys() for key in keys: key_subresult = [d[key] for d in m2m_documents] result[meta_field.name + '_' + key] = key_subresult else: try: instance_value = instance_values_dict[meta_field] except KeyError: instance_value = None if meta_field.model.is_primitive(): value = instance_value if value: value = instance_value.value result[meta_field.name] = sanitize_value(value) elif instance_value: fk_result = instance_value.elasticsearch_document() for fk_key, fk_value in fk_result[0].items(): try: result[meta_field.name + '_' + fk_key] = \ sanitize_value(fk_value) except TypeError: pass keywords.extend(fk_result[1]) for function_path in settings.METAMODEL[ 'ADDITIONAL_ELASTICSEARCH_FIELDS_FUNCTIONS']: path_components = function_path.split('.') f_module = importlib.import_module('.'.join(path_components[:-1])) additional_es_fields_function = getattr(f_module, path_components[-1]) additional_fields = \ additional_es_fields_function(self, result) if additional_fields: result.update(additional_fields) return result, keywords
class ModelDetailView(DetailView): queryset = MetaModel.get_non_primitive() template_name = 'metamodel/model_detail.html'
class ModelListView(ListView): queryset = MetaModel.get_non_primitive() template_name = 'metamodel/model_list.html'
class MetaModelAddFieldView(DetailView): queryset = MetaModel.get_non_primitive() template_name = 'metamodel/model_add_field.html' def get(self, request, *args, **kwargs): if request.is_ajax(): model_type = request.GET['model'] nullable = request.GET['nullable'] == 'true' multiple = request.GET['multiple'] == 'true' meta_model = self.get_object() requires_default = True if nullable or multiple: requires_default = False if not meta_model.instancemodel_set.all(): requires_default = False default_choices = None if model_type: meta_model = MetaModel.objects.get(pk=model_type) if meta_model.is_primitive(): default_choices = meta_model.html_input_type() else: default_choices = [ (e.pk, str(e)) for e in meta_model.instancemodel_set.all() ] return HttpResponse(json.dumps([requires_default, default_choices])) else: return super(MetaModelAddFieldView, self).get(request, *args, **kwargs) def get_context_data(self, **kwargs): context = super(MetaModelAddFieldView, self).get_context_data(**kwargs) form = MetaModelAddFieldForm() context['form'] = form return context def post(self, request, pk, *args, **kwargs): meta_model = self.get_object() form = MetaModelAddFieldForm(data=request.POST, files=request.FILES) if form.is_valid(): meta_field = form.instance meta_field.parent = meta_model if meta_field.requires_default_value_for_saving(): if meta_field.model.name == 'FileField': default_value = request.FILES['default'].name cleaned_default = meta_field.clean_value(default_value) if hasattr(settings, 'METAMODEL'): path = os.path.join( settings.METAMODEL.get('MEDIA_PATH', ''), cleaned_default) else: path = cleaned_default cleaned_default = default_storage.save( path, request.FILES['default']) else: default_value = request.POST.get('default') cleaned_default = meta_field.clean_value(default_value) meta_field.save(default=cleaned_default) else: meta_field.save() return HttpResponseRedirect( reverse('metamodel_model_meta', kwargs={'pk': meta_model.pk})) self.object = meta_model context = self.get_context_data(**kwargs) context['form'] = form return self.render_to_response(context)
def is_model_primitive(self): primitive_models_dict = MetaModel.get_primitive_models_dict() return self.model_id in primitive_models_dict