예제 #1
0
    def __init__(self, model, **kw):

        parameters = dict(
            #~ merge_from=models.ForeignKey(model,verbose_name=_("Merge...")),
            merge_to=fields.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)
                    parameters[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=parameters,
                  params_layout=layouts.Panel(main, **layout))

        super(MergeAction, self).__init__(**kw)
예제 #2
0
class ProjectRelated(model.Model):
    """
    Mixin for models that are related to a "project". This adds a
    field named `project` and related default behaviour.

    A project in this context means what the users consider "the
    central most important model that is used to classify most other
    things".  For example in :ref:`avanti` the "project" is a Client
    while in :ref:`tera` it is a therapy.  The application's project
    model is specified in :attr:`lino.core.site.Site.project_model`.


    .. attribute:: project

        Pointer to the project to which this object is related.

        If the application's :attr:`project_model
        <lino.core.site.Site.project_model>` is empty, the
        :attr:`project` field will be a :class:`DummyField
        <lino.core.fields.DummyField>`.
    """
    class Meta(object):
        abstract = True

    if settings.SITE.project_model:
        project = fields.ForeignKey(
            settings.SITE.project_model,
            blank=True,
            null=True,
            related_name="%(app_label)s_%(class)s_set_by_project",
        )
    else:
        project = fields.DummyField('project')

    def get_related_project(self):
        if settings.SITE.project_model:
            return self.project

    def summary_row(self, ar, **kw):
        s = [ar.obj2html(self)]
        if settings.SITE.project_model:
            # if self.project and not dd.has_fk(rr,'project'):
            if self.project:
                # s += " (" + ui.obj2html(self.project) + ")"
                s += [" (", ar.obj2html(self.project), ")"]
        return s

    def update_owned_instance(self, controllable):
        """
        When a :class:`project-related <ProjectRelated>` object controls
        another project-related object, then the controlled
        automatically inherits the `project` of its controller.
        """
        if isinstance(controllable, ProjectRelated):
            controllable.project = self.project
        super(ProjectRelated, self).update_owned_instance(controllable)

    def get_mailable_recipients(self):
        if isinstance(self.project, settings.SITE.models.contacts.Partner):
            if self.project.email:
                yield ('to', self.project)
        for r in super(ProjectRelated, self).get_mailable_recipients():
            yield r

    def get_postable_recipients(self):
        if isinstance(self.project, settings.SITE.models.contacts.Partner):
            yield self.project
        for p in super(ProjectRelated, self).get_postable_recipients():
            yield p
예제 #3
0
파일: sequenced.py 프로젝트: zyrobin/lino
class Hierarchical(Duplicable):
    """Abstract model mixin for things that have a "parent" and
    "siblings".

    Pronounciation: [hai'ra:kikl]

    """
    class Meta(object):
        abstract = True

    parent = fields.ForeignKey('self',
                               verbose_name=_("Parent"),
                               null=True,
                               blank=True,
                               related_name='children')

    @fields.displayfield(_("Children"))
    def children_summary(self, ar):
        if ar is None:
            return ''
        elems = [ar.obj2html(ch) for ch in self.children.all()]
        elems = join_elems(elems, sep=', ')
        return E.p(*elems)

    def get_siblings(self):
        if self.parent:
            return self.parent.children.all()
        return self.__class__.objects.filter(parent__isnull=True)

    #~ def save(self, *args, **kwargs):
    #~ super(Hierarchical, self).save(*args, **kwargs)
    def full_clean(self, *args, **kwargs):
        p = self.parent
        while p is not None:
            if p == self:
                raise ValidationError("Cannot be your own ancestor")
            p = p.parent
        super(Hierarchical, self).full_clean(*args, **kwargs)

    def is_parented(self, other):
        if self == other:
            return True
        p = self.parent
        while p is not None:
            if p == other:
                return True
            p = p.parent

    def get_parents(self):
        rv = []
        p = self.parent
        while p is not None:
            rv.insert(p)
            p = p.parent
        return rv

    def get_parental_line(self):
        """Return an ordered list of all ancestors of this instance.  

        The last element of the list is this.
        A top-level project is its own root.

        """
        obj = self
        tree = [obj]
        while obj.parent is not None:
            obj = obj.parent
            if obj in tree:
                raise Exception("Circular parent")
            tree.insert(0, obj)
        return tree

    def whole_clan(self):
        """Return a set of this instance and all children and grandchildren.

        """
        # TODO: go deeper but check for circular references
        clan = set([self])
        l1 = self.__class__.objects.filter(parent=self)
        if l1.count() == 0:
            return clan
        clan |= set(l1)
        l2 = self.__class__.objects.filter(parent__in=l1)
        if l2.count() == 0:
            return clan
        clan |= set(l2)
        l3 = self.__class__.objects.filter(parent__in=l2)
        if l3.count() == 0:
            return clan
        clan |= set(l3)
        # print 20150421, projects
        return clan