def lino_resolve_type(self): """ Called on every virtual field when all models are loaded. """ f = self.return_type if isinstance(f, six.string_types): f = self.return_type = resolve_field(f) if isinstance(f, FakeField): sortable_by = f.sortable_by self.sortable_by = sortable_by if sortable_by and isinstance(sortable_by, list): sortable_by = sortable_by[0] self.column = sortable_by if isinstance(f, models.ForeignKey): f.remote_field.model = resolve_model(f.remote_field.model) set_default_verbose_name(f) for k in VFIELD_ATTRIBS: setattr(self, k, getattr(f, k, None)) # if self.name == 'detail_pointer': # logger.info('20170905 resolve_type 1 %s on %s', # self.name, self.verbose_name) #~ removed 20120919 self.return_type.editable = self.editable # if self.name == 'detail_pointer': # logger.info('20170905 resolve_type done %s %s', # self.name, self.verbose_name) from lino.core import store store.get_atomizer(self.model, self, self.name)
def __init__(self, getter, name, fld, setter=None, **kw): self.func = getter self.name = name self.attname = name self.field = fld self.verbose_name = fld.verbose_name self.help_text = fld.help_text self.blank = fld.blank # self.null = getattr(fld, 'null', None) self.max_length = getattr(fld, 'max_length', None) self.max_digits = getattr(fld, 'max_digits', None) self.decimal_places = getattr(fld, 'decimal_places', None) self.sortable_by = [name] self.setter = setter if setter is not None: self.editable = True self.choices = getattr(fld, 'choices', None) #~ print 20120424, self.name #~ settings.SITE.register_virtual_field(self) if isinstance(fld, models.ForeignKey) or ( isinstance(fld, VirtualField) and isinstance(fld.return_type, models.ForeignKey)): self.remote_field = self.field.remote_field from lino.core import store store.get_atomizer(self.remote_field, self, name)
def __init__(self, getter, name, fld, setter=None, **kwargs): self.func = getter self.name = name self.attname = name self.field = fld self.verbose_name = fld.verbose_name self.help_text = fld.help_text self.blank = fld.blank # self.null = getattr(fld, 'null', None) self.max_length = getattr(fld, 'max_length', None) self.max_digits = getattr(fld, 'max_digits', None) self.decimal_places = getattr(fld, 'decimal_places', None) self.sortable_by = [ name ] self.setter = setter if setter is not None: self.editable = True self.choices = getattr(fld, 'choices', None) super(RemoteField, self).__init__(**kwargs) #~ print 20120424, self.name #~ settings.SITE.register_virtual_field(self) if isinstance(fld, models.ForeignKey) or (isinstance(fld, VirtualField) and isinstance(fld.return_type, models.ForeignKey)): self.remote_field = self.field.remote_field from lino.core import store store.get_atomizer(self.remote_field, self, name)
def __init__(self, func, name, fld, **kw): self.func = func self.name = name self.attname = name self.field = fld self.verbose_name = fld.verbose_name self.max_length = getattr(fld, 'max_length', None) self.max_digits = getattr(fld, 'max_digits', None) self.decimal_places = getattr(fld, 'decimal_places', None) #~ print 20120424, self.name #~ settings.SITE.register_virtual_field(self) if isinstance(fld, models.ForeignKey): self.rel = self.field.rel from lino.core import store store.get_atomizer(self.rel, self, name)
def row2text(self, fields, row, sums): """Render the given `row` into a line of text, using the given list of `fields` and collecting sums into `sums`. """ for i, fld in enumerate(fields): if fld.field is not None: sf = get_atomizer(row.__class__, fld.field, fld.field.name) if False: try: getter = sf.full_value_from_object v = getter(row, self) except Exception as e: raise Exception("20150218 %s: %s" % (sf, e)) # was used to find bug 20130422: yield "%s:\n%s" % (fld.field, e) continue else: getter = sf.full_value_from_object v = getter(row, self) if v is None: yield '' else: sums[i] += fld.value2num(v) # # In case you want the field name in error message: # try: # sums[i] += fld.value2num(v) # except Exception as e: # raise e.__class__("%s %s" % (fld.field, e)) yield fld.format_value(self, v)
def row2text(self, fields, row, sums): """Render the given `row` into a line of text, using the given list of `fields` and collecting sums into `sums`. """ # print(20160530, fields) for i, fld in enumerate(fields): if fld.field is not None: sf = get_atomizer(row.__class__, fld.field, fld.field.name) # print(20160530, fld.field.name, sf) if False: try: getter = sf.full_value_from_object v = getter(row, self) except Exception as e: raise Exception("20150218 %s: %s" % (sf, e)) # was used to find bug 20130422: yield "%s:\n%s" % (fld.field, e) continue else: getter = sf.full_value_from_object v = getter(row, self) if v is None: # if not v: yield '' else: sums[i] += fld.value2num(v) # # In case you want the field name in error message: # try: # sums[i] += fld.value2num(v) # except Exception as e: # raise e.__class__("%s %s" % (fld.field, e)) yield fld.format_value(self, v)
def lino_resolve_type(self): """ Called on every virtual field when all models are loaded. """ f = self.return_type if isinstance(f, str): try: f = self.return_type = resolve_field(f) except Exception as e: raise Exception( "Invalid return type spec {} for {} : {}".format(f, self, e)) if isinstance(f, FakeField): sortable_by = f.sortable_by self.sortable_by = sortable_by if sortable_by and isinstance(sortable_by, list): sortable_by = sortable_by[0] self.column = sortable_by if isinstance(f, models.ForeignKey): f.remote_field.model = resolve_model(f.remote_field.model) set_default_verbose_name(f) self.get_lookup = f.remote_field.get_lookup # 20200425 self.get_path_info = f.remote_field.get_path_info # 20200425 self.remote_field = f.remote_field for k in VFIELD_ATTRIBS: setattr(self, k, getattr(f, k, None)) # copy help_text if it hasn't been set by help_texts_extractor if f.help_text and not self.help_text: self.help_text = f.help_text # if self.name == 'detail_pointer': # logger.info('20170905 resolve_type 1 %s on %s', # self.name, self.verbose_name) #~ removed 20120919 self.return_type.editable = self.editable # if self.name == 'detail_pointer': # logger.info('20170905 resolve_type done %s %s', # self.name, self.verbose_name) from lino.core import store store.get_atomizer(self.model, self, self.name)
def __init__(self, getter, name, fld, setter=None, **kwargs): self.func = getter self.name = name self.attname = name # self.db_column = name # 20200423 self.field = fld # for k in ('verbose_name', 'help_text', 'blank', 'default', 'null'): # kwargs.setdefault(k, getattr(fld, k)) self.verbose_name = fld.verbose_name self.help_text = fld.help_text # self.blank = fld.blank self.blank = True self.default = None # self.null = fld.null # self.null = getattr(fld, 'null', None) self.max_length = getattr(fld, 'max_length', None) self.max_digits = getattr(fld, 'max_digits', None) self.decimal_places = getattr(fld, 'decimal_places', None) self.sortable_by = [ name ] self.setter = setter if setter is not None: self.editable = True self.choices = getattr(fld, 'choices', None) super(RemoteField, self).__init__(**kwargs) #~ print 20120424, self.name #~ settings.SITE.register_virtual_field(self) # The remote_field of a FK field has nothing to do with our RemoteField, # it is set by Django on each FK field and points to if isinstance(fld, VirtualField) and isinstance(fld.return_type, models.ForeignKey): fld.lino_resolve_type() # 20200425 fk = fld.return_type elif isinstance(fld, models.ForeignKey): fk = fld else: fk = None if fk is not None: # if not fk.remote_field: # raise Exception("20200425 {} has no remote_field".format(fk)) self.remote_field = fk.remote_field from lino.core import store store.get_atomizer(self.remote_field, self, name)
def fmt(e): s = elem_label(e) if isinstance(e, FieldElement): sf = get_atomizer(self.__class__, e.field, e.field.name) getter = sf.full_value_from_object value = getter(self, ar) # value = e.value_from_object(self, None) if value is not None: s += ": " + e.format_value(ar, value) return s
def lino_resolve_type(self): """Called on virtual fields that are defined on an Actor """ #~ logger.info("20120903 lino_resolve_type %s.%s", actor_or_model, name) #~ if self.name is not None: #~ if self.name != name: #~ raise Exception("Tried to re-use %s.%s" % (actor_or_model,name)) #~ self.name = name if isinstance(self.return_type, six.string_types): self.return_type = resolve_field(self.return_type) f = self.return_type #~ self.return_type.name = self.name if isinstance(f, models.ForeignKey): f.remote_field.model = resolve_model(f.remote_field.model) if f.verbose_name is None: #~ if f.name is None: f.verbose_name = f.remote_field.model._meta.verbose_name #~ from lino.core.kernel import set_default_verbose_name #~ set_default_verbose_name(self.return_type) if isinstance(f, FakeField): self.sortable_by = f.sortable_by # if self.name == 'detail_pointer': # logger.info('20170905 resolve_type 1 %s on %s', # self.name, self.verbose_name) #~ removed 20120919 self.return_type.editable = self.editable for k in VFIELD_ATTRIBS: setattr(self, k, getattr(self.return_type, k, None)) # if self.name == 'detail_pointer': # logger.info('20170905 resolve_type done %s %s', # self.name, self.verbose_name) from lino.core import store #~ self._lino_atomizer = store.create_field(self,self.name) store.get_atomizer(self.model, self, self.name)
def lino_resolve_type(self): """Called on virtual fields that are defined on an Actor """ # ~ logger.info("20120903 lino_resolve_type %s.%s", actor_or_model, name) # ~ if self.name is not None: # ~ if self.name != name: # ~ raise Exception("Tried to re-use %s.%s" % (actor_or_model,name)) # ~ self.name = name if isinstance(self.return_type, basestring): self.return_type = resolve_field(self.return_type) # ~ self.return_type.name = self.name if isinstance(self.return_type, models.ForeignKey): f = self.return_type if AFTER18: f.rel.model = resolve_model(f.rel.model) else: f.rel.to = resolve_model(f.rel.to) if f.verbose_name is None: # ~ if f.name is None: f.verbose_name = f.rel.model._meta.verbose_name # ~ from lino.core.kernel import set_default_verbose_name # ~ set_default_verbose_name(self.return_type) # ~ removed 20120919 self.return_type.editable = self.editable for k in """to_python choices save_form_data value_to_string verbose_name max_length rel max_digits decimal_places help_text blank""".split(): setattr(self, k, getattr(self.return_type, k, None)) # ~ logger.info('20120831 VirtualField %s on %s',name,actor_or_model) from lino.core import store # ~ self._lino_atomizer = store.create_field(self,self.name) store.get_atomizer(self.model, self, self.name)
def lino_resolve_type(self): """Called on virtual fields that are defined on an Actor """ #~ logger.info("20120903 lino_resolve_type %s.%s", actor_or_model, name) #~ if self.name is not None: #~ if self.name != name: #~ raise Exception("Tried to re-use %s.%s" % (actor_or_model,name)) #~ self.name = name if isinstance(self.return_type, six.string_types): self.return_type = resolve_field(self.return_type) #~ self.return_type.name = self.name if isinstance(self.return_type, models.ForeignKey): f = self.return_type if AFTER18: f.rel.model = resolve_model(f.rel.model) else: f.rel.to = resolve_model(f.rel.to) if f.verbose_name is None: #~ if f.name is None: f.verbose_name = f.rel.model._meta.verbose_name #~ from lino.core.kernel import set_default_verbose_name #~ set_default_verbose_name(self.return_type) #~ removed 20120919 self.return_type.editable = self.editable for k in ('''to_python choices save_form_data value_to_string verbose_name max_length rel max_digits decimal_places help_text blank'''.split()): setattr(self, k, getattr(self.return_type, k, None)) #~ logger.info('20120831 VirtualField %s on %s',name,actor_or_model) from lino.core import store #~ self._lino_atomizer = store.create_field(self,self.name) store.get_atomizer(self.model, self, self.name)
def get_data_elem(cls, name): """Return the named data element. This can be a database field, a :class:`lino.core.fields.RemoteField`, a :class:`lino.core.fields.VirtualField` or a Django-style virtual field (GenericForeignKey). """ #~ logger.info("20120202 get_data_elem %r,%r",model,name) if not name.startswith('__'): parts = name.split('__') if len(parts) > 1: # It's going to be a RemoteField # logger.warning("20151203 RemoteField %s in %s", name, cls) from lino.core import store model = cls field_chain = [] editable = False for n in parts: if model is None: raise Exception( "Invalid remote field {0} for {1}".format( name, cls)) if isinstance(model, six.string_types): # Django 1.9 no longer resolves the # rel.model of ForeignKeys on abstract # models, so we do it here. model = resolve_model(model) # logger.warning("20151203 %s", model) fld = model.get_data_elem(n) if fld is None: raise Exception( "Invalid RemoteField %s.%s (no field %s in %s)" % (full_model_name(model), name, n, full_model_name(model))) # make sure that the atomizer gets created. store.get_atomizer(model, fld, fld.name) field_chain.append(fld) if isinstance(fld, models.OneToOneRel): editable = True if getattr(fld, 'remote_field', None): model = fld.remote_field.model elif getattr(fld, 'rel', None): raise Exception("20180712") model = fld.rel.model else: model = None def getter(obj, ar=None): try: for fld in field_chain: if obj is None: return None obj = fld._lino_atomizer.full_value_from_object( obj, ar) return obj except Exception as e: # raise msg = "Error while computing {}: {} ({} in {})" raise Exception(msg.format(name, e, fld, field_chain)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return None if not editable: return fields.RemoteField(getter, name, fld) def setter(obj, value): # logger.info("20180712 %s setter() %s", name, value) # all intermediate fields are OneToOneRel target = obj try: for fld in field_chain: # print("20180712a %s" % fld) if isinstance(fld, models.OneToOneRel): reltarget = getattr(target, fld.name, None) if reltarget is None: rkw = {fld.field.name: target} # print( # "20180712 create {}({})".format( # fld.related_model, rkw)) reltarget = fld.related_model(**rkw) reltarget.full_clean() reltarget.save() setattr(target, fld.name, reltarget) target.full_clean() target.save() # print("20180712b {}.{} = {}".format( # target, fld.name, reltarget)) target = reltarget else: setattr(target, fld.name, value) target.full_clean() target.save() # print( # "20180712c setattr({},{},{}".format( # target, fld.name, value)) return True except Exception as e: raise Exception("Error while setting %s: %s" % (name, e)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return False return fields.RemoteField(getter, name, fld, setter) try: return cls._meta.get_field(name) except models.FieldDoesNotExist: pass v = get_class_attr(cls, name) if v is not None: return v for vf in cls._meta.private_fields: if vf.name == name: return vf
def make_remote_field(model, name): parts = name.split('__') if len(parts) == 1: return # It's going to be a RemoteField # logger.warning("20151203 RemoteField %s in %s", name, cls) from lino.core import store cls = model field_chain = [] editable = False for n in parts: if model is None: raise Exception( "Invalid remote field {0} for {1}".format(name, cls)) if isinstance(model, six.string_types): # Django 1.9 no longer resolves the # rel.model of ForeignKeys on abstract # models, so we do it here. model = resolve_model(model) # logger.warning("20151203 %s", model) fld = model.get_data_elem(n) if fld is None: raise Exception( "Invalid RemoteField %s.%s (no field %s in %s)" % (full_model_name(model), name, n, full_model_name(model))) # make sure that the atomizer gets created. store.get_atomizer(model, fld, fld.name) field_chain.append(fld) if isinstance(fld, models.OneToOneRel): editable = True if getattr(fld, 'remote_field', None): model = fld.remote_field.model elif getattr(fld, 'rel', None): raise Exception("20180712") model = fld.rel.model else: model = None def getter(obj, ar=None): try: for fld in field_chain: if obj is None: return None obj = fld._lino_atomizer.full_value_from_object( obj, ar) return obj except Exception as e: # raise msg = "Error while computing {}: {} ({} in {})" raise Exception(msg.format( name, e, fld, field_chain)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return None if not editable: return RemoteField(getter, name, fld) def setter(obj, value): # logger.info("20180712 %s setter() %s", name, value) # all intermediate fields are OneToOneRel target = obj try: for fld in field_chain: # print("20180712a %s" % fld) if isinstance(fld, models.OneToOneRel): reltarget = getattr(target, fld.name, None) if reltarget is None: rkw = { fld.field.name: target} # print( # "20180712 create {}({})".format( # fld.related_model, rkw)) reltarget = fld.related_model(**rkw) reltarget.full_clean() reltarget.save() setattr(target, fld.name, reltarget) target.full_clean() target.save() # print("20180712b {}.{} = {}".format( # target, fld.name, reltarget)) target = reltarget else: setattr(target, fld.name, value) target.full_clean() target.save() # print( # "20180712c setattr({},{},{}".format( # target, fld.name, value)) return True except Exception as e: raise e.__class__( "Error while setting %s: %s" % (name, e)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return False return RemoteField(getter, name, fld, setter)
def get_data_elem(cls, name): """Return the named data element. This can be a database field, a :class:`lino.core.fields.RemoteField`, a :class:`lino.core.fields.VirtualField` or a Django-style virtual field (GenericForeignKey). """ #~ logger.info("20120202 get_data_elem %r,%r",model,name) if not name.startswith('__'): parts = name.split('__') if len(parts) > 1: # It's going to be a RemoteField # logger.warning("20151203 RemoteField %s in %s", name, cls) from lino.core import store model = cls field_chain = [] for n in parts: if model is None: raise Exception( "Invalid remote field {0} for {1}".format(name, cls)) if isinstance(model, six.string_types): model = resolve_model(model) # logger.warning("20151203 %s", model) # Django 1.9 no longer resolves the # rel.model of ForeignKeys on abstract # models. # ~ 20130508 model.get_default_table().get_handle() # make sure that all atomizers of those fields get created. fld = model.get_data_elem(n) if fld is None: # raise Exception("Part %s of %s got None" % (n,model)) raise Exception( "Invalid RemoteField %s.%s (no field %s in %s)" % (full_model_name(model), name, n, full_model_name(model))) # make sure that the atomizer gets created. store.get_atomizer(model, fld, fld.name) field_chain.append(fld) if getattr(fld, 'rel', None): if AFTER18: model = fld.rel.model else: model = fld.rel.to else: model = None def func(obj, ar=None): try: for fld in field_chain: if obj is None: return obj obj = fld._lino_atomizer.full_value_from_object( obj, ar) return obj except Exception as e: raise Exception( "Error while computing %s: %s" % (name, e)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return None return fields.RemoteField(func, name, fld) try: return cls._meta.get_field(name) except models.FieldDoesNotExist: pass v = get_class_attr(cls, name) if v is not None: return v for vf in cls._meta.virtual_fields: if vf.name == name: return vf
def get_data_elem(cls, name): """Return the named data element. This can be a database field, a :class:`lino.core.fields.RemoteField`, a :class:`lino.core.fields.VirtualField` or a Django-style virtual field (GenericForeignKey). """ #~ logger.info("20120202 get_data_elem %r,%r",model,name) if not name.startswith('__'): parts = name.split('__') if len(parts) > 1: # It's going to be a RemoteField # logger.warning("20151203 RemoteField %s in %s", name, cls) from lino.core import store model = cls field_chain = [] for n in parts: if model is None: raise Exception( "Invalid remote field {0} for {1}".format(name, cls)) if isinstance(model, basestring): model = resolve_model(model) # logger.warning("20151203 %s", model) # Django 1.9 no longer resolves the # rel.model of ForeignKeys on abstract # models. # ~ 20130508 model.get_default_table().get_handle() # make sure that all atomizers of those fields get created. fld = model.get_data_elem(n) if fld is None: # raise Exception("Part %s of %s got None" % (n,model)) raise Exception( "Invalid RemoteField %s.%s (no field %s in %s)" % (full_model_name(model), name, n, full_model_name(model))) # make sure that the atomizer gets created. store.get_atomizer(model, fld, fld.name) field_chain.append(fld) if getattr(fld, 'rel', None): if AFTER18: model = fld.rel.model else: model = fld.rel.to else: model = None def func(obj, ar=None): try: for fld in field_chain: if obj is None: return obj obj = fld._lino_atomizer.full_value_from_object( obj, ar) return obj except Exception as e: raise Exception( "Error while computing %s: %s" % (name, e)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return None return fields.RemoteField(func, name, fld) try: return cls._meta.get_field(name) except models.FieldDoesNotExist: pass v = get_class_attr(cls, name) if v is not None: return v for vf in cls._meta.virtual_fields: if vf.name == name: return vf
def make_remote_field(model, name): parts = name.split('__') if len(parts) == 1: return # It's going to be a RemoteField # logger.warning("20151203 RemoteField %s in %s", name, cls) from lino.core import store cls = model field_chain = [] editable = False leaf_chooser = None for n in parts: if model is None: return # raise Exception( # "Invalid remote field {0} for {1}".format(name, cls)) if isinstance(model, str): # Django 1.9 no longer resolves the # rel.model of ForeignKeys on abstract # models, so we do it here. model = resolve_model(model) # logger.warning("20151203 %s", model) fld = model.get_data_elem(n) if fld is None: return # raise Exception( # "Invalid RemoteField %s.%s (no field %s in %s)" % # (full_model_name(model), name, n, full_model_name(model))) # make sure that the atomizer gets created. store.get_atomizer(model, fld, fld.name) if isinstance(fld, VirtualField): fld.lino_resolve_type() leaf_chooser = choosers.check_for_chooser(model, fld) field_chain.append(fld) if isinstance(fld, models.OneToOneRel): editable = True if getattr(fld, 'remote_field', None): model = fld.remote_field.model else: model = None if leaf_chooser is not None: d = choosers.get_choosers_dict(cls) d[name] = leaf_chooser def getter(obj, ar=None): try: for fld in field_chain: if obj is None: return None obj = fld._lino_atomizer.full_value_from_object( obj, ar) return obj except Exception as e: # raise msg = "Error while computing {}: {} ({} in {})" raise Exception(msg.format( name, e, fld, field_chain)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return None if not editable: rf = RemoteField(getter, name, fld) # choosers.check_for_chooser(model, rf) return rf def setter(obj, value): # logger.info("20180712 %s setter() %s", name, value) # all intermediate fields are OneToOneRel target = obj try: for fld in field_chain: # print("20180712a %s" % fld) if isinstance(fld, models.OneToOneRel): reltarget = getattr(target, fld.name, None) if reltarget is None: rkw = { fld.field.name: target} # print( # "20180712 create {}({})".format( # fld.related_model, rkw)) reltarget = fld.related_model(**rkw) reltarget.full_clean() reltarget.save() setattr(target, fld.name, reltarget) target.full_clean() target.save() # print("20180712b {}.{} = {}".format( # target, fld.name, reltarget)) target = reltarget else: setattr(target, fld.name, value) target.full_clean() target.save() # print( # "20180712c setattr({},{},{}".format( # target, fld.name, value)) return True except Exception as e: raise e.__class__( "Error while setting %s: %s" % (name, e)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return False rf = RemoteField(getter, name, fld, setter) # choosers.check_for_chooser(model, rf) return rf