Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
    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)
Ejemplo n.º 5
0
    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)
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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)
Ejemplo n.º 8
0
    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)
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
 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
Ejemplo n.º 12
0
    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)
Ejemplo n.º 13
0
    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)
Ejemplo n.º 14
0
    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)
Ejemplo n.º 15
0
    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
Ejemplo n.º 16
0
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)
Ejemplo n.º 17
0
    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
Ejemplo n.º 18
0
    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
Ejemplo n.º 19
0
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