Ejemplo n.º 1
0
def watch_changes(model, ignore=[], master_key=None, **options):
    """Declare the specified model to be "observed" ("watched") for changes.
    Each change to an object comprising at least one watched field
    will lead to an entry to the `Changes` table.

    `ignore` should be a string with a space-separated list of field
    names to be ignored.
    
    All calls to watch_changes will be grouped by model.

    """
    if isinstance(ignore, basestring):
        ignore = fields.fields_list(model, ignore)
    if isinstance(master_key, basestring):
        fld = model.get_data_elem(master_key)
        if fld is None:
            raise Exception("No field %r in %s" % (master_key, model))
        master_key = fld
    if isinstance(master_key, fields.RemoteField):
        get_master = master_key.func
    elif master_key is None:
        get_master = return_self
    else:
        def get_master(obj):
            return getattr(obj, master_key.name)
    ignore = set(ignore)
    cs = model.change_watcher_spec
    if cs is not None:
        ignore |= cs.ignored_fields
    for f in model._meta.fields:
        if not f.editable:
            ignore.add(f.name)
    model.change_watcher_spec = WatcherSpec(ignore, get_master)
Ejemplo n.º 2
0
 def set_datasource(self, ds):
     self._datasource = ds
     if ds is not None:
         if isinstance(self.hidden_elements, basestring):
             self.hidden_elements = set(fields_list(
                 ds, self.hidden_elements))
         self.hidden_elements = self.hidden_elements | ds.hidden_elements
Ejemplo n.º 3
0
    def __init__(self,
                 model=None,
                 watched_fields=None,
                 created_tpl=None,
                 updated_tpl=None,
                 deleted_tpl=None,
                 master_field=None):
        """

        """
        if model:
            self.model = model
        if watched_fields:
            self.watched_fields = watched_fields
        self.model = resolve_model(self.model, strict=True)
        self.watched_fields = fields_list(self.model, self.watched_fields)
        if master_field:
            self.master_field = master_field

        for k in ('created_tpl', 'updated_tpl', 'deleted_tpl'):
            v = locals().get(k)
            if v:
                setattr(self, k, v)
            v = getattr(self, k)
            if v:
                setattr(self, k, rt.get_template(v))
Ejemplo n.º 4
0
 def set_datasource(self, ds):
     self._datasource = ds
     if ds is not None:
         if isinstance(self.hidden_elements, basestring):
             self.hidden_elements = set(fields_list(
                 ds, self.hidden_elements))
         self.hidden_elements = self.hidden_elements | ds.hidden_elements
Ejemplo n.º 5
0
def watch_changes(model, ignore=[], master_key=None, **options):
    """Declare the specified model to be "observed" ("watched") for changes.
    Each change to an object comprising at least one watched field
    will lead to an entry to the `Changes` table.

    `ignore` should be a string with a space-separated list of field
    names to be ignored.
    
    All calls to watch_changes will be grouped by model.

    """
    if isinstance(ignore, six.string_types):
        ignore = fields.fields_list(model, ignore)
    if isinstance(master_key, six.string_types):
        fld = model.get_data_elem(master_key)
        if fld is None:
            raise Exception("No field %r in %s" % (master_key, model))
        master_key = fld
    if isinstance(master_key, fields.RemoteField):
        get_master = master_key.func
    elif master_key is None:
        get_master = return_self
    else:

        def get_master(obj):
            return getattr(obj, master_key.name)

    ignore = set(ignore)
    cs = model.change_watcher_spec
    if cs is not None:
        ignore |= cs.ignored_fields
    for f in model._meta.fields:
        if not f.editable:
            ignore.add(f.name)
    model.change_watcher_spec = WatcherSpec(ignore, get_master)
Ejemplo n.º 6
0
 def on_site_startup(self, site):
     from lino.core.fields import fields_list
     self.pupil_model = site.models.resolve(self.pupil_model)
     self.teacher_model = site.models.resolve(self.teacher_model)
     # self.pupil_name_fields = set(self.pupil_name_fields.split())
     self.pupil_name_fields = fields_list(
         site.models.courses.Enrolment, self.pupil_name_fields)
     super(Plugin, self).on_site_startup(site)
Ejemplo n.º 7
0
 def set_datasource(self, ds):
     self._datasource = ds
     if ds is not None:
         if isinstance(self.hidden_elements, six.string_types):
             self.hidden_elements = set(fields_list(
                 ds, self.hidden_elements))
         self.hidden_elements |= ds.hidden_elements
         self.editable = ds.editable
Ejemplo n.º 8
0
 def set_datasource(self, ds):
     self._datasource = ds
     if ds is not None:
         if isinstance(self.hidden_elements, six.string_types):
             self.hidden_elements = set(
                 fields_list(ds, self.hidden_elements))
         self.hidden_elements = self.hidden_elements | ds.hidden_elements
         self.editable = ds.editable
