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)
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
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))
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)
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)
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
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
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))
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)
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))
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)
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))
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()
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))
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
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()