def write_create_function(model, stream): fields = [ f for f in model._meta.get_fields() if f.concrete and f.model is model ] for f in fields: if getattr(f, 'auto_now_add', False): # raise Exception("%s.%s.auto_now_add is True : values will be lost!" % ( # full_model_name(model), f.name)) logger.warning("%s.%s.auto_now_add is True : values will be lost!", full_model_name(model), f.name) # f.auto_now_add = False stream.write('def create_%s(%s):\n' % (model._meta.db_table, ', '.join([ f.attname for f in fields if not getattr(f, '_lino_babel_field', False) ]))) for f in fields: if f.model is model: pre = ' ' else: pre = '# ' if isinstance(f, models.DecimalField): stream.write(pre + 'if %s is not None: %s = Decimal(%s)\n' % (f.attname, f.attname, f.attname)) elif isinstance(f, ChoiceListField): lstname = 'settings.SITE.models.{0}.{1}'.format( f.choicelist.app_label, f.choicelist.__name__) ln = pre + 'if {0}: {0} = {1}.get_by_value({0})\n' ln = '#' + ln # no longer needed but maybe useful as a comment stream.write(ln.format(f.attname, lstname)) elif is_pointer_to_contenttype(f): stream.write(pre + '%s = new_content_type_id(%s)\n' % (f.attname, f.attname)) if model._meta.parents: if len(model._meta.parents) != 1: msg = "%s : model._meta.parents is %r" % (model, model._meta.parents) raise Exception(msg) pm, pf = list(model._meta.parents.items())[0] fields = [f for f in fields if f != pf] stream.write(" kw = dict()\n") for f in fields: if f.model is model: pre = ' ' else: pre = '# ' if getattr(f, '_lino_babel_field', False): continue elif isinstance(f, (BabelCharField, BabelTextField)): stream.write(pre + 'if %s is not None: kw.update(bv2kw(%r,%s))\n' % (f.attname, f.attname, f.attname)) else: stream.write(pre + 'kw.update(%s=%s)\n' % (f.attname, f.attname)) if model._meta.parents: stream.write(' return create_mti_child(%s, %s, %s, **kw)\n\n' % (full_model_name( pm, '_'), pf.attname, full_model_name(model, '_'))) else: stream.write(' return %s(**kw)\n\n' % full_model_name(model, '_'))
def finalize(self): """ """ self.flush_deferred_objects() if len(self.AFTER_LOAD_HANDLERS): logger.info("Finalize %d after_load handlers", len(self.AFTER_LOAD_HANDLERS)) for h in self.AFTER_LOAD_HANDLERS: logger.info("Running after_load handler %s", h.__doc__) h(self) # logger.info("Loaded %d objects", self.count_objects) if self.save_later: count = 0 s = '' for model, msg_objects in list(self.save_later.items()): for msg, objects in list(msg_objects.items()): if False: # detailed content of the first object s += "\n- %s %s (%d object(s), e.g. %s)" % ( full_model_name(model), msg, len(objects), obj2str(objects[0].object, force_detailed=True)) else: # pk of all objects s += "\n- %s %s (%d object(s) with primary key %s)" % ( full_model_name(model), msg, len(objects), ', '.join([str(o.object.pk) for o in objects])) count += len(objects) msg = "Abandoning with {} unsaved instances:{}" logger.warning(msg.format(count, s))
def finalize(self): """ """ self.flush_deferred_objects() if len(self.AFTER_LOAD_HANDLERS): logger.info( "Finalize %d after_load handlers", len(self.AFTER_LOAD_HANDLERS)) for h in self.AFTER_LOAD_HANDLERS: logger.info("Running after_load handler %s", h.__doc__) h(self) logger.info("Loaded %d objects", self.count_objects) if self.save_later: count = 0 s = '' for model, msg_objects in list(self.save_later.items()): for msg, objects in list(msg_objects.items()): if False: # detailed content of the first object s += "\n- %s %s (%d object(s), e.g. %s)" % ( full_model_name(model), msg, len(objects), obj2str(objects[0].object, force_detailed=True)) else: # pk of all objects s += "\n- %s %s (%d object(s) with primary key %s)" % ( full_model_name(model), msg, len(objects), ', '.join([str(o.object.pk) for o in objects])) count += len(objects) msg = "Abandoning with %d unsaved instances:%s" % (count, s) logger.warning(msg)
def sort_models(self, unsorted): sorted = [] hope = True """ 20121120 if we convert the list to a set, we gain some performance for the ``in`` tests, but we obtain a random sorting order for all independent models, making the double dump test less evident. """ #~ 20121120 unsorted = set(unsorted) while len(unsorted) and hope: hope = False guilty = dict() #~ puts("hope for", [m.__name__ for m in unsorted]) for model in unsorted: deps = set([ f.rel.model for f in model._meta.fields if f.rel is not None and f.rel.model is not model and f.rel.model in unsorted ]) #~ deps += [m for m in model._meta.parents.keys()] for m in sorted: if m in deps: deps.remove(m) if len(deps): guilty[model] = deps else: sorted.append(model) unsorted.remove(model) hope = True break #~ ok = True #~ for d in deps: #~ if d in unsorted: #~ ok = False #~ if ok: #~ sorted.append(model) #~ unsorted.remove(model) #~ hope = True #~ break #~ else: #~ guilty[model] = deps #~ print model.__name__, "depends on", [m.__name__ for m in deps] if unsorted: assert len(unsorted) == len(guilty) msg = "There are %d models with circular dependencies :\n" % len( unsorted) msg += "- " + '\n- '.join([ full_model_name(m) + ' (depends on %s)' % ", ".join([full_model_name(d) for d in deps]) for m, deps in list(guilty.items()) ]) if False: # we don't write them to the .py file because they are # in random order which would cause false ddt to fail for ln in msg.splitlines(): self.stream.write('\n# %s' % ln) logger.info(msg) sorted.extend(unsorted) return sorted
def sort_models(self, unsorted): sorted = [] hope = True """ 20121120 if we convert the list to a set, we gain some performance for the ``in`` tests, but we obtain a random sorting order for all independent models, making the double dump test less evident. """ #~ 20121120 unsorted = set(unsorted) while len(unsorted) and hope: hope = False guilty = dict() #~ puts("hope for", [m.__name__ for m in unsorted]) for model in unsorted: deps = set([f.rel.model for f in model._meta.fields if f.rel is not None and f.rel.model is not model and f.rel.model in unsorted]) #~ deps += [m for m in model._meta.parents.keys()] for m in sorted: if m in deps: deps.remove(m) if len(deps): guilty[model] = deps else: sorted.append(model) unsorted.remove(model) hope = True break #~ ok = True #~ for d in deps: #~ if d in unsorted: #~ ok = False #~ if ok: #~ sorted.append(model) #~ unsorted.remove(model) #~ hope = True #~ break #~ else: #~ guilty[model] = deps #~ print model.__name__, "depends on", [m.__name__ for m in deps] if unsorted: assert len(unsorted) == len(guilty) msg = "There are %d models with circular dependencies :\n" % len( unsorted) msg += "- " + '\n- '.join([ full_model_name(m) + ' (depends on %s)' % ", ".join([ full_model_name(d) for d in deps]) for m, deps in list(guilty.items())]) if False: # we don't write them to the .py file because they are # in random order which would cause false ddt to fail for ln in msg.splitlines(): self.stream.write('\n# %s' % ln) logger.info(msg) sorted.extend(unsorted) return sorted
def add(name): for f, qs in getattr(self, name): if qs.count() > 0: lst.append( "- %d %s %s rows using %s : %s" % (qs.count(), name, full_model_name(f.model), f.name, " ".join([str(o.pk) for o in qs])) )
def value2string(self, obj, field): if isinstance(field, (BabelCharField, BabelTextField)): # ~ return repr([repr(x) for x in dbutils.field2args(obj,field.name)]) return repr(settings.SITE.field2args(obj, field.name)) value = field._get_val_from_obj(obj) # Protected types (i.e., primitives like None, numbers, dates, # and Decimals) are passed through as is. All other values are # converted to string first. if value is None: # ~ if value is None or value is NOT_PROVIDED: return "None" if isinstance(field, models.DateTimeField): d = value return "dt(%d,%d,%d,%d,%d,%d)" % (d.year, d.month, d.day, d.hour, d.minute, d.second) if isinstance(field, models.TimeField): d = value return "time(%d,%d,%d)" % (d.hour, d.minute, d.second) if is_pointer_to_contenttype(field): ContentType = settings.SITE.modules.contenttypes.ContentType ct = ContentType.objects.get(pk=value) return full_model_name(ct.model_class(), "_") # ~ return "'"+full_model_name(ct.model_class())+"'" # ~ return repr(tuple(value.app_label,value.model)) if isinstance(field, models.DateField): d = value return "date(%d,%d,%d)" % (d.year, d.month, d.day) # ~ return 'i2d(%4d%02d%02d)' % (d.year,d.month,d.day) if isinstance(value, (float, Decimal)): return repr(str(value)) if isinstance(value, int): return str(value) return repr(field.value_to_string(obj))
def __init__(self, model, **kw): fields = dict( #~ merge_from=models.ForeignKey(model,verbose_name=_("Merge...")), merge_to=models.ForeignKey(model, verbose_name=_("into..."), blank=False, null=False), reason=models.CharField(_("Reason"), max_length=100) #~ notify=models.BooleanField(_("Send notifications")) ) keep_volatiles = [] # logger.info("20160621 MergeAction for %s", model) # logger.info("20160621 MergeAction for %s : _lino_ddh.fklist is %s", # model, model._lino_ddh.fklist) for m, fk in traverse_ddh_fklist(model): if fk.name in m.allow_cascaded_delete: fieldname = full_model_name(m, '_') if fieldname not in keep_volatiles: keep_volatiles.append(fieldname) fields[fieldname] = models.BooleanField( m._meta.verbose_name_plural, default=False) # logger.info( # "20160621 %r in %r", fk.name, m.allow_cascaded_delete) layout = dict() if len(keep_volatiles) == 0: width = 50 main = """ merge_to reason """ else: COLCOUNT = 2 width = 70 if len(keep_volatiles) > COLCOUNT: tpl = '' for i, name in enumerate(keep_volatiles): if i % COLCOUNT == 0: tpl += '\n' else: tpl += ' ' tpl += name else: tpl = ' '.join(keep_volatiles) main = """ merge_to keep_volatiles reason """ layout.update(keep_volatiles=layouts.Panel( tpl, label=_("Also reassign volatile related objects"))) layout.update(window_size=(width, 'auto')) kw.update(parameters=fields, params_layout=layouts.Panel(main, **layout)) super(MergeAction, self).__init__(**kw)
def value2string(self, obj, field): if isinstance(field, (BabelCharField, BabelTextField)): return repr(settings.SITE.field2args(obj, field.name)) value = field._get_val_from_obj(obj) # Protected types (i.e., primitives like None, numbers, dates, # and Decimals) are passed through as is. All other values are # converted to string first. if value is None: #~ if value is None or value is NOT_PROVIDED: return 'None' if isinstance(field, models.DateTimeField): d = value return 'dt(%d,%d,%d,%d,%d,%d)' % (d.year, d.month, d.day, d.hour, d.minute, d.second) if isinstance(field, models.TimeField): d = value return 'time(%d,%d,%d)' % (d.hour, d.minute, d.second) if isinstance(field, models.ForeignKey) and field.rel.to is ContentType: ct = ContentType.objects.get(pk=value) return full_model_name(ct.model_class(), '_') #~ return "'"+full_model_name(ct.model_class())+"'" #~ return repr(tuple(value.app_label,value.model)) if isinstance(field, models.DateField): d = value return 'date(%d,%d,%d)' % (d.year, d.month, d.day) #~ return 'i2d(%4d%02d%02d)' % (d.year,d.month,d.day) if isinstance(value, (float, Decimal)): return repr(str(value)) if isinstance(value, (int, long)): return str(value) return repr(field.value_to_string(obj))
def test_controllables(self): found = [] for M in rt.models_by_base(Controllable): found.append(full_model_name(M)) expected = """cal.Event cal.Task excerpts.Excerpt notes.Note notifier.Notification outbox.Attachment outbox.Mail plausibility.Problem uploads.Upload""".split() self.assertEqual(found, expected) Person = rt.modules.contacts.Person Note = rt.modules.notes.Note Excerpt = rt.modules.excerpts.Excerpt ExcerptType = rt.modules.excerpts.ExcerptType ContentType = rt.modules.contenttypes.ContentType self.assertEqual(len(Person.allow_cascaded_delete), 0) self.assertEqual(len(Note.allow_cascaded_delete), 0) self.assertEqual(len(Excerpt.allow_cascaded_delete), 1) doe = create(Person, first_name="John", last_name="Doe") note = create(Note, owner=doe, body="John Doe is a fink!") ct = ContentType.objects.get_for_model(Note) etype = create(ExcerptType, name="Note", content_type=ct) excerpt = create(Excerpt, owner=note, excerpt_type=etype) self.assertEqual(Person.objects.count(), 1) self.assertEqual(Note.objects.count(), 1) self.assertEqual(Excerpt.objects.count(), 1) ar = rt.modules.notes.Notes.request() s = ar.to_rst(column_names="id owner") self.assertEqual(s, """\ ==== =============== ID Controlled by ---- --------------- 1 *John Doe* ==== =============== """) ar = rt.modules.excerpts.Excerpts.request() s = ar.to_rst(column_names="id owner") self.assertEqual(s, """\ ==== =============== ID Controlled by ---- --------------- 1 *Note #1* ==== =============== """) self.assertEqual(excerpt.disable_delete(), None) self.assertEqual(note.disable_delete(), None) self.assertEqual(doe.disable_delete(), None) # it is not "Cannot delete John Doe because 1 Notes refer to # it." because Note.owner is nullable. note.delete() self.assertEqual(Excerpt.objects.count(), 0) self.assertEqual(ExcerptType.objects.count(), 1)
def value2string(self, obj, field): from django.contrib.contenttypes.models import ContentType if isinstance(field, (BabelCharField, BabelTextField)): return repr(settings.SITE.field2args(obj, field.name)) value = field._get_val_from_obj(obj) # Protected types (i.e., primitives like None, numbers, dates, # and Decimals) are passed through as is. All other values are # converted to string first. if value is None: #~ if value is None or value is NOT_PROVIDED: return 'None' if isinstance(field, models.DateTimeField): d = value return 'dt(%d,%d,%d,%d,%d,%d)' % ( d.year, d.month, d.day, d.hour, d.minute, d.second) if isinstance(field, models.TimeField): d = value return 'time(%d,%d,%d)' % (d.hour, d.minute, d.second) if isinstance(field, ForeignKey) and field.rel.model is ContentType: ct = ContentType.objects.get(pk=value) return full_model_name(ct.model_class(), '_') #~ return "'"+full_model_name(ct.model_class())+"'" #~ return repr(tuple(value.app_label,value.model)) if isinstance(field, models.DateField): d = value return 'date(%d,%d,%d)' % (d.year, d.month, d.day) #~ return 'i2d(%4d%02d%02d)' % (d.year,d.month,d.day) if isinstance(value, (float, Decimal)): return repr(str(value)) if isinstance(value, int): return str(value) return repr(field.value_to_string(obj))
def __init__(self, model, **kw): fields = dict( #~ merge_from=models.ForeignKey(model,verbose_name=_("Merge...")), merge_to=models.ForeignKey( model, verbose_name=_("into..."), blank=False, null=False), reason=models.CharField(_("Reason"), max_length=100) #~ notify=models.BooleanField(_("Send notifications")) ) keep_volatiles = [] # logger.info("20160621 MergeAction for %s", model) # logger.info("20160621 MergeAction for %s : _lino_ddh.fklist is %s", # model, model._lino_ddh.fklist) for m, fk in traverse_ddh_fklist(model): if fk.name in m.allow_cascaded_delete: fieldname = full_model_name(m, '_') if fieldname not in keep_volatiles: keep_volatiles.append(fieldname) fields[fieldname] = models.BooleanField( m._meta.verbose_name_plural, default=False) # logger.info( # "20160621 %r in %r", fk.name, m.allow_cascaded_delete) layout = dict() if len(keep_volatiles) == 0: width = 50 main = """ merge_to reason """ else: COLCOUNT = 2 width = 70 if len(keep_volatiles) > COLCOUNT: tpl = '' for i, name in enumerate(keep_volatiles): if i % COLCOUNT == 0: tpl += '\n' else: tpl += ' ' tpl += name else: tpl = ' '.join(keep_volatiles) main = """ merge_to keep_volatiles reason """ layout.update(keep_volatiles=layouts.Panel( tpl, label=_("Also reassign volatile related objects"))) layout.update(window_size=(width, 'auto')) kw.update( parameters=fields, params_layout=layouts.Panel(main, **layout)) super(MergeAction, self).__init__(**kw)
def fk_display(obj, value): ct = getattr(obj, self.ct_field) if ct: try: return unicode(ct.get_object_for_this_type(pk=value)) except ct.model_class().DoesNotExist: return "%s with pk %r does not exist" % ( full_model_name(ct.model_class()), value)
def add(name): for f, qs in getattr(self, name): if qs.count() > 0: lst.append('- %d %s %s rows using %s : %s' % ( qs.count(), name, full_model_name(f.model), f.name, ' '.join([str(o.pk) for o in qs])))
def finalize(self): """ """ self.flush_deferred_objects() if len(self.AFTER_LOAD_HANDLERS): logger.info( "Finalize %d after_load handlers", len(self.AFTER_LOAD_HANDLERS)) for h in self.AFTER_LOAD_HANDLERS: logger.info("Running after_load handler %s", h.__doc__) h(self) # logger.info("Loaded %d objects", self.count_objects) if self.save_later: count = 0 s = '' for model, msg_objects in list(self.save_later.items()): for msg, objects in list(msg_objects.items()): if False: # detailed content of the first object s += "\n- %s %s (%d object(s), e.g. %s)" % ( full_model_name(model), msg, len(objects), obj2str(objects[0].object, force_detailed=True)) else: # pk of all objects s += "\n- %s %s (%d object(s) with primary key %s)" % ( full_model_name(model), msg, len(objects), ', '.join([str(o.object.pk) for o in objects])) count += len(objects) msg = "Abandoning with {} unsaved instances:{}" logger.warning(msg.format(count, s)) # Don't raise an exception. The unsaved instances got lost and # the loaddata should be done again, but meanwhile the database # is not necessarily invalid and may be used for further testing. # And anyway, loaddata would catch it and still continue. # raise Exception(msg) settings.SITE.loading_from_dump = False
def get_by_id(model, pk, offset=0, warn=True): if not pk: return None pk = int(pk) if pk == 0: return None try: return model.objects.get(pk=pk + offset) except model.DoesNotExist: if warn: dblogger.warning("%s %r does not exist?!", full_model_name(model), pk) return None
def analyze(self): self.volatiles = [] self.related = [] for m, fk in self.obj._lino_ddh.fklist: qs = m.objects.filter(**{fk.name: self.obj}) if fk.name in m.allow_cascaded_delete and not self.keep_volatiles.get(full_model_name(m, "_")): self.volatiles.append((fk, qs)) else: self.related.append((fk, qs)) self.generic_related = [] for gfk, fk, qs in settings.SITE.kernel.get_generic_related(self.obj): if not getattr(gfk, "dont_merge", False): self.generic_related.append((gfk, qs))
def analyze(self): self.volatiles = [] self.related = [] for m, fk in self.obj._lino_ddh.fklist: qs = m.objects.filter(**{fk.name: self.obj}) if fk.name in m.allow_cascaded_delete and \ not self.keep_volatiles.get(full_model_name(m, '_')): self.volatiles.append((fk, qs)) else: self.related.append((fk, qs)) self.generic_related = [] for gfk, fk, qs in settings.SITE.kernel.get_generic_related(self.obj): if not getattr(gfk, 'dont_merge', False): self.generic_related.append((gfk, qs))
def analyze(self): self.volatiles = [] self.related = [] self.generic_related = [] # logger.info("20160621 ddh.fklist is %s", self.obj._lino_ddh.fklist) for m, fk in traverse_ddh_fklist(self.obj.__class__): qs = m.objects.filter(**{fk.name: self.obj}) if fk.name in m.allow_cascaded_delete and \ not self.keep_volatiles.get(full_model_name(m, '_')): self.volatiles.append((fk, qs)) else: self.related.append((fk, qs)) for gfk, fk, qs in settings.SITE.kernel.get_generic_related(self.obj): if not getattr(gfk, 'dont_merge', False): self.generic_related.append((gfk, qs))
def show_db_overview(self): """Return a reStructredText-formatted "database overview" report. Used by test cases in tested documents. """ from lino.core.utils import (full_model_name, sorted_models_list) models_list = sorted_models_list() apps = [p.app_label for p in settings.SITE.installed_plugins] s = "%d apps: %s." % (len(apps), ", ".join(apps)) s += "\n%d models:\n" % len(models_list) i = 0 headers = [ #~ "No.", "Name", "Default table", #~ "M", "#fields", "#rows", #~ ,"first","last" ] rows = [] for model in models_list: if True: # model._meta.managed: i += 1 cells = [] #~ cells.append(str(i)) cells.append(full_model_name(model)) cells.append(model.get_default_table()) #~ cells.append(str(model)) #~ if model._meta.managed: #~ cells.append('X') #~ else: #~ cells.append('') cells.append(str(len(model._meta.concrete_fields))) qs = model.objects.all() n = qs.count() cells.append(str(n)) #~ if n: #~ cells.append(obj2str(qs[0])) #~ cells.append(obj2str(qs[n-1])) #~ else: #~ cells.append('') #~ cells.append('') rows.append(cells) s += rstgen.table(headers, rows) return s
def show_fields_by_type(fldtype): """Print a list of all fields (in all models) that have the specified type. """ from lino.core.utils import (sorted_models_list) items = [] for model in sorted_models_list(): flds = [] for f in model._meta.fields: if isinstance(f, fldtype): name = f.name verbose_name = force_text(f.verbose_name).strip() txt = "{verbose_name} ({name})".format(**locals()) flds.append(txt) if len(flds): txt = "{model} : {fields}".format(model=full_model_name(model), fields=", ".join(flds)) items.append(txt) print(rstgen.ul(items))
def value2string(self, obj, field): if isinstance(field, (BabelCharField, BabelTextField)): #~ return repr([repr(x) for x in dbutils.field2args(obj,field.name)]) return repr(settings.SITE.field2args(obj, field.name)) # value = field._get_val_from_obj(obj) value = field.value_from_object(obj) # Protected types (i.e., primitives like None, numbers, dates, # and Decimals) are passed through as is. All other values are # converted to string first. if value is None: #~ if value is None or value is NOT_PROVIDED: return 'None' if isinstance(field, models.DateTimeField): if is_aware(value): d = make_naive(value, timezone=utc) else: d = value return 'dt(%d,%d,%d,%d,%d,%d)' % (d.year, d.month, d.day, d.hour, d.minute, d.second) if isinstance(field, models.TimeField): d = value return 'time(%d,%d,%d)' % (d.hour, d.minute, d.second) if is_pointer_to_contenttype(field): ContentType = settings.SITE.models.contenttypes.ContentType ct = ContentType.objects.get(pk=value) return full_model_name(ct.model_class(), '_') #~ return "'"+full_model_name(ct.model_class())+"'" #~ return repr(tuple(value.app_label,value.model)) if isinstance(field, models.DateField): d = value return 'date(%d,%d,%d)' % (d.year, d.month, d.day) #~ return 'i2d(%4d%02d%02d)' % (d.year,d.month,d.day) if isinstance(value, (float, Decimal)): return repr(str(value)) if isinstance(value, int): return str(value) return repr(field.value_to_string(obj))
def model_name(m): return settings.SITE.userdocs_prefix + full_model_name(m).lower()
def get_rst(self): #~ from actordoc import get_actor_description #~ from django.conf import settings #~ from djangosite.dbutils import set_language with translation.override(self.language): level, cls = resolve_name(self.content[0]) if isinstance(cls, models.Field): fld = cls s = '' name = str(fld.model) + '.' + fld.name title = force_text(fld.verbose_name).strip() s += "\n.. index::\n single: " s += str(_('%(field)s (field in %(model)s)') % dict( field=title, model=model_ref(fld.model))) s += '\n\n' s += rstgen.header(level, _("%s (field)") % title) if len(self.content) > 1: s += '\n'.join(self.content[1:]) s += '\n\n' return s if isinstance(cls, Plugin): s = '' title = str(cls.verbose_name) s += "\n.. index::\n single: " s += str(_('%s (app)') % title) s += '\n\n.. _' + name + ':\n' s += '\n' s += rstgen.header(level, _("%s (app)") % title) return s if not isinstance(cls, type): raise Exception("%s is not an actor." % self.content[0]) if issubclass(cls, models.Model): model = cls s = '' name = model_name(model).lower() title = force_text(model._meta.verbose_name) s += "\n.. index::\n single: " s += str(_('%(model)s (model in %(app)s)') % dict( model=title, app=model._meta.app_label)) s += '\n\n' s += '\n\n.. _' + name + ':\n' s += '\n' s += rstgen.header(level, _("%s (model)") % title) s += '\n' s += '\n:Internal name: ``%s``\n' % full_model_name(cls) s += '\n:Implemented by: %s\n' % typeref(cls) s += '\n' if len(self.content) > 1: s += '\n'.join(self.content[1:]) s += '\n\n' model_reports = [ r for r in kernel.master_tables if r.model is cls] model_reports += [r for r in kernel.slave_tables if r.model is cls] s += rstgen.boldheader(_("Views on %s") % cls._meta.verbose_name) s += actors_overview_ul(model_reports) s += rstgen.boldheader(_("Fields in %s") % cls._meta.verbose_name) s += fields_ul(cls._meta.fields) action_list = cls.get_default_table().get_actions() action_list = [ ba for ba in action_list if not isinstance(ba.action, IGNORED_ACTIONS)] if action_list: s += '\n' s += rstgen.boldheader(_("Actions on %s") % cls._meta.verbose_name) s += actions_ul(action_list) slave_tables = getattr(cls, '_lino_slaves', {}).values() if slave_tables: s += rstgen.boldheader(_("Tables referring to %s") % cls._meta.verbose_name) s += actors_overview_ul(slave_tables) return s if issubclass(cls, actors.Actor): title = force_text(cls.label or cls.title) indextext = _('%(actor)s (view in %(app)s)') % dict( actor=title, app=cls.app_label) name = actor_name(cls) #~ if name == 'welfare.reception.waitingvisitors': #~ self.debug = True #~ print(20130907, name) self.index_entries.append(('single', indextext, name, '')) #~ self.add_ref_target(name,name) s = '' s += '\n\n.. _%s:\n\n' % name s += rstgen.header(level, _("%s (view)") % title) s += '\n:Internal name: ``%s`` (%s)\n' % (cls, typeref(cls)) if len(self.content) > 1: s += '\n'.join(self.content[1:]) s += '\n\n' s += '\n\n' s += get_actor_description(cls) s += '\n\n' return s raise Exception("Cannot handle actor %r." % cls)
def write_files(self): puts("Writing {0}...".format(self.main_file)) self.stream = open(self.main_file, 'wt') current_version = settings.SITE.version self.stream.write('''\ #!/usr/bin/env python # -*- coding: UTF-8 -*- # This is a Python dump created using dump2py. # DJANGO_SETTINGS_MODULE was %r, TIME_ZONE was %r. ''' % (settings.SETTINGS_MODULE, settings.TIME_ZONE)) self.stream.write(''' from __future__ import unicode_literals import logging logger = logging.getLogger('%s') import os ''' % __name__) self.stream.write('SOURCE_VERSION = %r\n' % str(current_version)) self.stream.write(''' from decimal import Decimal from datetime import datetime from datetime import time, date from django.conf import settings from django.utils.timezone import make_aware # from django.contrib.contenttypes.models import ContentType from lino.utils.dpy import create_mti_child from lino.utils.dpy import DpyLoader from lino.core.utils import resolve_model if settings.USE_TZ: def dt(*args): return make_aware(datetime(*args)) else: def dt(*args): return datetime(*args) def new_content_type_id(m): if m is None: return m ct = settings.SITE.models.contenttypes.ContentType.objects.get_for_model(m) if ct is None: return None return ct.pk ''') s = ','.join([ '%s=values[%d]' % (lng.name, lng.index) for lng in settings.SITE.languages]) self.stream.write(''' def bv2kw(fieldname, values): """ Needed if `Site.languages` changed between dumpdata and loaddata """ return settings.SITE.babelkw(fieldname, %s) ''' % s) self.models = sorted_models_list() if settings.SITE.is_installed('contenttypes'): from django.contrib.contenttypes.models import ContentType self.models = [m for m in self.models if not issubclass(m, ContentType)] if settings.SITE.is_installed('sessions'): from django.contrib.sessions.models import Session self.models = [m for m in self.models if not issubclass(m, Session)] for model in self.models: self.stream.write('%s = resolve_model("%s")\n' % ( full_model_name(model, '_'), full_model_name(model))) self.stream.write('\n') self.models = self.sort_models(self.models) self.stream.write('\n') for model in self.models: fields = [f for f in model._meta.get_fields() if f.concrete and f.model is model] for f in fields: if getattr(f, 'auto_now_add', False): raise Exception("%s.%s.auto_now_add is True : values will be lost!" % ( full_model_name(model), f.name)) #~ fields = model._meta.local_fields #~ fields = [f for f in model._meta.fields if f.serialize] #~ fields = [f for f in model._meta.local_fields if f.serialize] self.stream.write('def create_%s(%s):\n' % ( model._meta.db_table, ', '.join([ f.attname for f in fields if not getattr(f, '_lino_babel_field', False)]))) for f in fields: if isinstance(f, models.DecimalField): self.stream.write( ' if %s is not None: %s = Decimal(%s)\n' % ( f.attname, f.attname, f.attname)) elif isinstance(f, ChoiceListField): lstname = 'settings.SITE.modules.{0}.{1}'.format( f.choicelist.app_label, f.choicelist.__name__) ln = ' if {0}: {0} = {1}.get_by_value({0})\n' self.stream.write(ln.format(f.attname, lstname)) elif is_pointer_to_contenttype(f): self.stream.write( ' %s = new_content_type_id(%s)\n' % ( f.attname, f.attname)) if model._meta.parents: if len(model._meta.parents) != 1: msg = "%s : model._meta.parents is %r" % ( model, model._meta.parents) raise Exception(msg) pm, pf = list(model._meta.parents.items())[0] child_fields = [f for f in fields if f != pf] if child_fields: attrs = ',' + ','.join([ '%s=%s' % (f.attname, f.attname) for f in child_fields]) else: attrs = '' self.stream.write( ' return create_mti_child(%s, %s, %s%s)\n' % ( full_model_name(pm, '_'), pf.attname, full_model_name(model, '_'), attrs)) else: self.stream.write(" kw = dict()\n") for f in fields: if getattr(f, '_lino_babel_field', False): continue elif isinstance(f, (BabelCharField, BabelTextField)): self.stream.write( ' if %s is not None: kw.update(bv2kw(%r,%s))\n' % ( f.attname, f.attname, f.attname)) else: self.stream.write( ' kw.update(%s=%s)\n' % (f.attname, f.attname)) self.stream.write(' return %s(**kw)\n\n' % full_model_name(model, '_')) self.stream.write('\n') #~ used_models = set() self.stream.write(""" def main(args): loader = DpyLoader(globals()) from django.core.management import call_command call_command('initdb', interactive=args.interactive) os.chdir(os.path.dirname(__file__)) loader.initialize() """) for model in progress.bar(self.models): filename = '%s.py' % model._meta.db_table filename = os.path.join(self.output_dir, filename) # puts("Writing {0}...".format(filename)) # stream = file(filename, 'wt') stream = open(filename, 'wt') stream.write('# -*- coding: UTF-8 -*-\n') qs = model.objects.all() try: stream.write( 'logger.info("Loading %d objects to table %s...")\n' % ( qs.count(), model._meta.db_table)) fields = [f for f in model._meta.get_fields() if f.concrete and f.model is model] fields = [ f for f in fields if not getattr(f, '_lino_babel_field', False)] stream.write( "# fields: %s\n" % ', '.join( [f.name for f in fields])) for obj in qs: self.count_objects += 1 #~ used_models.add(model) stream.write('loader.save(create_%s(%s))\n' % ( obj._meta.db_table, ','.join([self.value2string(obj, f) for f in fields]))) stream.write('\n') stream.write('loader.flush_deferred_objects()\n') except DatabaseError as e: self.database_errors += 1 if not self.options['tolerate']: raise stream.write('\n') logger.warning("Tolerating database error %s in %s", e, model._meta.db_table) msg = ("The data of this table has not been dumped" "because an error {0} occured.").format(e) stream.write('raise Exception("{0}")\n'.format(msg)) stream.close() #~ self.stream.write('\nfilename = os.path.join(os.path.dirname(__file__),"%s.py")\n' % ) self.stream.write(' execfile("%s.py")\n' % model._meta.db_table) self.stream.write( ' loader.finalize()\n') # self.stream.write( # ' logger.info("Loaded %d objects",loader.count_objects)\n') self.stream.write(""" if __name__ == '__main__': import argparse parser = argparse.ArgumentParser(description='Restore the data.') parser.add_argument('--noinput', dest='interactive', action='store_false', default=True, help="Don't ask for confirmation before flushing the database.") args = parser.parse_args() main(args) """) #~ self.stream.write('\nsettings.SITE.load_from_file(globals())\n') self.stream.close()
def write_files(self): puts("Writing {0}...".format(self.main_file)) self.stream = open(self.main_file, 'wt') current_version = settings.SITE.version self.stream.write("""\ #!/usr/bin/env python # -*- coding: UTF-8 -*- """) self.stream.write('''\ """ This is a Python dump created using %s. ''' % settings.SITE.using_text()) #~ self.stream.write(settings.SITE.welcome_text()) self.stream.write(''' """ from __future__ import unicode_literals import logging logger = logging.getLogger('%s') import os ''' % __name__) if False: self.stream.write(""" os.environ['DJANGO_SETTINGS_MODULE'] = '%s' """ % settings.SETTINGS_MODULE) self.stream.write('SOURCE_VERSION = %r\n' % str(current_version)) self.stream.write(''' from decimal import Decimal from datetime import datetime as dt from datetime import time,date from django.conf import settings from django.contrib.contenttypes.models import ContentType from lino.utils.dpy import create_mti_child from lino.utils.dpy import DpyLoader from lino.core.utils import resolve_model def new_content_type_id(m): if m is None: return m ct = ContentType.objects.get_for_model(m) if ct is None: return None return ct.pk ''') s = ','.join([ '%s=values[%d]' % (lng.name, lng.index) for lng in settings.SITE.languages ]) self.stream.write(''' def bv2kw(fieldname, values): """ Needed if `Site.languages` changed between dumpdata and loaddata """ return settings.SITE.babelkw(fieldname, %s) ''' % s) self.models = [ m for m in sorted_models_list() if not issubclass(m, (ContentType, Session)) ] for model in self.models: self.stream.write( '%s = resolve_model("%s")\n' % (full_model_name(model, '_'), full_model_name(model))) self.stream.write('\n') self.models = self.sort_models(self.models) self.stream.write('\n') for model in self.models: fields = [ f for f, m in model._meta.get_fields_with_model() if m is None ] if AFTER17: fields = [f for f in fields if f.concrete] for f in fields: if getattr(f, 'auto_now_add', False): raise Exception( "%s.%s.auto_now_add is True : values will be lost!" % (full_model_name(model), f.name)) #~ fields = model._meta.local_fields #~ fields = [f for f in model._meta.fields if f.serialize] #~ fields = [f for f in model._meta.local_fields if f.serialize] self.stream.write('def create_%s(%s):\n' % (model._meta.db_table, ', '.join([ f.attname for f in fields if not getattr(f, '_lino_babel_field', False) ]))) if model._meta.parents: if len(model._meta.parents) != 1: msg = "%s : model._meta.parents is %r" % ( model, model._meta.parents) raise Exception(msg) pm, pf = model._meta.parents.items()[0] child_fields = [f for f in fields if f != pf] if child_fields: attrs = ',' + ','.join([ '%s=%s' % (f.attname, f.attname) for f in child_fields ]) else: attrs = '' #~ self.stream.write(' return insert_child(%s.objects.get(pk=%s),%s%s)\n' % ( #~ full_model_name(pm,'_'),pf.attname,full_model_name(model,'_'),attrs)) self.stream.write(' return create_mti_child(%s,%s,%s%s)\n' % (full_model_name(pm, '_'), pf.attname, full_model_name(model, '_'), attrs)) else: self.stream.write(" kw = dict()\n") for f in fields: if getattr(f, '_lino_babel_field', False): continue elif isinstance(f, (BabelCharField, BabelTextField)): self.stream.write( ' if %s is not None: kw.update(bv2kw(%r,%s))\n' % (f.attname, f.attname, f.attname)) else: if isinstance(f, models.DecimalField): self.stream.write( ' if %s is not None: %s = Decimal(%s)\n' % (f.attname, f.attname, f.attname)) elif isinstance( f, models.ForeignKey) and f.rel.to is ContentType: #~ self.stream.write( #~ ' %s = ContentType.objects.get_for_model(%s).pk\n' % ( #~ f.attname,f.attname)) self.stream.write( ' %s = new_content_type_id(%s)\n' % (f.attname, f.attname)) self.stream.write(' kw.update(%s=%s)\n' % (f.attname, f.attname)) self.stream.write(' return %s(**kw)\n\n' % full_model_name(model, '_')) self.stream.write('\n') #~ used_models = set() self.stream.write(""" def main(): loader = DpyLoader(globals()) from django.core.management import call_command # call_command('initdb', interactive=False) call_command('initdb') os.chdir(os.path.dirname(__file__)) loader.initialize() """) for model in progress.bar(self.models): filename = '%s.py' % model._meta.db_table filename = os.path.join(self.output_dir, filename) # puts("Writing {0}...".format(filename)) stream = file(filename, 'wt') stream.write('# -*- coding: UTF-8 -*-\n') qs = model.objects.all() try: stream.write( 'logger.info("Loading %d objects to table %s...")\n' % (qs.count(), model._meta.db_table)) fields = [ f for f, m in model._meta.get_fields_with_model() if m is None ] fields = [ f for f in fields if not getattr(f, '_lino_babel_field', False) ] if AFTER17: fields = [f for f in fields if f.concrete] stream.write("# fields: %s\n" % ', '.join([f.name for f in fields])) for obj in qs: self.count_objects += 1 #~ used_models.add(model) stream.write( 'loader.save(create_%s(%s))\n' % (obj._meta.db_table, ','.join( [self.value2string(obj, f) for f in fields]))) stream.write('\n') stream.write('loader.flush_deferred_objects()\n') except ProgrammingError as e: if not self.options['tolerate']: raise stream.write('\n') logger.warning("Tolerating database error %s in %s", e, model._meta.db_table) msg = ("The data of this table has not been dumped" "because an error {0} occured.").format(e) stream.write('raise Exception("{0}")\n'.format(msg)) stream.close() #~ self.stream.write('\nfilename = os.path.join(os.path.dirname(__file__),"%s.py")\n' % ) self.stream.write(' execfile("%s.py")\n' % model._meta.db_table) self.stream.write(' loader.finalize()\n') # self.stream.write( # ' logger.info("Loaded %d objects",loader.count_objects)\n') self.stream.write(""" if __name__ == '__main__': main() """) #~ self.stream.write('\nsettings.SITE.load_from_file(globals())\n') self.stream.close()
def get_data_elem(cls, name): """Return the named data element. This can be a database field, a :class:`lino.core.fields.RemoteField`, a :class:`lino.core.fields.VirtualField` or a Django-style virtual field (GenericForeignKey). """ #~ logger.info("20120202 get_data_elem %r,%r",model,name) if not name.startswith('__'): parts = name.split('__') if len(parts) > 1: # It's going to be a RemoteField # logger.warning("20151203 RemoteField %s in %s", name, cls) from lino.core import store model = cls field_chain = [] for n in parts: if model is None: raise Exception( "Invalid remote field {0} for {1}".format(name, cls)) if isinstance(model, basestring): model = resolve_model(model) # logger.warning("20151203 %s", model) # Django 1.9 no longer resolves the # rel.model of ForeignKeys on abstract # models. # ~ 20130508 model.get_default_table().get_handle() # make sure that all atomizers of those fields get created. fld = model.get_data_elem(n) if fld is None: # raise Exception("Part %s of %s got None" % (n,model)) raise Exception( "Invalid RemoteField %s.%s (no field %s in %s)" % (full_model_name(model), name, n, full_model_name(model))) # make sure that the atomizer gets created. store.get_atomizer(model, fld, fld.name) field_chain.append(fld) if getattr(fld, 'rel', None): if AFTER18: model = fld.rel.model else: model = fld.rel.to else: model = None def func(obj, ar=None): try: for fld in field_chain: if obj is None: return obj obj = fld._lino_atomizer.full_value_from_object( obj, ar) return obj except Exception as e: raise Exception( "Error while computing %s: %s" % (name, e)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return None return fields.RemoteField(func, name, fld) try: return cls._meta.get_field(name) except models.FieldDoesNotExist: pass v = get_class_attr(cls, name) if v is not None: return v for vf in cls._meta.virtual_fields: if vf.name == name: return vf
def write_files(self): puts("Writing {0}...".format(self.main_file)) self.stream = open(self.main_file, "wt") current_version = settings.SITE.version self.stream.write( """\ #!/usr/bin/env python # -*- coding: UTF-8 -*- """ ) self.stream.write( '''\ """ This is a Python dump created using %s. ''' % settings.SITE.using_text() ) # ~ self.stream.write(settings.SITE.welcome_text()) self.stream.write( ''' """ from __future__ import unicode_literals import logging logger = logging.getLogger('%s') import os ''' % __name__ ) if False: self.stream.write( """ os.environ['DJANGO_SETTINGS_MODULE'] = '%s' """ % settings.SETTINGS_MODULE ) self.stream.write("SOURCE_VERSION = %r\n" % str(current_version)) self.stream.write( """ from decimal import Decimal from datetime import datetime as dt from datetime import time, date from django.conf import settings # from django.contrib.contenttypes.models import ContentType from lino.utils.dpy import create_mti_child from lino.utils.dpy import DpyLoader from lino.core.utils import resolve_model def new_content_type_id(m): if m is None: return m ct = settings.SITE.modules.contenttypes.ContentType.objects.get_for_model(m) if ct is None: return None return ct.pk """ ) s = ",".join(["%s=values[%d]" % (lng.name, lng.index) for lng in settings.SITE.languages]) self.stream.write( ''' def bv2kw(fieldname, values): """ Needed if `Site.languages` changed between dumpdata and loaddata """ return settings.SITE.babelkw(fieldname, %s) ''' % s ) self.models = sorted_models_list() if settings.SITE.is_installed("contenttypes"): from django.contrib.contenttypes.models import ContentType self.models = [m for m in self.models if not issubclass(m, ContentType)] if settings.SITE.is_installed("sessions"): from django.contrib.sessions.models import Session self.models = [m for m in self.models if not issubclass(m, Session)] for model in self.models: self.stream.write('%s = resolve_model("%s")\n' % (full_model_name(model, "_"), full_model_name(model))) self.stream.write("\n") self.models = self.sort_models(self.models) self.stream.write("\n") for model in self.models: if AFTER17: fields = [f for f in model._meta.get_fields() if f.concrete and f.model is model] else: fields = [f for f, m in model._meta.get_fields_with_model() if m is None] for f in fields: if getattr(f, "auto_now_add", False): raise Exception( "%s.%s.auto_now_add is True : values will be lost!" % (full_model_name(model), f.name) ) # ~ fields = model._meta.local_fields # ~ fields = [f for f in model._meta.fields if f.serialize] # ~ fields = [f for f in model._meta.local_fields if f.serialize] self.stream.write( "def create_%s(%s):\n" % ( model._meta.db_table, ", ".join([f.attname for f in fields if not getattr(f, "_lino_babel_field", False)]), ) ) for f in fields: if isinstance(f, models.DecimalField): self.stream.write(" if %s is not None: %s = Decimal(%s)\n" % (f.attname, f.attname, f.attname)) elif isinstance(f, ChoiceListField): lstname = "settings.SITE.modules.{0}.{1}".format(f.choicelist.app_label, f.choicelist.__name__) ln = " if {0}: {0} = {1}.get_by_value({0})\n" self.stream.write(ln.format(f.attname, lstname)) elif is_pointer_to_contenttype(f): self.stream.write(" %s = new_content_type_id(%s)\n" % (f.attname, f.attname)) if model._meta.parents: if len(model._meta.parents) != 1: msg = "%s : model._meta.parents is %r" % (model, model._meta.parents) raise Exception(msg) pm, pf = list(model._meta.parents.items())[0] child_fields = [f for f in fields if f != pf] if child_fields: attrs = "," + ",".join(["%s=%s" % (f.attname, f.attname) for f in child_fields]) else: attrs = "" self.stream.write( " return create_mti_child(%s, %s, %s%s)\n" % (full_model_name(pm, "_"), pf.attname, full_model_name(model, "_"), attrs) ) else: self.stream.write(" kw = dict()\n") for f in fields: if getattr(f, "_lino_babel_field", False): continue elif isinstance(f, (BabelCharField, BabelTextField)): self.stream.write( " if %s is not None: kw.update(bv2kw(%r,%s))\n" % (f.attname, f.attname, f.attname) ) else: self.stream.write(" kw.update(%s=%s)\n" % (f.attname, f.attname)) self.stream.write(" return %s(**kw)\n\n" % full_model_name(model, "_")) self.stream.write("\n") # ~ used_models = set() self.stream.write( """ def main(): loader = DpyLoader(globals()) from django.core.management import call_command # call_command('initdb', interactive=False) call_command('initdb') os.chdir(os.path.dirname(__file__)) loader.initialize() """ ) for model in progress.bar(self.models): filename = "%s.py" % model._meta.db_table filename = os.path.join(self.output_dir, filename) # puts("Writing {0}...".format(filename)) stream = file(filename, "wt") stream.write("# -*- coding: UTF-8 -*-\n") qs = model.objects.all() try: stream.write('logger.info("Loading %d objects to table %s...")\n' % (qs.count(), model._meta.db_table)) if AFTER17: fields = [f for f in model._meta.get_fields() if f.concrete and f.model is model] else: fields = [f for f, m in model._meta.get_fields_with_model() if m is None] fields = [f for f in fields if not getattr(f, "_lino_babel_field", False)] stream.write("# fields: %s\n" % ", ".join([f.name for f in fields])) for obj in qs: self.count_objects += 1 # ~ used_models.add(model) stream.write( "loader.save(create_%s(%s))\n" % (obj._meta.db_table, ",".join([self.value2string(obj, f) for f in fields])) ) stream.write("\n") stream.write("loader.flush_deferred_objects()\n") except ProgrammingError as e: if not self.options["tolerate"]: raise stream.write("\n") logger.warning("Tolerating database error %s in %s", e, model._meta.db_table) msg = ("The data of this table has not been dumped" "because an error {0} occured.").format(e) stream.write('raise Exception("{0}")\n'.format(msg)) stream.close() # ~ self.stream.write('\nfilename = os.path.join(os.path.dirname(__file__),"%s.py")\n' % ) self.stream.write(' execfile("%s.py")\n' % model._meta.db_table) self.stream.write(" loader.finalize()\n") # self.stream.write( # ' logger.info("Loaded %d objects",loader.count_objects)\n') self.stream.write( """ if __name__ == '__main__': main() """ ) # ~ self.stream.write('\nsettings.SITE.load_from_file(globals())\n') self.stream.close()
def make_remote_field(model, name): parts = name.split('__') if len(parts) == 1: return # It's going to be a RemoteField # logger.warning("20151203 RemoteField %s in %s", name, cls) from lino.core import store cls = model field_chain = [] editable = False for n in parts: if model is None: raise Exception( "Invalid remote field {0} for {1}".format(name, cls)) if isinstance(model, six.string_types): # Django 1.9 no longer resolves the # rel.model of ForeignKeys on abstract # models, so we do it here. model = resolve_model(model) # logger.warning("20151203 %s", model) fld = model.get_data_elem(n) if fld is None: raise Exception( "Invalid RemoteField %s.%s (no field %s in %s)" % (full_model_name(model), name, n, full_model_name(model))) # make sure that the atomizer gets created. store.get_atomizer(model, fld, fld.name) field_chain.append(fld) if isinstance(fld, models.OneToOneRel): editable = True if getattr(fld, 'remote_field', None): model = fld.remote_field.model elif getattr(fld, 'rel', None): raise Exception("20180712") model = fld.rel.model else: model = None def getter(obj, ar=None): try: for fld in field_chain: if obj is None: return None obj = fld._lino_atomizer.full_value_from_object( obj, ar) return obj except Exception as e: # raise msg = "Error while computing {}: {} ({} in {})" raise Exception(msg.format( name, e, fld, field_chain)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return None if not editable: return RemoteField(getter, name, fld) def setter(obj, value): # logger.info("20180712 %s setter() %s", name, value) # all intermediate fields are OneToOneRel target = obj try: for fld in field_chain: # print("20180712a %s" % fld) if isinstance(fld, models.OneToOneRel): reltarget = getattr(target, fld.name, None) if reltarget is None: rkw = { fld.field.name: target} # print( # "20180712 create {}({})".format( # fld.related_model, rkw)) reltarget = fld.related_model(**rkw) reltarget.full_clean() reltarget.save() setattr(target, fld.name, reltarget) target.full_clean() target.save() # print("20180712b {}.{} = {}".format( # target, fld.name, reltarget)) target = reltarget else: setattr(target, fld.name, value) target.full_clean() target.save() # print( # "20180712c setattr({},{},{}".format( # target, fld.name, value)) return True except Exception as e: raise e.__class__( "Error while setting %s: %s" % (name, e)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return False return RemoteField(getter, name, fld, setter)
def write_files(self): puts("Writing {0}...".format(self.main_file)) self.stream = open(self.main_file, 'wt') current_version = settings.SITE.version self.stream.write('''\ #!/usr/bin/env python # -*- coding: UTF-8 -*- # This is a Python dump created using dump2py. # DJANGO_SETTINGS_MODULE was %r, TIME_ZONE was %r. ''' % (settings.SETTINGS_MODULE, settings.TIME_ZONE)) self.stream.write(''' from __future__ import unicode_literals import logging logger = logging.getLogger('%s') ''' % __name__) self.stream.write('SOURCE_VERSION = %r\n' % str(current_version)) self.stream.write(''' import os import six from decimal import Decimal from datetime import datetime from datetime import time, date from django.conf import settings from django.utils.timezone import make_aware, utc from django.core.management import call_command # from django.contrib.contenttypes.models import ContentType from lino.utils.dpy import create_mti_child from lino.utils.dpy import DpyLoader from lino.core.utils import resolve_model if settings.USE_TZ: def dt(*args): return make_aware(datetime(*args), timezone=utc) else: def dt(*args): return datetime(*args) def new_content_type_id(m): if m is None: return m ct = settings.SITE.models.contenttypes.ContentType.objects.get_for_model(m) if ct is None: return None return ct.pk def pmem(): # Thanks to https://stackoverflow.com/questions/938733/total-memory-used-by-python-process process = psutil.Process(os.getpid()) print(process.memory_info().rss) def execfile(fn, *args): logger.info("Execute file %s ...", fn) six.exec_(compile(open(fn, "rb").read(), fn, 'exec'), *args) # pmem() # requires pip install psutil ''') s = ','.join([ '%s=values[%d]' % (lng.name, lng.index) for lng in settings.SITE.languages ]) self.stream.write(''' def bv2kw(fieldname, values): """ Needed if `Site.languages` changed between dumpdata and loaddata """ return settings.SITE.babelkw(fieldname, %s) ''' % s) self.models = sorted_models_list() if settings.SITE.is_installed('contenttypes'): from django.contrib.contenttypes.models import ContentType self.models = [ m for m in self.models if not issubclass(m, ContentType) ] if settings.SITE.is_installed('sessions'): from django.contrib.sessions.models import Session self.models = [ m for m in self.models if not issubclass(m, Session) ] for model in self.models: self.stream.write( '%s = resolve_model("%s")\n' % (full_model_name(model, '_'), full_model_name(model))) self.stream.write('\n') self.models = self.sort_models(self.models) self.stream.write('\n') for model in self.models: write_create_function(model, self.stream) self.stream.write('\n') #~ used_models = set() self.stream.write(""" def main(args): loader = DpyLoader(globals(), quick=args.quick) from django.core.management import call_command call_command('initdb', interactive=args.interactive) os.chdir(os.path.dirname(__file__)) loader.initialize() args = (globals(), locals()) """) max_row_count = self.options['max_row_count'] for model in progress.bar(self.models): try: qs = model.objects.all() total_count = qs.count() except DatabaseError as e: self.database_errors += 1 if not self.options['tolerate']: raise self.stream.write('\n') logger.warning("Tolerating database error %s in %s", e, model._meta.db_table) msg = ("The data of table {0} has not been dumped" "because an error {1} occured.").format( model._meta.db_table, e) self.stream.write('raise Exception("{0}")\n'.format(msg)) continue fields = [ f for f in model._meta.get_fields() if f.concrete and f.model is model ] fields = [ f for f in fields if not getattr(f, '_lino_babel_field', False) ] chunks = [] # list of tuples (i, filename, queryset) if total_count > max_row_count: num_files = (total_count // max_row_count) + 1 for i in range(num_files): o1 = max_row_count * i o2 = max_row_count * (i + 1) t = (i + 1, '%s_%d.py' % (model._meta.db_table, i + 1), qs[o1:o2]) chunks.append(t) else: chunks.append((1, '%s.py' % model._meta.db_table, qs)) for i, filename, qs in chunks: self.stream.write(' execfile("%s", *args)\n' % filename) filename = os.path.join(self.output_dir, filename) # puts("Writing {0}...".format(filename)) # stream = file(filename, 'wt') stream = open(filename, 'wt') stream.write('# -*- coding: UTF-8 -*-\n') txt = "%d objects" % total_count if len(chunks) > 1: txt += " (part %d of %d)" % (i, len(chunks)) stream.write('logger.info("Loading %s to table %s...")\n' % (txt, model._meta.db_table)) stream.write("# fields: %s\n" % ', '.join([f.name for f in fields])) for obj in qs: self.count_objects += 1 #~ used_models.add(model) stream.write( 'loader.save(create_%s(%s))\n' % (obj._meta.db_table, ','.join( [self.value2string(obj, f) for f in fields]))) stream.write('\n') if i == len(chunks): stream.write('loader.flush_deferred_objects()\n') stream.close() #~ self.stream.write('\nfilename = os.path.join(os.path.dirname(__file__),"%s.py")\n' % ) self.stream.write(' loader.finalize()\n') # 20180416 why was the following message commented out? # reactivated it because otherwise we have no log entry when # the process has finished. self.stream.write( ' logger.info("Loaded %d objects", loader.count_objects)\n') self.stream.write(" call_command('resetsequences')\n") self.stream.write(""" if __name__ == '__main__': import argparse parser = argparse.ArgumentParser(description='Restore the data.') parser.add_argument('--noinput', dest='interactive', action='store_false', default=True, help="Don't ask for confirmation before flushing the database.") parser.add_argument('--quick', dest='quick', action='store_true',default=False, help='Do not call full_clean() on restored instances.') args = parser.parse_args() main(args) """) #~ self.stream.write('\nsettings.SITE.load_from_file(globals())\n') self.stream.close()
def write_files(self): puts("Writing {0}...".format(self.main_file)) self.stream = open(self.main_file, 'wt') current_version = settings.SITE.version self.stream.write('''\ #!/usr/bin/env python # -*- coding: UTF-8 -*- # This is a Python dump created using dump2py. # DJANGO_SETTINGS_MODULE was %r, TIME_ZONE was %r. ''' % (settings.SETTINGS_MODULE, settings.TIME_ZONE)) self.stream.write(''' from __future__ import unicode_literals import logging logger = logging.getLogger('%s') import os ''' % __name__) self.stream.write('SOURCE_VERSION = %r\n' % str(current_version)) self.stream.write(''' from decimal import Decimal from datetime import datetime from datetime import time, date from django.conf import settings from django.utils.timezone import make_aware # from django.contrib.contenttypes.models import ContentType from lino.utils.dpy import create_mti_child from lino.utils.dpy import DpyLoader from lino.core.utils import resolve_model if settings.USE_TZ: def dt(*args): return make_aware(datetime(*args)) else: def dt(*args): return datetime(*args) def new_content_type_id(m): if m is None: return m ct = settings.SITE.models.contenttypes.ContentType.objects.get_for_model(m) if ct is None: return None return ct.pk ''') s = ','.join([ '%s=values[%d]' % (lng.name, lng.index) for lng in settings.SITE.languages ]) self.stream.write(''' def bv2kw(fieldname, values): """ Needed if `Site.languages` changed between dumpdata and loaddata """ return settings.SITE.babelkw(fieldname, %s) ''' % s) self.models = sorted_models_list() if settings.SITE.is_installed('contenttypes'): from django.contrib.contenttypes.models import ContentType self.models = [ m for m in self.models if not issubclass(m, ContentType) ] if settings.SITE.is_installed('sessions'): from django.contrib.sessions.models import Session self.models = [ m for m in self.models if not issubclass(m, Session) ] for model in self.models: self.stream.write( '%s = resolve_model("%s")\n' % (full_model_name(model, '_'), full_model_name(model))) self.stream.write('\n') self.models = self.sort_models(self.models) self.stream.write('\n') for model in self.models: fields = [ f for f in model._meta.get_fields() if f.concrete and f.model is model ] for f in fields: if getattr(f, 'auto_now_add', False): raise Exception( "%s.%s.auto_now_add is True : values will be lost!" % (full_model_name(model), f.name)) #~ fields = model._meta.local_fields #~ fields = [f for f in model._meta.fields if f.serialize] #~ fields = [f for f in model._meta.local_fields if f.serialize] self.stream.write('def create_%s(%s):\n' % (model._meta.db_table, ', '.join([ f.attname for f in fields if not getattr(f, '_lino_babel_field', False) ]))) for f in fields: if isinstance(f, models.DecimalField): self.stream.write( ' if %s is not None: %s = Decimal(%s)\n' % (f.attname, f.attname, f.attname)) elif isinstance(f, ChoiceListField): lstname = 'settings.SITE.modules.{0}.{1}'.format( f.choicelist.app_label, f.choicelist.__name__) ln = ' if {0}: {0} = {1}.get_by_value({0})\n' self.stream.write(ln.format(f.attname, lstname)) elif is_pointer_to_contenttype(f): self.stream.write(' %s = new_content_type_id(%s)\n' % (f.attname, f.attname)) if model._meta.parents: if len(model._meta.parents) != 1: msg = "%s : model._meta.parents is %r" % ( model, model._meta.parents) raise Exception(msg) pm, pf = list(model._meta.parents.items())[0] child_fields = [f for f in fields if f != pf] if child_fields: attrs = ',' + ','.join([ '%s=%s' % (f.attname, f.attname) for f in child_fields ]) else: attrs = '' self.stream.write( ' return create_mti_child(%s, %s, %s%s)\n' % (full_model_name(pm, '_'), pf.attname, full_model_name(model, '_'), attrs)) else: self.stream.write(" kw = dict()\n") for f in fields: if getattr(f, '_lino_babel_field', False): continue elif isinstance(f, (BabelCharField, BabelTextField)): self.stream.write( ' if %s is not None: kw.update(bv2kw(%r,%s))\n' % (f.attname, f.attname, f.attname)) else: self.stream.write(' kw.update(%s=%s)\n' % (f.attname, f.attname)) self.stream.write(' return %s(**kw)\n\n' % full_model_name(model, '_')) self.stream.write('\n') #~ used_models = set() self.stream.write(""" def main(args): loader = DpyLoader(globals()) from django.core.management import call_command call_command('initdb', interactive=args.interactive) os.chdir(os.path.dirname(__file__)) loader.initialize() """) for model in progress.bar(self.models): filename = '%s.py' % model._meta.db_table filename = os.path.join(self.output_dir, filename) # puts("Writing {0}...".format(filename)) # stream = file(filename, 'wt') stream = open(filename, 'wt') stream.write('# -*- coding: UTF-8 -*-\n') qs = model.objects.all() try: stream.write( 'logger.info("Loading %d objects to table %s...")\n' % (qs.count(), model._meta.db_table)) fields = [ f for f in model._meta.get_fields() if f.concrete and f.model is model ] fields = [ f for f in fields if not getattr(f, '_lino_babel_field', False) ] stream.write("# fields: %s\n" % ', '.join([f.name for f in fields])) for obj in qs: self.count_objects += 1 #~ used_models.add(model) stream.write( 'loader.save(create_%s(%s))\n' % (obj._meta.db_table, ','.join( [self.value2string(obj, f) for f in fields]))) stream.write('\n') stream.write('loader.flush_deferred_objects()\n') except DatabaseError as e: self.database_errors += 1 if not self.options['tolerate']: raise stream.write('\n') logger.warning("Tolerating database error %s in %s", e, model._meta.db_table) msg = ("The data of this table has not been dumped" "because an error {0} occured.").format(e) stream.write('raise Exception("{0}")\n'.format(msg)) stream.close() #~ self.stream.write('\nfilename = os.path.join(os.path.dirname(__file__),"%s.py")\n' % ) self.stream.write(' execfile("%s.py")\n' % model._meta.db_table) self.stream.write(' loader.finalize()\n') # self.stream.write( # ' logger.info("Loaded %d objects",loader.count_objects)\n') self.stream.write(""" if __name__ == '__main__': import argparse parser = argparse.ArgumentParser(description='Restore the data.') parser.add_argument('--noinput', dest='interactive', action='store_false', default=True, help="Don't ask for confirmation before flushing the database.") args = parser.parse_args() main(args) """) #~ self.stream.write('\nsettings.SITE.load_from_file(globals())\n') self.stream.close()
def get_rst(self): #~ from actordoc import get_actor_description #~ from django.conf import settings #~ from djangosite.dbutils import set_language with translation.override(self.language): level, cls = resolve_name(self.content[0]) if isinstance(cls, models.Field): fld = cls s = '' name = str(fld.model) + '.' + fld.name title = force_unicode(fld.verbose_name).strip() s += "\n.. index::\n single: " s += unicode( _('%(field)s (field in %(model)s)') % dict(field=title, model=model_ref(fld.model))) s += '\n\n' s += rstgen.header(level, _("%s (field)") % title) if len(self.content) > 1: s += '\n'.join(self.content[1:]) s += '\n\n' return s if isinstance(cls, Plugin): s = '' title = unicode(cls.verbose_name) s += "\n.. index::\n single: " s += unicode(_('%s (app)') % title) s += '\n\n.. _' + name + ':\n' s += '\n' s += rstgen.header(level, _("%s (app)") % title) return s if not isinstance(cls, type): raise Exception("%s is not an actor." % self.content[0]) if issubclass(cls, models.Model): model = cls s = '' name = model_name(model).lower() title = force_unicode(model._meta.verbose_name) s += "\n.. index::\n single: " s += unicode( _('%(model)s (model in %(app)s)') % dict(model=title, app=model._meta.app_label)) s += '\n\n' s += '\n\n.. _' + name + ':\n' s += '\n' s += rstgen.header(level, _("%s (model)") % title) s += '\n' s += '\n:Internal name: ``%s``\n' % full_model_name(cls) s += '\n:Implemented by: %s\n' % typeref(cls) s += '\n' if len(self.content) > 1: s += '\n'.join(self.content[1:]) s += '\n\n' model_reports = [ r for r in dbtables.master_reports if r.model is cls ] model_reports += [ r for r in dbtables.slave_reports if r.model is cls ] s += rstgen.boldheader( _("Views on %s") % cls._meta.verbose_name) s += actors_overview_ul(model_reports) s += rstgen.boldheader( _("Fields in %s") % cls._meta.verbose_name) s += fields_ul(cls._meta.fields) action_list = cls.get_default_table().get_actions() action_list = [ ba for ba in action_list if not isinstance(ba.action, IGNORED_ACTIONS) ] if action_list: s += '\n' s += rstgen.boldheader( _("Actions on %s") % cls._meta.verbose_name) s += actions_ul(action_list) slave_tables = getattr(cls, '_lino_slaves', {}).values() if slave_tables: s += rstgen.boldheader( _("Tables referring to %s") % cls._meta.verbose_name) s += actors_overview_ul(slave_tables) return s if issubclass(cls, actors.Actor): title = force_unicode(cls.label or cls.title) indextext = _('%(actor)s (view in %(app)s)') % dict( actor=title, app=cls.app_label) name = actor_name(cls) #~ if name == 'welfare.reception.waitingvisitors': #~ self.debug = True #~ print(20130907, name) self.index_entries.append(('single', indextext, name, '')) #~ self.add_ref_target(name,name) s = '' s += '\n\n.. _%s:\n\n' % name s += rstgen.header(level, _("%s (view)") % title) s += '\n:Internal name: ``%s`` (%s)\n' % (cls, typeref(cls)) if len(self.content) > 1: s += '\n'.join(self.content[1:]) s += '\n\n' s += '\n\n' s += get_actor_description(cls) s += '\n\n' return s raise Exception("Cannot handle actor %r." % cls)
def get_data_elem(cls, name): """Return the named data element. This can be a database field, a :class:`lino.core.fields.RemoteField`, a :class:`lino.core.fields.VirtualField` or a Django-style virtual field (GenericForeignKey). """ #~ logger.info("20120202 get_data_elem %r,%r",model,name) if not name.startswith('__'): parts = name.split('__') if len(parts) > 1: # It's going to be a RemoteField # logger.warning("20151203 RemoteField %s in %s", name, cls) from lino.core import store model = cls field_chain = [] editable = False for n in parts: if model is None: raise Exception( "Invalid remote field {0} for {1}".format( name, cls)) if isinstance(model, six.string_types): # Django 1.9 no longer resolves the # rel.model of ForeignKeys on abstract # models, so we do it here. model = resolve_model(model) # logger.warning("20151203 %s", model) fld = model.get_data_elem(n) if fld is None: raise Exception( "Invalid RemoteField %s.%s (no field %s in %s)" % (full_model_name(model), name, n, full_model_name(model))) # make sure that the atomizer gets created. store.get_atomizer(model, fld, fld.name) field_chain.append(fld) if isinstance(fld, models.OneToOneRel): editable = True if getattr(fld, 'remote_field', None): model = fld.remote_field.model elif getattr(fld, 'rel', None): raise Exception("20180712") model = fld.rel.model else: model = None def getter(obj, ar=None): try: for fld in field_chain: if obj is None: return None obj = fld._lino_atomizer.full_value_from_object( obj, ar) return obj except Exception as e: # raise msg = "Error while computing {}: {} ({} in {})" raise Exception(msg.format(name, e, fld, field_chain)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return None if not editable: return fields.RemoteField(getter, name, fld) def setter(obj, value): # logger.info("20180712 %s setter() %s", name, value) # all intermediate fields are OneToOneRel target = obj try: for fld in field_chain: # print("20180712a %s" % fld) if isinstance(fld, models.OneToOneRel): reltarget = getattr(target, fld.name, None) if reltarget is None: rkw = {fld.field.name: target} # print( # "20180712 create {}({})".format( # fld.related_model, rkw)) reltarget = fld.related_model(**rkw) reltarget.full_clean() reltarget.save() setattr(target, fld.name, reltarget) target.full_clean() target.save() # print("20180712b {}.{} = {}".format( # target, fld.name, reltarget)) target = reltarget else: setattr(target, fld.name, value) target.full_clean() target.save() # print( # "20180712c setattr({},{},{}".format( # target, fld.name, value)) return True except Exception as e: raise Exception("Error while setting %s: %s" % (name, e)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return False return fields.RemoteField(getter, name, fld, setter) try: return cls._meta.get_field(name) except models.FieldDoesNotExist: pass v = get_class_attr(cls, name) if v is not None: return v for vf in cls._meta.private_fields: if vf.name == name: return vf
def __init__(self, model, *args, **kwargs): self.model = model self.template_name = "noi/{0}.html".format(full_model_name(model)) super(TemplateView, self).__init__(*args, **kwargs)
def get_data_elem(cls, name): """Return the named data element. This can be a database field, a :class:`lino.core.fields.RemoteField`, a :class:`lino.core.fields.VirtualField` or a Django-style virtual field (GenericForeignKey). """ #~ logger.info("20120202 get_data_elem %r,%r",model,name) if not name.startswith('__'): parts = name.split('__') if len(parts) > 1: # It's going to be a RemoteField # logger.warning("20151203 RemoteField %s in %s", name, cls) from lino.core import store model = cls field_chain = [] for n in parts: if model is None: raise Exception( "Invalid remote field {0} for {1}".format(name, cls)) if isinstance(model, six.string_types): model = resolve_model(model) # logger.warning("20151203 %s", model) # Django 1.9 no longer resolves the # rel.model of ForeignKeys on abstract # models. # ~ 20130508 model.get_default_table().get_handle() # make sure that all atomizers of those fields get created. fld = model.get_data_elem(n) if fld is None: # raise Exception("Part %s of %s got None" % (n,model)) raise Exception( "Invalid RemoteField %s.%s (no field %s in %s)" % (full_model_name(model), name, n, full_model_name(model))) # make sure that the atomizer gets created. store.get_atomizer(model, fld, fld.name) field_chain.append(fld) if getattr(fld, 'rel', None): if AFTER18: model = fld.rel.model else: model = fld.rel.to else: model = None def func(obj, ar=None): try: for fld in field_chain: if obj is None: return obj obj = fld._lino_atomizer.full_value_from_object( obj, ar) return obj except Exception as e: raise Exception( "Error while computing %s: %s" % (name, e)) # ~ if False: # only for debugging if True: # see 20130802 logger.exception(e) return str(e) return None return fields.RemoteField(func, name, fld) try: return cls._meta.get_field(name) except models.FieldDoesNotExist: pass v = get_class_attr(cls, name) if v is not None: return v for vf in cls._meta.virtual_fields: if vf.name == name: return vf
def serialize(self, queryset, **options): from django.contrib.sessions.models import Session from django.contrib.contenttypes.models import ContentType self.options = options self.stream = options.get("stream", StringIO()) self.selected_fields = options.get("fields") self.use_natural_keys = options.get("use_natural_keys", False) if self.write_preamble: current_version = settings.SITE.version if '+' in current_version: logger.warning( "Dumpdata from intermediate version %s" % current_version) self.stream.write('# -*- coding: UTF-8 -*-\n') self.stream.write('''\ """ This is a `Python dump created using %s. ''' % settings.SITE.using_text()) #~ self.stream.write(settings.SITE.welcome_text()) self.stream.write(''' """ from __future__ import unicode_literals ''') self.stream.write('SOURCE_VERSION = %r\n' % str(current_version)) self.stream.write('from decimal import Decimal\n') self.stream.write('from datetime import datetime as dt\n') self.stream.write('from datetime import time,date\n') self.stream.write('from lino.utils.dpy import create_mti_child\n') self.stream.write('from lino.utils.dbutils import resolve_model\n') self.stream.write( 'from lino.modlib.gfks.models import ContentType\n') self.stream.write('from django.conf import settings\n') self.stream.write(''' def new_content_type_id(m): if m is None: return m # if not fmn: return None # m = resolve_model(fmn) ct = ContentType.objects.get_for_model(m) if ct is None: return None return ct.pk ''') #~ s = ','.join([ #~ '%s=values[%d]' % (k,i) #~ for i,k in enumerate(settings.SITE.AVAILABLE_LANGUAGES)]) s = ','.join([ '%s=values[%d]' % (lng.name, lng.index) for lng in settings.SITE.languages]) self.stream.write(''' def bv2kw(fieldname,values): """ Needed if `Site.languages` changed between dumpdata and loaddata """ return settings.SITE.babelkw(fieldname,%s) ''' % s) #~ model = queryset.model if self.models is None: self.models = sorted_models_list() # models.get_models() if self.write_preamble: for model in self.models: self.stream.write('%s = resolve_model("%s")\n' % ( full_model_name(model, '_'), full_model_name(model))) self.stream.write('\n') for model in self.models: fields = [f for f, m in model._meta.get_fields_with_model() if m is None] for f in fields: if getattr(f, 'auto_now_add', False): raise Exception("%s.%s.auto_now_add is True : values will be lost!" % ( full_model_name(model), f.name)) field_names = [f.attname for f in fields if not getattr(f, '_lino_babel_field', False)] self.stream.write('def create_%s(%s):\n' % ( model._meta.db_table, ', '.join(field_names))) if model._meta.parents: if len(model._meta.parents) != 1: msg = "%s : model._meta.parents is %r" % ( model, model._meta.parents) raise Exception(msg) pm, pf = list(model._meta.parents.items())[0] child_fields = [f for f in fields if f != pf] if child_fields: attrs = ', ' + ', '.join([ '%s=%s' % (f.attname, f.attname) for f in child_fields]) else: attrs = '' tpl = ' return create_mti_child(%s, %s, %s%s)\n' self.stream.write(tpl % ( full_model_name(pm, '_'), pf.attname, full_model_name(model, '_'), attrs)) else: self.stream.write(" kw = dict()\n") for f in fields: if getattr(f, '_lino_babel_field', False): continue elif isinstance(f, (BabelCharField, BabelTextField)): tpl = ' if %s is not None:' tpl += ' kw.update(bv2kw(%r, %s))\n' self.stream.write( tpl % (f.attname, f.attname, f.attname)) else: if isinstance(f, models.DecimalField): self.stream.write( ' if %s is not None: %s = Decimal(%s)\n' % ( f.attname, f.attname, f.attname)) elif isinstance(f, ChoiceListField): lstname = 'settings.SITE.modules.{0}.{1}'.format( f.choicelist.app_label, f.choicelist.__name__) ln = ' if {0}: {0} = {1}.get_by_value({0})\n' self.stream.write(ln.format(f.attname, lstname)) elif isinstance(f, ForeignKey): if f.rel.model is ContentType: self.stream.write( ' %s = new_content_type_id(%s)\n' % ( f.attname, f.attname)) self.stream.write( ' kw.update(%s=%s)\n' % (f.attname, f.attname)) self.stream.write(' return %s(**kw)\n\n' % full_model_name(model, '_')) #~ self.start_serialization() self.stream.write('\n') model = None all_models = [] for obj in queryset: if isinstance(obj, ContentType): continue if isinstance(obj, Session): continue if obj.__class__ != model: model = obj.__class__ if model in all_models: raise Exception("%s instances weren't grouped!" % model) all_models.append(model) self.stream.write('\ndef %s_objects():\n' % model._meta.db_table) fields = [f for f, m in model._meta.get_fields_with_model() if m is None] fields = [ f for f in fields if not getattr(f, '_lino_babel_field', False)] self.stream.write(' yield create_%s(%s)\n' % ( obj._meta.db_table, ','.join([self.value2string(obj, f) for f in fields]))) self.stream.write('\n\ndef objects():\n') all_models = self.sort_models(all_models) for model in all_models: #~ self.stream.write(' for o in %s_objects(): yield o\n' % model._meta.db_table) self.stream.write(' yield %s_objects()\n' % model._meta.db_table)
def test_controllables(self): found = [] for M in rt.models_by_base(Controllable): found.append(full_model_name(M)) expected = """cal.Event cal.Task checkdata.Problem comments.Comment comments.Mention excerpts.Excerpt notes.Note notify.Message uploads.Upload """.split() self.assertEqual(found, expected) Person = rt.models.contacts.Person Note = rt.models.notes.Note Excerpt = rt.models.excerpts.Excerpt ExcerptType = rt.models.excerpts.ExcerptType ContentType = rt.models.contenttypes.ContentType self.assertEqual(len(Person.allow_cascaded_delete), 0) self.assertEqual(len(Note.allow_cascaded_delete), 0) self.assertEqual(len(Excerpt.allow_cascaded_delete), 1) doe = create(Person, first_name="John", last_name="Doe") note = create(Note, owner=doe, body="John Doe is a fink!") ct = ContentType.objects.get_for_model(Note) etype = create(ExcerptType, name="Note", content_type=ct) excerpt = create(Excerpt, owner=note, excerpt_type=etype) self.assertEqual(Person.objects.count(), 1) self.assertEqual(Note.objects.count(), 1) self.assertEqual(Excerpt.objects.count(), 1) ar = rt.models.notes.Notes.request() s = ar.to_rst(column_names="id owner") self.assertEqual( s, """\ ==== =============== ID Controlled by ---- --------------- 1 *John Doe* ==== =============== """) ar = rt.models.excerpts.Excerpts.request() s = ar.to_rst(column_names="id owner") self.assertEqual( s, """\ ==== =============== ID Controlled by ---- --------------- 1 *Note #1* ==== =============== """) self.assertEqual(excerpt.disable_delete(), None) self.assertEqual(note.disable_delete(), None) self.assertEqual(doe.disable_delete(), None) # it is not "Cannot delete John Doe because 1 Notes refer to # it." because Note.owner is nullable. note.delete() self.assertEqual(Excerpt.objects.count(), 0) self.assertEqual(ExcerptType.objects.count(), 5)
def write_files(self): puts("Writing {0}...".format(self.main_file)) self.stream = open(self.main_file, 'wt') current_version = settings.SITE.version self.stream.write('''\ #!/usr/bin/env python # -*- coding: UTF-8 -*- # This is a Python dump created using dump2py. # DJANGO_SETTINGS_MODULE was %r, TIME_ZONE was %r. ''' % (settings.SETTINGS_MODULE, settings.TIME_ZONE)) self.stream.write(''' from __future__ import unicode_literals import logging logger = logging.getLogger('%s') ''' % __name__) self.stream.write('SOURCE_VERSION = %r\n' % str(current_version)) self.stream.write(''' import os import six from decimal import Decimal from datetime import datetime from datetime import time, date from django.conf import settings from django.utils.timezone import make_aware, utc from django.core.management import call_command # from django.contrib.contenttypes.models import ContentType from lino.utils.dpy import create_mti_child from lino.utils.dpy import DpyLoader from lino.core.utils import resolve_model if settings.USE_TZ: def dt(*args): return make_aware(datetime(*args), timezone=utc) else: def dt(*args): return datetime(*args) def new_content_type_id(m): if m is None: return m ct = settings.SITE.models.contenttypes.ContentType.objects.get_for_model(m) if ct is None: return None return ct.pk def pmem(): # Thanks to https://stackoverflow.com/questions/938733/total-memory-used-by-python-process process = psutil.Process(os.getpid()) print(process.memory_info().rss) def execfile(fn, *args): logger.info("Execute file %s ...", fn) six.exec_(compile(open(fn, "rb").read(), fn, 'exec'), *args) # pmem() # requires pip install psutil ''') s = ','.join([ '%s=values[%d]' % (lng.name, lng.index) for lng in settings.SITE.languages]) self.stream.write(''' def bv2kw(fieldname, values): """ Needed if `Site.languages` changed between dumpdata and loaddata """ return settings.SITE.babelkw(fieldname, %s) ''' % s) self.models = sorted_models_list() if settings.SITE.is_installed('contenttypes'): from django.contrib.contenttypes.models import ContentType self.models = [m for m in self.models if not issubclass(m, ContentType)] if settings.SITE.is_installed('sessions'): from django.contrib.sessions.models import Session self.models = [m for m in self.models if not issubclass(m, Session)] for model in self.models: self.stream.write('%s = resolve_model("%s")\n' % ( full_model_name(model, '_'), full_model_name(model))) self.stream.write('\n') self.models = self.sort_models(self.models) self.stream.write('\n') for model in self.models: write_create_function(model, self.stream) self.stream.write('\n') #~ used_models = set() self.stream.write(""" def main(args): loader = DpyLoader(globals(), quick=args.quick) from django.core.management import call_command call_command('initdb', interactive=args.interactive) os.chdir(os.path.dirname(__file__)) loader.initialize() args = (globals(), locals()) """) max_row_count = self.options['max_row_count'] for model in progress.bar(self.models): try: qs = model.objects.all() total_count = qs.count() except DatabaseError as e: self.database_errors += 1 if not self.options['tolerate']: raise self.stream.write('\n') logger.warning("Tolerating database error %s in %s", e, model._meta.db_table) msg = ("The data of table {0} has not been dumped" "because an error {1} occured.").format( model._meta.db_table, e) self.stream.write('raise Exception("{0}")\n'.format(msg)) continue fields = [f for f in model._meta.get_fields() if f.concrete and f.model is model] fields = [ f for f in fields if not getattr(f, '_lino_babel_field', False)] chunks = [] # list of tuples (i, filename, queryset) if total_count > max_row_count: num_files = (total_count // max_row_count) + 1 for i in range(num_files): o1 = max_row_count * i o2 = max_row_count * (i+1) t = (i+1, '%s_%d.py' % (model._meta.db_table, i+1), qs[o1:o2]) chunks.append(t) else: chunks.append((1, '%s.py' % model._meta.db_table, qs)) for i, filename, qs in chunks: self.stream.write(' execfile("%s", *args)\n' % filename) filename = os.path.join(self.output_dir, filename) # puts("Writing {0}...".format(filename)) # stream = file(filename, 'wt') stream = open(filename, 'wt') stream.write('# -*- coding: UTF-8 -*-\n') txt = "%d objects" % total_count if len(chunks) > 1: txt += " (part %d of %d)" % (i, len(chunks)) stream.write( 'logger.info("Loading %s to table %s...")\n' % ( txt, model._meta.db_table)) stream.write( "# fields: %s\n" % ', '.join( [f.name for f in fields])) for obj in qs: self.count_objects += 1 #~ used_models.add(model) stream.write('loader.save(create_%s(%s))\n' % ( obj._meta.db_table, ','.join([self.value2string(obj, f) for f in fields]))) stream.write('\n') if i == len(chunks): stream.write('loader.flush_deferred_objects()\n') stream.close() #~ self.stream.write('\nfilename = os.path.join(os.path.dirname(__file__),"%s.py")\n' % ) self.stream.write( ' loader.finalize()\n') # 20180416 why was the following message commented out? # reactivated it because otherwise we have no log entry when # the process has finished. self.stream.write( ' logger.info("Loaded %d objects", loader.count_objects)\n') self.stream.write( " call_command('resetsequences')\n") self.stream.write(""" if __name__ == '__main__': import argparse parser = argparse.ArgumentParser(description='Restore the data.') parser.add_argument('--noinput', dest='interactive', action='store_false', default=True, help="Don't ask for confirmation before flushing the database.") parser.add_argument('--quick', dest='quick', action='store_true',default=False, help='Do not call full_clean() on restored instances.') args = parser.parse_args() main(args) """) #~ self.stream.write('\nsettings.SITE.load_from_file(globals())\n') self.stream.close()
def serialize(self, queryset, **options): self.options = options self.stream = options.get("stream", StringIO()) self.selected_fields = options.get("fields") self.use_natural_keys = options.get("use_natural_keys", False) if self.write_preamble: current_version = settings.SITE.version if '+' in current_version: logger.warning("Dumpdata from intermediate version %s" % current_version) self.stream.write('# -*- coding: UTF-8 -*-\n') self.stream.write('''\ """ This is a `Python dump created using %s. ''' % settings.SITE.using_text()) #~ self.stream.write(settings.SITE.welcome_text()) self.stream.write(''' """ from __future__ import unicode_literals ''') self.stream.write('SOURCE_VERSION = %r\n' % str(current_version)) self.stream.write('from decimal import Decimal\n') self.stream.write('from datetime import datetime as dt\n') self.stream.write('from datetime import time,date\n') self.stream.write('from lino.utils.dpy import create_mti_child\n') self.stream.write('from lino.utils.dbutils import resolve_model\n') self.stream.write( 'from lino.modlib.gfks.models import ContentType\n') self.stream.write('from django.conf import settings\n') self.stream.write(''' def new_content_type_id(m): if m is None: return m # if not fmn: return None # m = resolve_model(fmn) ct = ContentType.objects.get_for_model(m) if ct is None: return None return ct.pk ''') #~ s = ','.join([ #~ '%s=values[%d]' % (k,i) #~ for i,k in enumerate(settings.SITE.AVAILABLE_LANGUAGES)]) s = ','.join([ '%s=values[%d]' % (lng.name, lng.index) for lng in settings.SITE.languages ]) self.stream.write(''' def bv2kw(fieldname,values): """ Needed if `Site.languages` changed between dumpdata and loaddata """ return settings.SITE.babelkw(fieldname,%s) ''' % s) #~ model = queryset.model if self.models is None: self.models = sorted_models_list() # models.get_models() if self.write_preamble: for model in self.models: self.stream.write( '%s = resolve_model("%s")\n' % (full_model_name(model, '_'), full_model_name(model))) self.stream.write('\n') for model in self.models: fields = [ f for f, m in model._meta.get_fields_with_model() if m is None ] for f in fields: if getattr(f, 'auto_now_add', False): raise Exception( "%s.%s.auto_now_add is True : values will be lost!" % (full_model_name(model), f.name)) field_names = [ f.attname for f in fields if not getattr(f, '_lino_babel_field', False) ] self.stream.write('def create_%s(%s):\n' % (model._meta.db_table, ', '.join(field_names))) if model._meta.parents: if len(model._meta.parents) != 1: msg = "%s : model._meta.parents is %r" % ( model, model._meta.parents) raise Exception(msg) pm, pf = model._meta.parents.items()[0] child_fields = [f for f in fields if f != pf] if child_fields: attrs = ',' + ','.join([ '%s=%s' % (f.attname, f.attname) for f in child_fields ]) else: attrs = '' tpl = ' return create_mti_child(%s, %s, %s%s)\n' self.stream.write(tpl % (full_model_name( pm, '_'), pf.attname, full_model_name(model, '_'), attrs)) else: self.stream.write(" kw = dict()\n") for f in fields: if getattr(f, '_lino_babel_field', False): continue elif isinstance(f, (BabelCharField, BabelTextField)): tpl = ' if %s is not None:' tpl += ' kw.update(bv2kw(%r, %s))\n' self.stream.write(tpl % (f.attname, f.attname, f.attname)) else: if isinstance(f, models.DecimalField): self.stream.write( ' if %s is not None: %s = Decimal(%s)\n' % (f.attname, f.attname, f.attname)) elif isinstance( f, models.ForeignKey) and f.rel.to is ContentType: #~ self.stream.write( #~ ' %s = ContentType.objects.get_for_model(%s).pk\n' % ( #~ f.attname,f.attname)) self.stream.write( ' %s = new_content_type_id(%s)\n' % (f.attname, f.attname)) self.stream.write(' kw.update(%s=%s)\n' % (f.attname, f.attname)) self.stream.write(' return %s(**kw)\n\n' % full_model_name(model, '_')) #~ self.start_serialization() self.stream.write('\n') model = None all_models = [] for obj in queryset: if isinstance(obj, ContentType): continue if isinstance(obj, Session): continue #~ if isinstance(obj,Permission): continue if obj.__class__ != model: model = obj.__class__ if model in all_models: raise Exception("%s instances weren't grouped!" % model) all_models.append(model) self.stream.write('\ndef %s_objects():\n' % model._meta.db_table) fields = [ f for f, m in model._meta.get_fields_with_model() if m is None ] fields = [ f for f in fields if not getattr(f, '_lino_babel_field', False) ] self.stream.write( ' yield create_%s(%s)\n' % (obj._meta.db_table, ','.join( [self.value2string(obj, f) for f in fields]))) self.stream.write('\n\ndef objects():\n') all_models = self.sort_models(all_models) for model in all_models: #~ self.stream.write(' for o in %s_objects(): yield o\n' % model._meta.db_table) self.stream.write(' yield %s_objects()\n' % model._meta.db_table)
def handle(self, *args, **options): if args: raise CommandError("This command doesn't accept any arguments.") self.options = options #~ settings.SITE.startup() state = dict() state.update(timestamp=datetime.datetime.now()) state.update(lino_version=lino.__version__) states_file = os.path.join(settings.SITE.project_dir, 'states.pck') if os.path.exists(states_file): fd = open(states_file) states_list = pickle.load(fd) fd.close() logger.info("Loaded %d states from %s", len(states_list), states_file) else: states_list = [] models_list = sorted_models_list() apps = [p.app_label for p in settings.SITE.installed_plugins] state.update(applications=" ".join(apps)) for model in models_list: if model._meta.managed: model_state = dict() #~ cells.append(str(i)) #~ cells.append(full_model_name(model)) #~ cells.append(str(model)) #~ if model._meta.managed: #~ cells.append('X') #~ else: #~ cells.append('') model_state.update(fields=[f.name for f in model._meta.fields]) #~ qs = model.objects.all() qs = model.objects.order_by('pk') n = qs.count() model_state.update(rows=n) connection = connections[DEFAULT_DB_ALIAS] #~ if isinstance(connection,sqlite): #~ cells.append("-") if mysql and isinstance(connection, mysql): cursor = connection.cursor() dbname = connection.settings_dict['NAME'] sql = """\ SELECT (data_length+index_length) tablesize FROM information_schema.tables WHERE table_schema='%s' and table_name='%s'; """ % (dbname, model._meta.db_table) #~ print sql cursor.execute(sql) row = cursor.fetchone() if row is not None: model_state.update(bytes=row[0]) else: pass state[full_model_name(model)] = model_state if len(states_list): msg = compare(state, states_list[-1]) if msg: logger.info(msg) #~ sendmail_admins() states_list.append(state) #~ print state if self.options['write']: f = open(states_file, 'w') pickle.dump(states_list, f) logger.info("Saved %d states to %s", len(states_list), states_file)
def write_create_function(model, stream): fields = [f for f in model._meta.get_fields() if f.concrete and f.model is model] for f in fields: if getattr(f, 'auto_now_add', False): # raise Exception("%s.%s.auto_now_add is True : values will be lost!" % ( # full_model_name(model), f.name)) logger.warning( "%s.%s.auto_now_add is True : values will be lost!", full_model_name(model), f.name) # f.auto_now_add = False stream.write('def create_%s(%s):\n' % ( model._meta.db_table, ', '.join([ f.attname for f in fields if not getattr(f, '_lino_babel_field', False)]))) for f in fields: if f.model is model: pre = ' ' else: pre = '# ' if isinstance(f, models.DecimalField): stream.write( pre+'if %s is not None: %s = Decimal(%s)\n' % ( f.attname, f.attname, f.attname)) elif isinstance(f, ChoiceListField): lstname = 'settings.SITE.models.{0}.{1}'.format( f.choicelist.app_label, f.choicelist.__name__) ln = pre+'if {0}: {0} = {1}.get_by_value({0})\n' ln = '#' + ln # no longer needed but maybe useful as a comment stream.write(ln.format(f.attname, lstname)) elif is_pointer_to_contenttype(f): stream.write( pre+'%s = new_content_type_id(%s)\n' % ( f.attname, f.attname)) if model._meta.parents: if len(model._meta.parents) != 1: msg = "%s : model._meta.parents is %r" % ( model, model._meta.parents) raise Exception(msg) pm, pf = list(model._meta.parents.items())[0] fields = [f for f in fields if f != pf] stream.write(" kw = dict()\n") for f in fields: if f.model is model: pre = ' ' else: pre = '# ' if getattr(f, '_lino_babel_field', False): continue elif isinstance(f, (BabelCharField, BabelTextField)): stream.write( pre + 'if %s is not None: kw.update(bv2kw(%r,%s))\n' % ( f.attname, f.attname, f.attname)) else: stream.write( pre + 'kw.update(%s=%s)\n' % (f.attname, f.attname)) if model._meta.parents: stream.write( ' return create_mti_child(%s, %s, %s, **kw)\n\n' % ( full_model_name(pm, '_'), pf.attname, full_model_name(model, '_'))) else: stream.write(' return %s(**kw)\n\n' % full_model_name(model, '_'))