Ejemplo n.º 9
0
 def on_analyze(cls, site):
     super(Bleached, cls).on_analyze(site)
     if cls.bleached_fields is None:
         return
     if isinstance(cls.bleached_fields, six.string_types):
         cls.bleached_fields = fields_list(cls, cls.bleached_fields)
     if not bleach:
         # site.logger.debug(
         #     "%s not being bleached because `bleach` is broken "
         #     "or not installed.", cls)
         raise Exception(
             "{} has bleached fields but `bleach` is not installed.".format(
                 cls))
Ejemplo n.º 10
0
 def on_analyze(cls, site):
     super(Bleached, cls).on_analyze(site)
     if cls.bleached_fields is None:
         return
     if isinstance(cls.bleached_fields, six.string_types):
         cls.bleached_fields = fields_list(cls, cls.bleached_fields)
     if not bleach:
         # site.logger.debug(
         #     "%s not being bleached because `bleach` is broken "
         #     "or not installed.", cls)
         raise Exception(
             "{} has bleached fields but `bleach` is not installed.".format(
                 cls))
Ejemplo n.º 11
0
    def __init__(self, model=None, watched_fields=None,
                 created_tpl=None, updated_tpl=None, deleted_tpl=None,
                 master_field=None):
        """

        """
        if model:
            self.model = model
        if watched_fields:
            self.watched_fields = watched_fields
        self.model = resolve_model(self.model, strict=True)
        self.watched_fields = fields_list(self.model, self.watched_fields)
        if master_field:
            self.master_field = master_field

        for k in ('created_tpl', 'updated_tpl', 'deleted_tpl'):
            v = locals().get(k)
            if v:
                setattr(self, k, v)
            v = getattr(self, k)
            if v:
                setattr(self, k, rt.get_template(v))
Ejemplo n.º 12
0
 def add_active_field(cls, names):
     if isinstance(cls.active_fields, basestring):
         cls.active_fields = frozenset(
             fields.fields_list(cls, cls.active_fields))
     cls.active_fields = cls.active_fields | fields.fields_list(cls, names)
Ejemplo n.º 13
0
    def class_init(self):

        if self.model is not None:
            model = resolve_model(self.model, self.app_label)
            if isinstance(model, UnresolvedModel):
                # if settings.SITE.is_installed(self.app_label):
                raise Exception("Invalid model {} on table {}".format(
                    self.model, self))
            self.model = model

        if isinstance(self.model, UnresolvedModel):
            self.model = None

        if self.model is not None:
            if isinstance(self.hidden_columns, six.string_types):
                self.hidden_columns = frozenset(
                    fields.fields_list(self.model, self.hidden_columns))
            self.hidden_columns |= self.model.hidden_columns

            if isinstance(self.active_fields, six.string_types):
                self.active_fields = frozenset(
                    fields.fields_list(self.model, self.active_fields))
            self.active_fields |= self.model.active_fields
            self.hidden_elements |= self.model.hidden_elements

            # self.simple_parameters |= self.model.simple_parameters

            for b in self.model.mro():
                for k, v in list(b.__dict__.items()):
                    if isinstance(v, actions.Action):
                        existing_value = self.__dict__.get(k, NOT_PROVIDED)
                        if existing_value is NOT_PROVIDED:
                            # settings.SITE.install_help_text(
                            #     v, v.__class__)
                            setattr(self, k, v)
                        else:
                            if existing_value is None:  # 20130820
                                pass
                                # logger.info("%s disables model action '%s'",self,k)
                            else:
                                if not isinstance(existing_value,
                                                  actions.Action):
                                    raise Exception(
                                        "%s cannot install model action %s "
                                        "because name is already used "
                                        "for %r" % self, k, existing_value)

            for name in ('workflow_state_field', 'workflow_owner_field'):
                if getattr(self, name) is None:
                    setattr(self, name, getattr(self.model, name))

            for name in (  # 'disabled_fields',
                    'handle_uploaded_files',
                    # 'get_row_permission',
                    # 'disable_editing',
            ):
                if getattr(self, name) is None:
                    m = getattr(self.model, name, None)
                    if m is not None:
                        # logger.debug('20120731 Install model method %s from %r to %r',name,self.model,self)
                        setattr(self, name, model2actor(m))
                        # 'dictproxy' object does not support item assignment:
                        # self.__dict__[name] = model2actor(m)

            if self.master_key:

                master_model = None
                try:
                    fk = self.model._meta.get_field(self.master_key)
                    # x = self.model._meta.get_field_by_name(self.master_key)
                    # fk, remote, direct, m2m = x
                    # assert direct
                    # assert not m2m
                    if fk.rel is not None:
                        master_model = fk.rel.model
                    elif isinstance(fk, ChoiceListField):
                        master_model = fk.choicelist.item_class
                    elif isinstance(fk, GenericForeignKey):
                        master_model = ContentType
                    else:
                        raise Exception(
                            "Unsupported master_key {0} ({1})".format(
                                fk, fk.__class__))
                except models.FieldDoesNotExist:
                    for vf in self.model._meta.virtual_fields:
                        if vf.name == self.master_key:
                            fk = vf
                            master_model = ContentType
                            break
                if master_model is None:
                    df = getattr(self.model, self.master_key, None)
                    if df is None:
                        msg = "No field '{0}' in {1}".format(
                            self.master_key, self.model)
                        raise Exception(
                            INVALID_MK.format(self.master_key, self, msg))
                    elif isinstance(df, fields.DummyField):
                        self.abstract = True
                    else:
                        msg = "Cannot handle master key {0}".format(df)
                        msg += " (20150820 virtual fields: {0})".format([
                            vf.name for vf in self.model._meta.virtual_fields
                        ])
                        raise Exception(
                            INVALID_MK.format(self.master_key, self, msg))
                        # raise Exception(
                        #     "%s : invalid master class for master_key "
                        #     "%r in %s" % (
                        #         self, self.master_key, self.model))
                else:
                    self.master = master_model
                    self.master_field = fk
                    # self.hidden_columns |= set([fk.name])

        super(Table, self).class_init()

        if self.order_by is not None:
            if not isinstance(self.order_by, (list, tuple)):
                raise Exception("%s.order_by is %r (must be a list or tuple)" %
                                (self, self.order_by))
            if False:
                # good idea, but doesn't yet work for foreign fields,
                # e.g. order_by = ['content_type__app_label']
                for fieldname in self.order_by:
                    if fieldname.startswith('-'):
                        fieldname = fieldname[1:]
                    try:
                        fk, remote, direct, m2m = self.model._meta.get_field_by_name(
                            fieldname)
                        assert direct
                        assert not m2m
                    except models.FieldDoesNotExist:
                        raise Exception("Unknown fieldname %r in %s.order_by" %
                                        (fieldname, self))
Ejemplo n.º 14
0
 def add_active_field(cls, names):
     if isinstance(cls.active_fields, six.string_types):
         cls.active_fields = frozenset(
             fields.fields_list(cls, cls.active_fields))
     cls.active_fields = cls.active_fields | fields.fields_list(cls, names)
Ejemplo n.º 15
0
    def class_init(self):

        if self.model is not None:
            self.model = resolve_model(self.model, self.app_label)

        if isinstance(self.model, UnresolvedModel):
            self.model = None

        if self.model is not None:
            if isinstance(self.hidden_columns, basestring):
                self.hidden_columns = frozenset(
                    fields.fields_list(self.model, self.hidden_columns))
            self.hidden_columns |= self.model.hidden_columns

            if isinstance(self.active_fields, basestring):
                self.active_fields = frozenset(
                    fields.fields_list(self.model, self.active_fields))
            self.active_fields |= self.model.active_fields
            self.hidden_elements |= self.model.hidden_elements

            # self.simple_parameters |= self.model.simple_parameters

            for b in self.model.mro():
                for k, v in b.__dict__.items():
                    if isinstance(v, actions.Action):
                        existing_value = self.__dict__.get(k, NOT_PROVIDED)
                        if existing_value is NOT_PROVIDED:
                            setattr(self, k, v)
                        else:
                            if existing_value is None:  # 20130820
                                pass
                                #~ logger.info("%s disables model action '%s'",self,k)
                            else:
                                if not isinstance(
                                        existing_value, actions.Action):
                                    raise Exception(
                                        "%s cannot install model action %s "
                                        "because name is already used "
                                        "for %r" % self, k, existing_value)

            for name in ('workflow_state_field', 'workflow_owner_field'):
                if getattr(self, name) is None:
                    setattr(self, name, getattr(self.model, name))

            for name in (  # 'disabled_fields',
                'handle_uploaded_files',
                #~ 'get_row_permission',
                #~ 'disable_editing',
            ):
                if getattr(self, name) is None:
                    m = getattr(self.model, name, None)
                    if m is not None:
                        #~ logger.debug('20120731 Install model method %s from %r to %r',name,self.model,self)
                        setattr(self, name, model2actor(m))
                        #~ 'dictproxy' object does not support item assignment:
                        #~ self.__dict__[name] = model2actor(m)

            if self.master_key:

                master_model = None
                try:
                    fk = self.model._meta.get_field(self.master_key)
                    # x = self.model._meta.get_field_by_name(self.master_key)
                    # fk, remote, direct, m2m = x
                    # assert direct
                    # assert not m2m
                    if fk.rel is not None:
                        master_model = fk.rel.model
                    elif isinstance(fk, ChoiceListField):
                        master_model = fk.choicelist.item_class
                    elif isinstance(fk, GenericForeignKey):
                        master_model = ContentType
                    else:
                        raise Exception("Oops: {0}".format(fk))
                except models.FieldDoesNotExist:
                    for vf in self.model._meta.virtual_fields:
                        if vf.name == self.master_key:
                            fk = vf
                            master_model = ContentType
                            break
                if master_model is None:
                    df = getattr(self.model, self.master_key, None)
                    if df is None:
                        msg = "No field '{0}' in {1}".format(
                            self.master_key, self.model)
                        raise Exception(INVALID_MK.format(
                            self.master_key, self, msg))
                    elif isinstance(df, fields.DummyField):
                        self.abstract = True
                    else:
                        msg = "Cannot handle master key {0}".format(df)
                        msg += " (20150820 virtual fields: {0})".format(
                            [vf.name for vf in
                             self.model._meta.virtual_fields])
                        raise Exception(INVALID_MK.format(
                            self.master_key, self, msg))
                        # raise Exception(
                        #     "%s : invalid master class for master_key "
                        #     "%r in %s" % (
                        #         self, self.master_key, self.model))
                else:
                    self.master = master_model
                    self.master_field = fk
                    # self.hidden_columns |= set([fk.name])

        super(Table, self).class_init()

        if self.order_by is not None:
            if not isinstance(self.order_by, (list, tuple)):
                raise Exception("%s.order_by is %r (must be a list or tuple)" %
                                (self, self.order_by))
            if False:
                # good idea, but doesn't yet work for foreign fields,
                # e.g. order_by = ['content_type__app_label']
                for fieldname in self.order_by:
                    if fieldname.startswith('-'):
                        fieldname = fieldname[1:]
                    try:
                        fk, remote, direct, m2m = self.model._meta.get_field_by_name(
                            fieldname)
                        assert direct
                        assert not m2m
                    except models.FieldDoesNotExist:
                        raise Exception("Unknown fieldname %r in %s.order_by" %
                                        (fieldname, self))
Ejemplo n.º 16
0
    def kernel_startup(kernel, self):
        """This is a part of a Lino site startup.  The Django Model
        definitions are done, now Lino analyzes them and does certain
        actions:

        - Verify that there are no more pending injects Install a
          :class:`DisableDeleteHandler
          <lino.core.ddh.DisableDeleteHandler>` for each Model into
          `_lino_ddh`.

        - Install :class:`lino.core.model.Model` attributes and
          methods into Models that don't inherit from it.

        """
        if len(sys.argv) == 0:
            process_name = 'WSGI'
        else:
            process_name = ' '.join(sys.argv)

        logger.info("Started %s (using %s) --> PID %s", process_name,
                    settings.SETTINGS_MODULE, os.getpid())

        # puts(self.welcome_text())

        def goodbye():
            logger.info("Done %s (PID %s)", process_name, os.getpid())

        atexit.register(goodbye)

        models_list = get_models(include_auto_created=True)
        # this also triggers django.db.models.loading.cache._populate()

        self.setup_model_spec(self, 'user_model')
        self.setup_model_spec(self, 'project_model')

        for app_name_model, p in self.override_modlib_models.items():
            # app_name_model is the full installed app module name +
            # the model name. It certainly contains at least one dot.
            m = '.'.join(app_name_model.split('.')[-2:])
            resolve_model(
                m,
                strict="%s plugin tries to extend unresolved model '%%s'" %
                p.__class__.__module__)

        for model in models_list:
            #~ print 20130216, model
            #~ fix_field_cache(model)

            # if hasattr(model, '_lino_ddh'):
            if '_lino_ddh' in model.__dict__:
                raise Exception("20150831 %s", model)
            model._lino_ddh = DisableDeleteHandler(model)

            Model.django2lino(model)

            if isinstance(model.hidden_columns, basestring):
                model.hidden_columns = frozenset(
                    fields.fields_list(model, model.hidden_columns))

            if isinstance(model.active_fields, basestring):
                model.active_fields = frozenset(
                    fields.fields_list(model, model.active_fields))

            if isinstance(model.allow_cascaded_delete, basestring):
                model.allow_cascaded_delete = frozenset(
                    fields.fields_list(model, model.allow_cascaded_delete))

            qsf = model.__dict__.get('quick_search_fields', None)
            # never inherit from concrete parent model.
            if qsf is None:
                fields_list = []
                for field in model._meta.fields:
                    if isinstance(field, models.CharField):
                        fields_list.append(field.name)
                model.quick_search_fields = frozenset(fields_list)
            elif isinstance(qsf, basestring):
                model.quick_search_fields = frozenset(
                    fields.fields_list(model, model.quick_search_fields))
            else:
                raise ChangedAPI(
                    "{0}.quick_search_fields must be None or a string "
                    "of space-separated field names (not {1})".format(
                        model, qsf))

            if model._meta.abstract:
                raise Exception("Tiens?")

            # self.modules.define(model._meta.app_label, model.__name__, model)

            for f in model._meta.virtual_fields:
                if isinstance(f, GenericForeignKey):
                    kernel.GFK_LIST.append(f)

        # vip_classes = (layouts.BaseLayout, fields.Dummy)
        # for a in models.get_apps():
        #     app_label = a.__name__.split('.')[-2]

        #     for k, v in a.__dict__.items():
        #         if isinstance(v, type) and issubclass(v, vip_classes):
        #             self.modules.define(app_label, k, v)

        #         if k.startswith('setup_'):
        #             self.modules.define(app_label, k, v)

        if self.user_profiles_module:
            from django.utils.importlib import import_module
            import_module(self.user_profiles_module)

        self.setup_choicelists()
        self.setup_workflows()

        for model in models_list:
            if model._meta.auto_created:
                continue  # automatic intermediate models created by
                # ManyToManyField should not disable delete
            for f, m in model._meta.get_fields_with_model():

                # Refuse nullable CharFields, but don't trigger on
                # NullableCharField (which is a subclass of CharField).

                if f.__class__ is models.CharField and f.null:
                    msg = "Nullable CharField %s in %s" % (f.name, model)
                    raise Exception(msg)
                    #~ if f.__class__ is models.CharField:
                    #~ raise Exception(msg)
                    #~ else:
                    #~ logger.info(msg)
                elif isinstance(f, models.ForeignKey):
                    # f.rel.to = resolve_model(f.rel.to, strict=True)
                    if isinstance(f.rel.to, basestring):
                        raise Exception("Could not resolve target %r of "
                                        "ForeignKey '%s' in %s "
                                        "(models are %s)" %
                                        (f.rel.to, f.name, model, models_list))
                    set_default_verbose_name(f)
                    """
                    If JobProvider is an MTI child of Company,
                    then mti.delete_child(JobProvider) must not fail on a
                    JobProvider being referred only by objects that can refer
                    to a Company as well.
                    """
                    if not hasattr(f.rel.to, '_lino_ddh'):
                        raise Exception("20150824")
                    # f.rel.to._lino_ddh.add_fk(f.model, f)
                    # m = f.model._meta.concrete_model
                    # f.rel.to._lino_ddh.add_fk(m, f)
                    f.rel.to._lino_ddh.add_fk(m or model, f)

        kernel.protect_foreignkeys(models_list)

        for p in self.installed_plugins:
            if isinstance(p, Plugin):
                p.before_analyze()

        # logger.info("20150429 Gonna send pre_analyze signal")
        pre_analyze.send(self, models_list=models_list)
        # logger.info("20150429 pre_analyze signal done")
        # MergeActions are defined in pre_analyze.
        # And MergeAction needs the info in _lino_ddh to correctly find
        # keep_volatiles

        self.setup_actions()

        for model in models_list:
            """Virtual fields declared on the model must have been attached
            before calling Model.site_setup(), e.g. because
            pcsw.Person.site_setup() declares `is_client` as imported
            field.

            """

            model.on_analyze(self)

            for k, v in class_dict_items(model):
                if isinstance(v, fields.VirtualField):
                    v.attach_to_model(model, k)

        #~ logger.info("20130817 attached model vfs")

        actors.discover()

        logger.debug("actors.initialize()")
        for a in actors.actors_list:
            a.class_init()

        dbtables.discover()
        #~ choosers.discover()
        actions.discover_choosers()

        for a in actors.actors_list:
            a.on_analyze(self)

        post_analyze.send(self, models_list=models_list)

        if False:
            logger.info("Languages: %s. %d apps, %d models, %s actors.",
                        ', '.join([li.django_code for li in self.languages]),
                        len(self.modules), len(models_list),
                        len(actors.actors_list))

        #~ logger.info(settings.INSTALLED_APPS)

        self.setup_layouts()

        self.on_each_app('site_setup')  # deprecated

        # Actor.after_site_setup() is called after the apps'
        # site_setup().  Example: pcsw.site_setup() adds a detail to
        # properties.Properties, the base class for
        # properties.PropsByGroup.  The latter would not install a
        # `detail_action` during her after_site_setup() and also would
        # never get it later.

        for a in actors.actors_list:
            a.after_site_setup(self)

        #~ self.on_site_startup()

        self.resolve_virtual_fields()
Ejemplo n.º 17
0
    def class_init(self):

        if self.model is not None:
            self.model = resolve_model(self.model, self.app_label)

        if isinstance(self.model, UnresolvedModel):
            self.model = None

        if self.model is not None:
            if isinstance(self.hidden_columns, basestring):
                self.hidden_columns = frozenset(
                    fields.fields_list(self.model, self.hidden_columns))
            self.hidden_columns |= self.model.hidden_columns

            if isinstance(self.active_fields, basestring):
                self.active_fields = frozenset(
                    fields.fields_list(self.model, self.active_fields))
            self.active_fields |= self.model.active_fields
            self.hidden_elements |= self.model.hidden_elements

            for b in self.model.mro():
                for k, v in b.__dict__.items():
                    # ~ v = self.model.__dict__.get(k,v) # 20131025 allow disabling inherited actions
                    if isinstance(v, actions.Action):
                        #~ print "20130326 %s.%s = action %s from %s" % (self,k,v,b)
                        existing_value = self.__dict__.get(k, NOT_PROVIDED)
                        if existing_value is NOT_PROVIDED:
                            setattr(self, k, v)
                        else:
                            if existing_value is None:  # 20130820
                                pass
                                #~ logger.info("%s disables model action '%s'",self,k)
                                #~ self.unbind_action(k)
                            else:
                                if not isinstance(existing_value, actions.Action):
                                    raise Exception(
                                        "%s cannot install model action %s because name is already used for %r" %
                                        self, k, existing_value)

            for name in ('workflow_state_field', 'workflow_owner_field'):
                if getattr(self, name) is None:
                    setattr(self, name, getattr(self.model, name))
                    #~ v = getattr(self.model,name,None)
                    #~ if v is not None:
                        #~ setattr(self,name,v)

            for name in (  # 'disabled_fields',
                'handle_uploaded_files',
                #~ 'get_row_permission',
                #~ 'disable_editing',
            ):
                if getattr(self, name) is None:
                    m = getattr(self.model, name, None)
                    if m is not None:
                        #~ logger.debug('20120731 Install model method %s from %r to %r',name,self.model,self)
                        setattr(self, name, model2actor(m))
                        #~ 'dictproxy' object does not support item assignment:
                        #~ self.__dict__[name] = model2actor(m)

            if self.master_key:

                master_model = None
                try:
                    x = self.model._meta.get_field_by_name(self.master_key)
                    fk, remote, direct, m2m = x
                    assert direct
                    assert not m2m
                    if fk.rel is not None:
                        master_model = fk.rel.to
                except models.FieldDoesNotExist as e:
                    for vf in self.model._meta.virtual_fields:
                        if vf.name == self.master_key:
                            fk = vf
                            master_model = ContentType
                            break
                if master_model is None:
                    df = getattr(self.model, self.master_key, None)
                    if isinstance(df, fields.DummyField):
                        self.abstract = True
                    else:
                        raise Exception(
                            "%s : no master for master_key %r in %s" % (
                                self, self.master_key, self.model))
                else:
                    self.master = master_model
                    self.master_field = fk
                    self.hidden_columns |= set([fk.name])
        #~ else:
            #~ assert self.master is None

        super(Table, self).class_init()

        if self.order_by is not None:
            if not isinstance(self.order_by, (list, tuple)):
                raise Exception("%s.order_by is %r (must be a list or tuple)" %
                                (self, self.order_by))
            if False:
                # good idea, but doesn't yet work for foreign fields,
                # e.g. order_by = ['content_type__app_label']
                for fieldname in self.order_by:
                    if fieldname.startswith('-'):
                        fieldname = fieldname[1:]
                    try:
                        fk, remote, direct, m2m = self.model._meta.get_field_by_name(
                            fieldname)
                        assert direct
                        assert not m2m
                    except models.FieldDoesNotExist, e:
                        raise Exception("Unknown fieldname %r in %s.order_by" %
                                        (fieldname, self))
Ejemplo n.º 18
0
    def class_init(self):
      
        if self.model is not None:
            self.model = resolve_model(self.model,self.app_label)
            
        if isinstance(self.model,UnresolvedModel):
            self.model = None
            
        if self.model is not None:
            if isinstance(self.hidden_columns,basestring):
                self.hidden_columns = frozenset(fields.fields_list(self.model,self.hidden_columns))
            self.hidden_columns = self.hidden_columns | self.model.hidden_columns
            self.hidden_elements = self.hidden_elements | self.model.hidden_elements
            
            #~ if self.model is not None:
              
            #~ for b in self.model.mro():
                #~ for k,v in b.__dict__.items():
                    #~ if isinstance(v,actions.Action):
                        #~ raise Exception("20130121 Must convert %s.%s to get_model_actions()" % (self.model,k))
            for b in self.model.mro():
                for k,v in b.__dict__.items():
                    #~ v = self.model.__dict__.get(k,v) # 20131025 allow disabling inherited actions
                    if isinstance(v,actions.Action):
                        #~ print "20130326 %s.%s = action %s from %s" % (self,k,v,b)
                        existing_value = self.__dict__.get(k,NOT_PROVIDED) 
                        if existing_value is NOT_PROVIDED:
                            setattr(self,k,v)
                        else:
                            if existing_value is None: # 20130820
                                pass
                                #~ logger.info("%s disables model action '%s'",self,k)
                                #~ self.unbind_action(k)
                            else:
                                if not isinstance(existing_value,actions.Action):
                                    raise Exception(
                                        "%s cannot install model action %s because name is already used for %r" %
                                        self,k,existing_value)

            for name in ('workflow_state_field','workflow_owner_field'):
                if getattr(self,name) is None:
                    setattr(self,name,getattr(self.model,name))
                    #~ v = getattr(self.model,name,None)
                    #~ if v is not None:
                        #~ setattr(self,name,v)
                        
            for name in ( #'disabled_fields',
                         'handle_uploaded_files', 
                         #~ 'get_row_permission', 
                         #~ 'disable_editing',
                         ):
                if getattr(self,name) is None:
                    m = getattr(self.model,name,None)
                    if m is not None:
                        #~ logger.debug('20120731 Install model method %s from %r to %r',name,self.model,self)
                        setattr(self,name,model2actor(m))
                        #~ 'dictproxy' object does not support item assignment:
                        #~ self.__dict__[name] = model2actor(m) 
                        
            if self.master_key:
                #~ assert self.model is not None, "%s has .master_key but .model is None" % self
                #~ self.master = resolve_model(self.master,self.app_label)
                master_model = None
                try:
                    fk, remote, direct, m2m = self.model._meta.get_field_by_name(self.master_key)
                    assert direct
                    assert not m2m
                    #~ if fk.rel is None:
                        #~ raise Exception("%s.master_key %r is not a RelatedField" % (self,self.master_key))
                    if fk.rel is not None:
                        master_model = fk.rel.to
                except models.FieldDoesNotExist,e:
                    #~ logger.debug("FieldDoesNotExist in %r._meta.get_field_by_name(%r)",self.model,self.master_key)
                    for vf in self.model._meta.virtual_fields:
                        if vf.name == self.master_key:
                            fk = vf
                            master_model = ContentType
                            break
                if master_model is None:
                    raise Exception("%s : no master for master_key %r in %s" % (
                        self,self.master_key,self.model))
                self.master = master_model
                #~ self.fk = fk
                self.master_field = fk
Ejemplo n.º 19
0
    def kernel_startup(kernel, self):
        """This is a part of a Lino site startup.  The Django Model
        definitions are done, now Lino analyzes them and does certain
        actions:

        - Verify that there are no more pending injects Install a
          :class:`DisableDeleteHandler
          <lino.core.ddh.DisableDeleteHandler>` for each Model into
          `_lino_ddh`.

        - Install :class:`lino.core.model.Model` attributes and
          methods into Models that don't inherit from it.

        """
        if len(sys.argv) == 0:
            process_name = 'WSGI'
        else:
            process_name = ' '.join(sys.argv)

        logger.info("Started %s (using %s) --> PID %s",
                    process_name, settings.SETTINGS_MODULE, os.getpid())
        # puts(self.welcome_text())

        def goodbye():
            logger.info("Done %s (PID %s)", process_name, os.getpid())
        atexit.register(goodbye)

        models_list = get_models(include_auto_created=True)
        # this also triggers django.db.models.loading.cache._populate()

        self.setup_model_spec(self, 'user_model')
        self.setup_model_spec(self, 'project_model')

        for app_name_model, p in list(self.override_modlib_models.items()):
            # app_name_model is the full installed app module name +
            # the model name. It certainly contains at least one dot.
            m = '.'.join(app_name_model.split('.')[-2:])
            resolve_model(
                m,
                strict="%s plugin tries to extend unresolved model '%%s'" %
                p.__class__.__module__)

        for model in models_list:
            #~ print 20130216, model
            #~ fix_field_cache(model)

            # if hasattr(model, '_lino_ddh'):
            if '_lino_ddh' in model.__dict__:
                raise Exception("20150831 %s", model)
            model._lino_ddh = DisableDeleteHandler(model)

            Model.django2lino(model)

            if isinstance(model.hidden_columns, basestring):
                model.hidden_columns = frozenset(
                    fields.fields_list(model, model.hidden_columns))

            if isinstance(model.active_fields, basestring):
                model.active_fields = frozenset(
                    fields.fields_list(model, model.active_fields))

            if isinstance(model.allow_cascaded_delete, basestring):
                model.allow_cascaded_delete = frozenset(
                    fields.fields_list(model, model.allow_cascaded_delete))

            qsf = model.quick_search_fields
            # Attention when inheriting this from from parent model.
            # qsf = model.__dict__.get('quick_search_fields', None)
            if qsf is None:
                fields_list = []
                for field in model._meta.fields:
                    if isinstance(field, models.CharField):
                        fields_list.append(field.name)
                model.quick_search_fields = frozenset(fields_list)
            elif isinstance(qsf, frozenset):
                pass
            elif isinstance(qsf, basestring):
                model.quick_search_fields = frozenset(
                    fields.fields_list(model, model.quick_search_fields))
            else:
                raise ChangedAPI(
                    "{0}.quick_search_fields must be None or a string "
                    "of space-separated field names (not {1})".format(
                        model, qsf))

            if model._meta.abstract:
                raise Exception("Tiens?")

            # self.modules.define(model._meta.app_label, model.__name__, model)

            for f in model._meta.virtual_fields:
                if isinstance(f, GenericForeignKey):
                    kernel.GFK_LIST.append(f)

        # vip_classes = (layouts.BaseLayout, fields.Dummy)
        # for a in models.get_apps():
        #     app_label = a.__name__.split('.')[-2]

        #     for k, v in a.__dict__.items():
        #         if isinstance(v, type) and issubclass(v, vip_classes):
        #             self.modules.define(app_label, k, v)

        #         if k.startswith('setup_'):
        #             self.modules.define(app_label, k, v)

        if self.user_profiles_module:
            from importlib import import_module
            import_module(self.user_profiles_module)
        
        self.setup_choicelists()
        self.setup_workflows()

        for model in models_list:
            if model._meta.auto_created:
                continue  # automatic intermediate models created by
                          # ManyToManyField should not disable delete
            # for f, m in model._meta.get_fields_with_model():
            for f in model._meta.get_fields():
                m = f.model

                # Refuse nullable CharFields, but don't trigger on
                # NullableCharField (which is a subclass of CharField).

                if f.__class__ is models.CharField and f.null:
                    msg = "Nullable CharField %s in %s" % (f.name, model)
                    raise Exception(msg)
                elif isinstance(f, models.ForeignKey):
                    if isinstance(f.rel.model, basestring):
                        raise Exception("Could not resolve target %r of "
                                        "ForeignKey '%s' in %s "
                                        "(models are %s)" %
                                        (f.rel.model, f.name, model, models_list))
                    set_default_verbose_name(f)

                    """
                    If JobProvider is an MTI child of Company,
                    then mti.delete_child(JobProvider) must not fail on a
                    JobProvider being referred only by objects that can refer
                    to a Company as well.
                    """
                    if not hasattr(f.rel.model, '_lino_ddh'):
                        raise Exception("20150824")
                    # f.rel.model._lino_ddh.add_fk(f.model, f)
                    # m = f.model._meta.concrete_model
                    # f.rel.model._lino_ddh.add_fk(m, f)
                    f.rel.model._lino_ddh.add_fk(m or model, f)

        kernel.protect_foreignkeys(models_list)

        for p in self.installed_plugins:
            if isinstance(p, Plugin):
                p.before_analyze()

        # logger.info("20150429 Gonna send pre_analyze signal")
        pre_analyze.send(self, models_list=models_list)
        # logger.info("20150429 pre_analyze signal done")
        # MergeActions are defined in pre_analyze.
        # And MergeAction needs the info in _lino_ddh to correctly find
        # keep_volatiles

        self.setup_actions()

        for model in models_list:

            """Virtual fields declared on the model must have been attached
            before calling Model.site_setup(), e.g. because
            pcsw.Person.site_setup() declares `is_client` as imported
            field.

            """

            model.on_analyze(self)

            for k, v in class_dict_items(model):
                if isinstance(v, fields.VirtualField):
                    v.attach_to_model(model, k)

        #~ logger.info("20130817 attached model vfs")

        actors.discover()

        logger.debug("actors.initialize()")
        for a in actors.actors_list:
            a.class_init()

        dbtables.discover()
        #~ choosers.discover()
        actions.discover_choosers()

        for a in actors.actors_list:
            a.on_analyze(self)

        post_analyze.send(self, models_list=models_list)

        if False:
            logger.info("Languages: %s. %d apps, %d models, %s actors.",
                        ', '.join([li.django_code for li in self.languages]),
                        len(self.modules),
                        len(models_list),
                        len(actors.actors_list))

        #~ logger.info(settings.INSTALLED_APPS)

        self.setup_layouts()

        self.on_each_app('site_setup')  # deprecated

        # Actor.after_site_setup() is called after the apps'
        # site_setup().  Example: pcsw.site_setup() adds a detail to
        # properties.Properties, the base class for
        # properties.PropsByGroup.  The latter would not install a
        # `detail_action` during her after_site_setup() and also would
        # never get it later.

        for a in actors.actors_list:
            a.after_site_setup(self)

        #~ self.on_site_startup()

        self.resolve_virtual_fields()