예제 #1
0
    def get_json(self, params, id):
        graph.update_if_needed()

        all_sources = {}
        p2e = {}
        p2c = {}
        p2g = {}

        p = extended_personas(
            nodes=set([graph.node_from_id(id)]),
            p2e=p2e,
            p2c=p2c,
            p2g=p2g,
            all_sources=all_sources,
            styles=None, as_css=True, graph=graph, schemes=None)

        query = models.P2P.objects.filter(
            type=models.P2P.sameAs)

        node = graph.node_from_id(id)
        assertions = list(models.P2P.objects.filter(
            type=models.P2P.sameAs,
            person1__in=node.ids.union(node.different)))

        decujus = p[node.main_id]

        return {
            "person": decujus,
            "sources": all_sources,
            "p2c": p2c.values(),
            "p2e": p2e.values(),
            "p2p": assertions,
            "p2g": p2g.values()
        }
예제 #2
0
파일: persona.py 프로젝트: a59/geneapro
def view(request, id):
    """Display all details known about persona ID"""

    id = int(id)

    graph.update_if_needed()
    #if len(graph) == 0:
    #    return render_to_response(
    #        'geneaprove/firsttime.html',
    #        context_instance=RequestContext(request))

    styles = None
    p = extended_personas(
        nodes=set([graph.node_from_id(id)]),
        styles=styles, as_css=True, graph=graph, schemes=None)

    query = models.P2P.objects.filter(
        type=models.P2P.sameAs)

    node = graph.node_from_id(id)
    assertions = list(models.P2P.objects.filter(
        type=models.P2P.sameAs,
        person1__in=node.ids.union(node.different)))

    decujus = p[node.main_id]

    decujus.all_chars = decujus.all_chars.values()
    decujus.all_events = decujus.all_events.values()
    decujus.all_groups = decujus.all_groups.values()

    data = {
        "person": decujus,
        "p2p": assertions,
    }
    return HttpResponse(to_json(data), content_type='application/json')
예제 #3
0
def personaEvents(request, id):
    """All events for the person"""

    id = int(id)

    graph.update_if_needed()

    schemes = set() # The surety schemes that are needed
    styles = None
    p = extended_personas(
        nodes=set([graph.node_from_id(id)]),
        styles=styles, as_css=True, graph=graph, schemes=schemes)

    data = ["%s: %s (%s)%s" % (e.event.name, e.event.date, e.event.place,
                               u"\u2713" if e.event.sources  else u"\u2717")
            for i, e in p[id].all_events.items()
            if e.role == 'principal'
               and not e.assertion.disproved]
    data.extend("%s: %s%s%s" % (
                c.char.name, 
                " ".join("%s:%s" % (p.name, p.value) for p in c.parts),
                "(%s)" % c.char.date if c.char.date else "",
                u"\u2713" if c.char.sources else u"\u2717")
             for k, c in p[id].all_chars.items()
             if not c.assertion.disproved
                and c.char.name not in ("_UID", ))

    return HttpResponse(
        to_json(data, year_only=False),
        content_type="application/json")
예제 #4
0
def personaEvents(request, id):
    """All events for the person"""

    id = int(id)

    graph.update_if_needed()

    schemes = set()  # The surety schemes that are needed
    styles = None
    p = extended_personas(nodes=set([graph.node_from_id(id)]),
                          styles=styles,
                          as_css=True,
                          graph=graph,
                          schemes=schemes)

    data = [
        "%s: %s (%s)%s" % (e.event.name, e.event.date, e.event.place,
                           u"\u2713" if e.event.sources else u"\u2717")
        for i, e in p[id].all_events.items()
        if e.role == 'principal' and not e.assertion.disproved
    ]
    data.extend("%s: %s%s%s" % (c.char.name, " ".join(
        "%s:%s" % (p.name, p.value)
        for p in c.parts), "(%s)" % c.char.date if c.char.date else "",
                                u"\u2713" if c.char.sources else u"\u2717")
                for k, c in p[id].all_chars.items()
                if not c.assertion.disproved and c.char.name not in ("_UID", ))

    return HttpResponse(to_json(data, year_only=False),
                        content_type="application/json")
예제 #5
0
def view(request, id):
    """Display all details known about persona ID"""

    id = int(id)

    graph.update_if_needed()
    if len(graph) == 0:
        return render_to_response(
            'geneaprove/firsttime.html',
            context_instance=RequestContext(request))

    schemes = set() # The surety schemes that are needed
    styles = None
    p = extended_personas(
        nodes=set([graph.node_from_id(id)]),
        styles=styles, as_css=True, graph=graph, schemes=schemes)

    surety_schemes = dict()
    for s in schemes:
        surety_schemes[s] = models.Surety_Scheme.objects.get(id=s).parts.all()

    query = models.P2P.objects.filter(
        type=models.P2P.sameAs)

    node = graph.node_from_id(id)
    assertions = list(models.P2P.objects.filter(
        type=models.P2P.sameAs,
        person1__in=node.ids.union(node.different)))

    decujus = p[node.main_id]

    return render_to_response(
        'geneaprove/persona.html',
        {"decujus": id,
         "person": decujus,
         "decujus_name": "%s %s" % (decujus.given_name, decujus.surname),
         "chars": decujus.all_chars,
         "events": decujus.all_events,
         "groups": decujus.all_groups,
         "schemes": surety_schemes,
         "p2p": [(0, a) for a in assertions],
        },
        context_instance=RequestContext(request))
예제 #6
0
파일: pedigree.py 프로젝트: a59/geneapro
    def add_parents(p):
        p.generation = distance[graph.node_from_id(p.id)]
        if p.generation >= max_levels:
            return

        fathers = graph.fathers(p.id)
        mothers = graph.mothers(p.id)
        p.parents = [
            None if not fathers else persons.get(fathers[0].main_id, None),
            None if not mothers else persons.get(mothers[0].main_id, None)]

        for pa in p.parents:
            if pa:
                add_parents(pa)
예제 #7
0
 def build_sosa_tree(sosa_tree, marriage, sosa, id):
     # A person might not be in 'persons', and yet its parent be there,
     # in case we have filtered out earlier generations.
     if id in persons:
         sosa_tree[sosa] = id
         persons[id].generation = distance[graph.node_from_id(id)]
         if persons[id].marriage:
             marriage[sosa] = persons[id].marriage
     fathers = graph.fathers(id)
     if fathers:
         build_sosa_tree(sosa_tree, marriage, sosa * 2, fathers[0].main_id)
     mothers = graph.mothers(id)
     if mothers:
         build_sosa_tree(
             sosa_tree, marriage, sosa * 2 + 1, mothers[0].main_id)
예제 #8
0
def view(request, id):
    """Display all details known about persona ID"""

    id = int(id)

    graph.update_if_needed()
    #if len(graph) == 0:
    #    return render_to_response(
    #        'geneaprove/firsttime.html',
    #        context_instance=RequestContext(request))

    styles = None
    p = extended_personas(nodes=set([graph.node_from_id(id)]),
                          styles=styles,
                          as_css=True,
                          graph=graph,
                          schemes=None)

    query = models.P2P.objects.filter(type=models.P2P.sameAs)

    node = graph.node_from_id(id)
    assertions = list(
        models.P2P.objects.filter(type=models.P2P.sameAs,
                                  person1__in=node.ids.union(node.different)))

    decujus = p[node.main_id]

    decujus.all_chars = decujus.all_chars.values()
    decujus.all_events = decujus.all_events.values()
    decujus.all_groups = decujus.all_groups.values()

    data = {
        "person": decujus,
        "p2p": assertions,
    }
    return HttpResponse(to_json(data), content_type='application/json')
예제 #9
0
    def get_json(self, params, id):
        id = int(id);
        graph.update_if_needed()

        # ??? The stats includes persons "Unknown" that were created during a
        # gedcom import for the purpose of preserving families. Will be fixed
        # when we store children differently (for instance in a group)

        distance = dict()
        decujus = graph.node_from_id(id)

        allpeople = graph.people_in_tree(id=decujus.main_id, distance=distance)
        persons = extended_personas(
            nodes=allpeople, styles=None, event_types=event_types_for_pedigree,
            graph=graph)

        f = graph.fathers(decujus.main_id)
        fathers = graph.people_in_tree(id=f[0], maxdepthDescendants=0) if f else []
        m = graph.mothers(decujus.main_id)
        mothers = graph.people_in_tree(id=m[0], maxdepthDescendants=0) if m else []

        cal = CalendarGregorian()

        generations = dict()  # list of persons for each generation
        for a in allpeople:
            d = distance[a]
            if d not in generations:
                generations[d] = []
            generations[d].append(a)

        ranges = []

        for index in sorted(generations.keys()):
            births = None
            deaths = None
            gen_range = [index + 1, "?", "?", ""]  # gen, min, max, legend
            for p in generations[index]:
                p = persons[p.main_id]
                if p.birth and p.birth.Date:
                    if births is None or p.birth.Date < births:
                        births = p.birth.Date
                        year = p.birth.Date.year(cal)
                        if year is not None:
                            gen_range[1] = year

                if p.death and p.death.Date:
                    if deaths is None or p.death.Date > deaths:
                        deaths = p.death.Date
                        year = p.death.Date.year(cal)
                        if year is not None:
                            gen_range[2] = year

            if index >= 0:
                gen_range[3] = "Gen. %02d (%d / %d) %s - %s" \
                    % (index + 1, len(generations[index]), 2 ** (index + 1),
                       gen_range[1], gen_range[2])
            else:
                gen_range[3] = "Desc. %02d (%d) %s - %s" \
                    % (-index, len(generations[index]),
                       gen_range[1], gen_range[2])

            # Postprocess the ranges:
            #   generation n's earliest date has to be at least 15 years before
            #     its children's earliest date (can't have children before that)
            #   generation n's latest date (death) has to be after the children's
            #     generation earliest date (first birth)

            if len(ranges) > 0:
                if gen_range[1] == "?":
                    gen_range[1] = ranges[-1][1] - 15
                if gen_range[2] == "?" or gen_range[2] < ranges[-1][1]:
                    gen_range[2] = ranges[-1][1]
            if gen_range[2] == '?':
                gen_range[2] = datetime.datetime.now().year

            ranges.append(gen_range)

        ages = []
        for a in range(0, 120, 5):
            ages.append([a, 0, 0, 0])  # date_range, males, females, unknown

        for p in persons.itervalues():
            if p.birth and p.birth.Date and p.death and p.death.Date:
                age = p.death.Date.years_since(p.birth.Date)
                if age is not None:
                    if p.sex == "M":
                        ages[int(age / 5)][1] += 1
                    elif p.sex == "F":
                        ages[int(age / 5)][2] += 1
                    else:
                        ages[int(age / 5)][3] += 1

        return {
            "total_ancestors": len(allpeople),
            "total_father":    len(fathers),
            "total_mother":    len(mothers),
            "total_persons":   len(graph),
            "ranges":          ranges,
            "ages":            ages,
            "decujus":         decujus.main_id,
            "decujus_name":  "%s %s" % (
                persons[decujus.main_id].given_name,
                persons[decujus.main_id].surname)
        }
예제 #10
0
파일: pedigree.py 프로젝트: a59/geneapro
def __get_json_sosa_tree(graph, id, max_levels, style_rules,
                  last_descendant_known=-1,
                  maxdepthDescendants=1, last_gen_known=-1):
    """
        :param last_gen_known: is the number of the last generation for which the
            client already has data, and thus do not need to be sent again. -1
            to retrieve all.
        :param maxdepthDescendants:
            The number of generations for which we compute the children.
    """

    decujus = graph.node_from_id(id)
    styles = Styles(style_rules, graph, decujus=decujus.main_id)

    distance = dict()
    ancestors = graph.people_in_tree(
        id=decujus.main_id, maxdepthAncestors=max_levels - 1,
        maxdepthDescendants=0, distance=distance)
    ancestors = [a for a in ancestors if distance[a] >= last_gen_known]

    descendants = graph.people_in_tree(
        id=decujus.main_id, maxdepthAncestors=0,
        distance=distance, maxdepthDescendants=maxdepthDescendants)
    descendants = [
        a for a in descendants
        if a != decujus and distance[a] >= last_descendant_known]

    sosa_tree = dict()
    marriage = dict()
    children = {}

    persons = {}
    all_person_nodes = set(ancestors).union(descendants)
    if all_person_nodes:
        persons = extended_personas(
            all_person_nodes, styles,
            event_types=event_types_for_pedigree, graph=graph)

    def add_parents(p):
        p.generation = distance[graph.node_from_id(p.id)]
        if p.generation >= max_levels:
            return

        fathers = graph.fathers(p.id)
        mothers = graph.mothers(p.id)
        p.parents = [
            None if not fathers else persons.get(fathers[0].main_id, None),
            None if not mothers else persons.get(mothers[0].main_id, None)]

        for pa in p.parents:
            if pa:
                add_parents(pa)

    def add_children(p, gen):
        p.children = []
        sorted = [(persons[node.main_id] if node.main_id in persons else None,
                   node)
                  for node in graph.children(p.id)]
        sorted.sort(
            key=lambda c: c[0].birth.Date if c[0] and c[0].birth else None)
        for c in sorted:
            if c[0]:
                c[0].generation = -gen # distance[c[1]]
                p.children.append(c[0])
                if gen < maxdepthDescendants:
                    add_children(c[0], gen + 1)

    main = persons[decujus.main_id]
    add_parents(main)
    add_children(main, gen=1)

    # We will however return a simpler version of the information computed
    # above (which includes all known events for the persons)

    show_age = False
    def person_to_json_for_pedigree(obj):
        if isinstance(obj, models.Persona):
            d = obj.death
            if show_age and obj.birth:
                if d:
                    if d.Date:
                        d.Date += " (age %s)" % (
                            str(d.Date.years_since(obj.birth.Date)), )
                else:
                    d = {Date: " (age %s)" % (
                       str(DateRange.today().years_since(obj.birth.Date)), )}

            return {
                'id':   obj.id,
                'givn': obj.given_name,
                'surn': obj.surname,
                'sex':  obj.sex,
                'generation': obj.generation,
                'parents': obj.parents if hasattr(obj, 'parents') else None,
                'children': obj.children if hasattr(obj, 'children') else None,
                'style': obj.styles,
                'birth': obj.birth,
                'marriage': obj.marriage,
                'death': d}

    return to_json(
        obj= {'generations': max_levels,
              'descendants': maxdepthDescendants,
              'decujus':     main, 
              'styles':      styles.all_styles()},
        custom=person_to_json_for_pedigree) 
예제 #11
0
def get_sosa_tree(graph, id, max_levels, style_rules,
                  last_descendant_known=-1,
                  maxdepthDescendants=1, last_gen_known=-1):
   """
       :param last_gen_known: is the number of the last generation for which the
           client already has data, and thus do not need to be sent again. -1
           to retrieve all.
       :param maxdepthDescendants:
           The number of generations for which we compute the children.
   """

   decujus = graph.node_from_id(id)

   styles = Styles(style_rules, graph, decujus=decujus.main_id)

   distance = dict()
   ancestors = graph.people_in_tree(
       id=decujus.main_id, maxdepthAncestors=max_levels - 1,
       maxdepthDescendants=0, distance=distance)
   ancestors = [a for a in ancestors if distance[a] >= last_gen_known]

   descendants = graph.people_in_tree(
       id=decujus.main_id, maxdepthAncestors=0,
       distance=distance, maxdepthDescendants=maxdepthDescendants)
   descendants.remove(decujus)
   descendants = [a for a in descendants if distance[a] >= last_descendant_known]

   sosa_tree = dict()
   marriage = dict()
   children = {}
   persons = {}

   all_person_nodes = set(ancestors).union(descendants)
   if all_person_nodes:
       persons = extended_personas(
           all_person_nodes, styles,
           event_types=event_types_for_pedigree, graph=graph)

       def build_sosa_tree(sosa_tree, marriage, sosa, id):
           # A person might not be in 'persons', and yet its parent be there,
           # in case we have filtered out earlier generations.
           if id in persons:
               sosa_tree[sosa] = id
               persons[id].generation = distance[graph.node_from_id(id)]
               if persons[id].marriage:
                   marriage[sosa] = persons[id].marriage
           fathers = graph.fathers(id)
           if fathers:
               build_sosa_tree(sosa_tree, marriage, sosa * 2, fathers[0].main_id)
           mothers = graph.mothers(id)
           if mothers:
               build_sosa_tree(
                   sosa_tree, marriage, sosa * 2 + 1, mothers[0].main_id)

       def build_children_tree(children, id, gen):
           if id in persons:
               children[id] = []
           sorted = [(persons[node.main_id] if node.main_id in persons else None, node)
                     for node in graph.children(id)]
           sorted.sort(key=lambda p: p[0].birth.Date if p[0] and p[0].birth else None)
           for p in sorted:
               if p[0]:
                   p[0].generation = -distance[p[1]]
                   if id in persons:
                       children[id].append(p[0].id)
               if gen < maxdepthDescendants:
                   build_children_tree(children, id=p[0].id, gen=gen + 1)

       build_sosa_tree(sosa_tree, marriage, 1, decujus.main_id)
       build_children_tree(children, id=decujus.main_id, gen=1)

   return {'generations': max_levels,
           'descendants': maxdepthDescendants,
           'persons':     persons,    # All persons indexed by id
           'sosa':        sosa_tree,  # sosa_number -> person_id
           'children':    children,   # personId -> [children_id*]
           'marriage':    marriage,   # sosa_number -> marriage info
           'styles':      styles.all_styles()}
예제 #12
0
    def get_json(self, params, id):
        # ??? Should lock until the view has been generated
        graph.update_if_needed()

        max_levels = int(params.get("gens", 5))
        last_descendant_known = int(params.get("desc_known", -1))

        # The number of generations for which we compute the children.
        maxdepthDescendants = int(params.get("descendant_gens", 1))

        # the number of the last generation for which the client already has
        # data, and thus do not need to be sent again. -1 to retrieve all.
        last_gen_known = int(params.get("gens_known", -1))

        # Whether to show full dates or only the year
        self.year_only = params.get('year_only', '') == 'true'

        decujus = graph.node_from_id(id)
        styles = Styles(style_rules, graph, decujus=decujus.main_id)

        distance = dict()
        people = graph.people_in_tree(
            id=decujus.main_id,
            maxdepthAncestors=max_levels - 1,
            maxdepthDescendants=maxdepthDescendants,
            distance=distance)
        ancestors = [a for a in people
                     if distance[a] >= 0 and distance[a] >= last_gen_known]
        descendants = [a for a in people
                       if a != decujus and distance[a] < 0
                       and distance[a] <= -last_descendant_known]

        sosa_tree = dict()
        marriage = dict()
        children = {}

        persons = {}
        all_person_nodes = set(ancestors).union(descendants)
        if all_person_nodes:
            persons = extended_personas(
                all_person_nodes, styles,
                event_types=event_types_for_pedigree, graph=graph)

        def add_parents(p):
            p.generation = distance[graph.node_from_id(p.id)]
            if p.generation >= max_levels:
                return

            fathers = graph.fathers(p.id)
            mothers = graph.mothers(p.id)
            p.parents = [
                None if not fathers else persons.get(fathers[0].main_id, None),
                None if not mothers else persons.get(mothers[0].main_id, None)]

            for pa in p.parents:
                if pa:
                    add_parents(pa)

        def add_children(p, gen):
            p.children = []
            sorted = [(persons[node.main_id] if node.main_id in persons else None,
                       node)
                      for node in graph.children(p.id)]
            sorted.sort(
                key=lambda c: c[0].birth.Date if c[0] and c[0].birth else None)
            for c in sorted:
                if c[0]:
                    c[0].generation = -gen # distance[c[1]]
                    p.children.append(c[0])
                    if gen < maxdepthDescendants:
                        add_children(c[0], gen + 1)

        main = persons[decujus.main_id]
        add_parents(main)
        add_children(main, gen=1)
        return {'generations': max_levels,
                'descendants': maxdepthDescendants,
                'decujus':     main, 
                'styles':      styles.all_styles()}
예제 #13
0
파일: merge.py 프로젝트: a59/geneapro
def find_candidate(graph):
    """Find all candidate personas for a merge"""

    p1 = 7843  # Emmanuel Briot
    p2 = 1     # Emmanuel Briot
    p3 = 3052  # Marie HOUTEVILLE
    p4 = 3335  # Thomine Levesque
    p5 = 1311
    p6 = 7842

    persons = extended_personas(
        nodes=set([graph.node_from_id(p1),
                   graph.node_from_id(p2),
                   graph.node_from_id(p3),
                   graph.node_from_id(p4),
                   graph.node_from_id(p5),
                   graph.node_from_id(p6)]),
        styles=None, same=same, query_groups=False)
    for p in [(p1, p2), (p2, p1), (p3, p4), (p5, p6), (p6, p5)]:
        print persons[p[0]].name, persons[p[1]].name
        score = compare(persons[p[0]], persons[p[1]])
        print "  => ", score

    # Get all persons from the database with a guess at their lifespan.
    # If we know the birth date, lifespan starts there, otherwise it starts
    #   some years before the first event
    # Likewise for death date.
    # This results is potentially over-optimistic lifespans, but still reduces
    # the number of comparisons to do.
    # The following query (and its processing) might take a while on big
    # databases, but we'll need access to the whole information for persons
    # anyway, so we might as well query everything from the start)
    # number of persons: 9171
    #   number of queries:6   total queries time:0.26s   total time:26.21s

    persons = extended_personas(
        nodes=None, styles=None, graph=graph, query_groups=False)

    # A temporary structure ordered by the first date in lifespan

    births = []
    delta = datetime.timedelta(days=maximum_lifespan * 365)

    for p in persons.itervalues():
        birth = death = None

        if p.birth is not None:
            birth = p.birth.date_sort
        if p.death is not None:
            death = p.death.date_sort
        if birth is None or death is None:
            h = [a.event.date_sort
                 for a in p.all_events.itervalues()
                 if a.event.date_sort is not None]
            if h:
                h.sort()
                birth = birth or h[0] - delta
                death = death or h[-1] + delta

        # If birth is None, that means there are no events, and we don't
        # really want to merge that person then.
        if birth:
            p.max_lifespan = death
            heapq.heappush(births, (birth, p))

    # Now we traverse the list and only compare persons that were alive at
    # the same time (otherwise we assume they cannot be merged)
    # ??? We can save time by not comparing when we have already
    # decided in the past they can't be the same

    alive = []  # Each person alive at the given date
    comparisons = 0
    same = 0

    while births:
        date, person = heapq.heappop(births)

        for a in alive:
            if a.max_lifespan < date:
                alive.remove(a)
            elif date.year < 1970:
                continue
            else:
                # print "Compare %s and %s" % (person.name, a.name)
                comparisons += 1
                score = compare(a, person)
                if score >= 150:
                    print "%d Might be the same: %d %s and %d %s, score=%d %d" % (
                        date.year, person.id, person.name, a.id, a.name, score,
                        compare(person, a))
                    same += 1

        alive.append(person)

    # Maximum comparisons (n^2) would be: 83_302_129
    # Actual comparisons with this algo:  14_635_289
    print "Number of comparisons: ", comparisons
    print "Possible merges: ", same
예제 #14
0
def extended_personas(
    nodes, styles, graph, p2e=None, event_types=None, schemes=None,
    p2c=None, p2g=None,
    all_sources=None, as_css=False, query_groups=True):
    """
    Compute the events for the various persons in `nodes` (all all persons in
    the database if None)
    Return a dict indexed on id containing extended instances of Persona,
    with additional fields for the birth, the death,...

       :param nodes:
           A set of graph.Persona_node, or None to get all persons from the
           database.
       :param graph: an instance of Graph, which is used to compute whether
          two ids represent the same person.
       :param dict all_sources: either a dictionary, or None. If specified, it
          will be filled with  "sourceId -> models.Source" objects
       :param as_css:
          True to get the styles as a CSS string rather than a python dict
       :param event_types: restricts the types of events that are retrieved
       :param dict p2e: All person-to-event assertions
       :param dict p2c: All persona-to-characteristic assertions
       :param dict p2g: All persona-to-group assertions
       :return: a list of persons:
          * persons is a dictionary of Persona instances, indexed on persona_id

       SCHEMES is the list of ids of Surety_Scheme that are used. You
          should pass a set() if you are interested in this. Otherwise, it is
          just discarded.

       This sets persons[*].chars to a list of the characteristics.
       Only the events of type in TYPES are returned
    """
    if nodes:
        ids = [a.main_id for a in nodes]
    else:
        ids = None

    compute_parts = styles and styles.need_place_parts()

    roles = dict()  # role_id  -> name
    places = dict()  # place_id -> place

    assert(schemes is None or isinstance(schemes, set))

    if styles:
        styles.start()

    # Get the role names

    for role in models.Event_Type_Role.objects.all():
        roles[role.id] = role.name

    ##############
    # Create the personas that will be returned.
    ##############

    persons = dict()  # id -> person
    if ids:
        for p in sql_in(models.Persona.objects, "id", ids):
            # p.id is always the main_id, since that's how ids was built
            persons[p.id] = p
            __add_default_person_attributes(p)
    else:
        for p in models.Persona.objects.all():
            mid = graph.node_from_id(p.id).main_id
            if mid not in persons:
                persons[mid] = p
                __add_default_person_attributes(p)

    ################
    # Check all events that the persons were involved in.
    ################

    events = models.P2E.objects.select_related(
        'event', 'event__place', 'event__type', 'surety')
    if event_types:
        events = events.filter(event__type__in=event_types)

    all_ids = None
    if nodes:
        all_ids = set()
        for p in nodes:
            all_ids.update(p.ids)

    # All query the 'principal' for each events, so that we can provide
    # that information graphically.
    for p in sql_in(events, "person", all_ids):
        e = p.event

        p_node = graph.node_from_id(p.person_id)
        person = persons[p_node.main_id]

        # ??? A person could be involved multiple times in the same
        # event, under multiple roles. Here we are only preserving the
        # last occurrence
        if p2e is not None:
            # ??? Should we reset p.p1, since this is always the same
            p2e[e.id] = p

        if all_sources is not None:
            all_sources.setdefault(p.source_id, {})

        e.Date = e.date and DateRange(e.date)

        if schemes is not None:
            schemes.add(p.surety.scheme_id)

        if compute_parts and e.place:
            places[e.place_id] = e.place

        if styles:
            styles.process(person, p.role_id, e)

        if not p.disproved \
           and p.role_id == models.Event_Type_Role.principal:
            if not e.Date:
                pass
            elif e.type_id == models.Event_Type.birth:
                if person.birth is None \
                   or person.birth.date_sort > e.date_sort:
                    person.birth = e
            elif e.type_id == models.Event_Type.death:
                if person.death is None \
                   or person.death.date_sort < e.date_sort:
                    person.death = e
            elif e.type_id == models.Event_Type.marriage:
                person.marriage = e

    #########
    # Get all groups to which the personas belong
    #########

    if query_groups:
        groups = models.P2G.objects.select_related('group')
        for gr in sql_in(groups, "person", all_ids):
            p_node = graph.node_from_id(gr.person_id)
            person = persons[p_node.main_id]

            if p2g is not None:
                p2g[gr.group_id] = gr
            if all_sources is not None:
                all_sources.setdefault(gr.source_id, {})

            if schemes is not None:
                schemes.add(gr.surety.scheme_id)

    #########
    # Get all characteristics of these personas
    #########

    c2p = dict()  # characteristic_id -> person
    all_p2c = models.P2C.objects.select_related(
        'characteristic', 'characteristic__place')

    for p in sql_in(all_p2c, "person", all_ids):
        c = p.characteristic
        p_node = graph.node_from_id(p.person_id)
        person = persons[p_node.main_id]
        c2p[c.id] = person

        if all_sources is not None:
            all_sources.setdefault(p.source_id, {})

        c.date = c.date and DateRange(c.date)

        if schemes is not None:
            schemes.add(p.surety.scheme_id)

        if p2c is not None:
            # ??? Should we reset p.person, since this is always the same
            # ??? but can't set it to None in the model
            p2c[c.id] = p

        if compute_parts and c.place:
            places[c.place_id] = c.place

    chars = models.Characteristic_Part.objects.select_related(
        'type', 'characteristic', 'characteristic__place')

    for part in sql_in(chars, "characteristic", nodes and c2p.keys()):
        person = c2p[part.characteristic_id]

        if part.type_id == models.Characteristic_Part_Type.sex:
            person.sex = part.name
        elif part.type_id == models.Characteristic_Part_Type.given_name:
            person.given_name = part.name
        elif part.type_id == models.Characteristic_Part_Type.surname:
            person.surname = part.name

    ########
    # Compute place parts once, to limit the number of queries
    # These are only used for styles, not for actual display, although we
    # could benefit from them.
    ########

    if compute_parts:
        prev_place = None
        d = None

        for p in sql_in(models.Place_Part.objects
                        .order_by('place').select_related('type'),
                        "place", places.keys()):

            # ??? We should also check the parent place to gets its own parts
            if p.place_id != prev_place:
                prev_place = p.place_id
                d = dict()
                setattr(places[prev_place], "parts", d)

            d[p.type.name] = p.name

    ##########
    # Get the title for all sources that are mentioned
    ##########

    if all_sources is not None:
        for s in sql_in(models.Source.objects, "id", all_sources.keys()):
            all_sources[s.id] = s

    ##########
    # Compute the styles
    ##########

    if styles:
        for p in persons.itervalues():
            styles.compute(p, as_css=as_css)

    return persons
예제 #15
0
def __get_events(nodes, styles, graph, types=None, schemes=None,
                 query_groups=True):
    """Compute the events for the various persons in IDS (all all persons in
       the database if None)
       
       :param nodes:
           A set of graph.Persona_node, or None to get all persons from the
           database.
       :param graph: an instance of Graph, which is used to compute whether
          two ids represent the same person.
       :return: a list of persons:
          * persons is a dictionary of Persona instances, indexed on persona_id

       SCHEMES is the list of ids of Surety_Scheme that are used. You
          should pass a set() if you are interested in this. Otherwise, it is
          just discarded.

       This sets persons[*].chars to a list of the characteristics.
       Only the events of type in TYPES are returned
    """
    if nodes:
        ids = [a.main_id for a in nodes]
    else:
        ids = None

    compute_parts = styles and styles.need_place_parts()

    roles = dict()  # role_id  -> name
    places = dict() # place_id -> place

    assert(schemes is None or isinstance(schemes, set))

    # Get the role names

    for role in models.Event_Type_Role.objects.all():
        roles[role.id] = role.name

    ##############
    # Create the personas that will be returned.
    ##############

    persons = dict() # id -> person
    if ids:
        for p in sql_in(models.Persona.objects, "id", ids):
            # p.id is always the main_id, since that's how ids was built
            persons[p.id] = p
            __add_default_person_attributes(p)
    else:
        for p in models.Persona.objects.all():
            mid = graph.node_from_id(p.id).main_id
            if mid not in persons:
                persons[mid] = p
                __add_default_person_attributes(p)

    ################
    # Check all events that the persons were involved in.
    ################

    events = models.P2E.objects.select_related(
        'event', 'event__place', 'event__type', 'surety')
    if types:
        events = events.filter(event__type__in=types)

    all_ids = None
    if nodes:
        all_ids = set()
        for p in nodes:
            all_ids.update(p.ids)

    all_events = dict()

    # All query the 'principal' for each events, so that we can provide
    # that information graphically.
    for p in sql_in(events, "person", all_ids):
        #or_q=Q(role=models.Event_Type_Role.principal)):
        e = p.event

        p_node = graph.node_from_id(p.person_id)
        person = persons[p_node.main_id]
        person.all_events[e.id] = EventInfo(
            event=e, role=roles[p.role_id], assertion=p)

        e.sources = getattr(e, "sources", set())
        e.sources.add(p.source_id)
        e.Date = e.date and DateRange(e.date)

        if schemes is not None:
            schemes.add(p.surety.scheme_id)

        if compute_parts and e.place:
            places[e.place_id] = e.place

        if styles:
            styles.process(person, p.role_id, e)

        if not p.disproved \
           and p.role_id == models.Event_Type_Role.principal:
            if not e.Date:
                pass
            elif e.type_id == models.Event_Type.birth:
                if person.birth is None \
                   or person.birth.date_sort > e.date_sort:
                    person.birth = e
            elif e.type_id == models.Event_Type.death:
                if person.death is None \
                   or person.death.date_sort < e.date_sort:
                    person.death = e
            elif e.type_id == models.Event_Type.marriage:
                person.marriage = e

    #########
    # Get all groups to which the personas belong
    #########

    if query_groups:
        groups = models.P2G.objects.select_related('group')
        for gr in sql_in(groups, "person", all_ids):
            p_node = graph.node_from_id(gr.person_id)
            person = persons[p_node.main_id]
            person.all_groups[gr.group_id] = GroupInfo(
                group=gr.group, assertion=gr)
            if gr.source_id:
                src = getattr(gr.group, "sources", [])
                src.append(gr.source_id)
                gr.group.sources = src
            gr.group.role = gr.role

            if schemes is not None:
                schemes.add(gr.surety.scheme_id)

    #########
    # Get all characteristics of these personas
    #########

    p2c = dict()  # characteristic_id -> person
    all_p2c = models.P2C.objects.select_related(
        'characteristic', 'characteristic__place')

    for p in sql_in(all_p2c, "person", all_ids):
        c = p.characteristic
        p_node = graph.node_from_id(p.person_id)
        person = persons[p_node.main_id]
        p2c[c.id] = person

        c.sources = getattr(c, "sources", set())
        c.sources.add(p.source_id)
        c.date = c.date and DateRange(c.date)

        if schemes is not None:
            schemes.add(p.surety.scheme_id)

        person.all_chars[c.id] = CharInfo(
            char=c,
            assertion=p,
            parts=[])

        if compute_parts and c.place:
            places[c.place_id] = c.place

    chars = models.Characteristic_Part.objects.select_related(
        'type', 'characteristic', 'characteristic__place')

    for part in sql_in(chars, "characteristic", nodes and p2c.keys()):
        person = p2c[part.characteristic_id]
        ch = person.all_chars[part.characteristic_id]
        ch.parts.append(CharPartInfo(name=part.type.name, value=part.name))

        if part.type_id == models.Characteristic_Part_Type.sex:
           person.sex = part.name
        elif part.type_id == models.Characteristic_Part_Type.given_name:
           person.given_name = part.name
        elif part.type_id == models.Characteristic_Part_Type.surname:
           person.surname = part.name

    ########
    # Compute place parts once, to limit the number of queries
    # These are only used for styles, not for actual display, although we
    # could benefit from them.
    ########

    if compute_parts:
       prev_place = None
       d = None

       for p in sql_in(models.Place_Part.objects
           .order_by('place').select_related('type'),
           "place", places.keys()):

          # ??? We should also check the parent place to gets its own parts
          if p.place_id != prev_place:
             prev_place = p.place_id
             d = dict()
             setattr(places[prev_place], "parts", d)

          d[p.type.name] = p.name

    return persons
예제 #16
0
def __get_events(nodes,
                 styles,
                 graph,
                 types=None,
                 schemes=None,
                 query_groups=True):
    """Compute the events for the various persons in IDS (all all persons in
       the database if None)

       :param nodes:
           A set of graph.Persona_node, or None to get all persons from the
           database.
       :param graph: an instance of Graph, which is used to compute whether
          two ids represent the same person.
       :return: a list of persons:
          * persons is a dictionary of Persona instances, indexed on persona_id

       SCHEMES is the list of ids of Surety_Scheme that are used. You
          should pass a set() if you are interested in this. Otherwise, it is
          just discarded.

       This sets persons[*].chars to a list of the characteristics.
       Only the events of type in TYPES are returned
    """
    if nodes:
        ids = [a.main_id for a in nodes]
    else:
        ids = None

    compute_parts = styles and styles.need_place_parts()

    roles = dict()  # role_id  -> name
    places = dict()  # place_id -> place

    assert (schemes is None or isinstance(schemes, set))

    # Get the role names

    for role in models.Event_Type_Role.objects.all():
        roles[role.id] = role.name

    ##############
    # Create the personas that will be returned.
    ##############

    persons = dict()  # id -> person
    if ids:
        for p in sql_in(models.Persona.objects, "id", ids):
            # p.id is always the main_id, since that's how ids was built
            persons[p.id] = p
            __add_default_person_attributes(p)
    else:
        for p in models.Persona.objects.all():
            mid = graph.node_from_id(p.id).main_id
            if mid not in persons:
                persons[mid] = p
                __add_default_person_attributes(p)

    ################
    # Check all events that the persons were involved in.
    ################

    events = models.P2E.objects.select_related('event', 'event__place',
                                               'event__type', 'surety')
    if types:
        events = events.filter(event__type__in=types)

    all_ids = None
    if nodes:
        all_ids = set()
        for p in nodes:
            all_ids.update(p.ids)

    all_events = dict()

    # All query the 'principal' for each events, so that we can provide
    # that information graphically.
    for p in sql_in(events, "person", all_ids):
        # or_q=Q(role=models.Event_Type_Role.principal)):
        e = p.event

        p_node = graph.node_from_id(p.person_id)
        person = persons[p_node.main_id]
        person.all_events[e.id] = EventInfo(event=e,
                                            role=roles[p.role_id],
                                            assertion=p)

        e.sources = getattr(e, "sources", set())
        e.sources.add(p.source_id)
        e.Date = e.date and DateRange(e.date)

        if schemes is not None:
            schemes.add(p.surety.scheme_id)

        if compute_parts and e.place:
            places[e.place_id] = e.place

        if styles:
            styles.process(person, p.role_id, e)

        if not p.disproved \
           and p.role_id == models.Event_Type_Role.principal:
            if not e.Date:
                pass
            elif e.type_id == models.Event_Type.birth:
                if person.birth is None \
                   or person.birth.date_sort > e.date_sort:
                    person.birth = e
            elif e.type_id == models.Event_Type.death:
                if person.death is None \
                   or person.death.date_sort < e.date_sort:
                    person.death = e
            elif e.type_id == models.Event_Type.marriage:
                person.marriage = e

    #########
    # Get all groups to which the personas belong
    #########

    if query_groups:
        groups = models.P2G.objects.select_related('group')
        for gr in sql_in(groups, "person", all_ids):
            p_node = graph.node_from_id(gr.person_id)
            person = persons[p_node.main_id]
            person.all_groups[gr.group_id] = GroupInfo(group=gr.group,
                                                       assertion=gr)
            if gr.source_id:
                src = getattr(gr.group, "sources", [])
                src.append(gr.source_id)
                gr.group.sources = src
            gr.group.role = gr.role

            if schemes is not None:
                schemes.add(gr.surety.scheme_id)

    #########
    # Get all characteristics of these personas
    #########

    p2c = dict()  # characteristic_id -> person
    all_p2c = models.P2C.objects.select_related('characteristic',
                                                'characteristic__place')

    for p in sql_in(all_p2c, "person", all_ids):
        c = p.characteristic
        p_node = graph.node_from_id(p.person_id)
        person = persons[p_node.main_id]
        p2c[c.id] = person

        c.sources = getattr(c, "sources", set())
        c.sources.add(p.source_id)
        c.date = c.date and DateRange(c.date)

        if schemes is not None:
            schemes.add(p.surety.scheme_id)

        person.all_chars[c.id] = CharInfo(char=c, assertion=p, parts=[])

        if compute_parts and c.place:
            places[c.place_id] = c.place

    chars = models.Characteristic_Part.objects.select_related(
        'type', 'characteristic', 'characteristic__place')

    for part in sql_in(chars, "characteristic", nodes and p2c.keys()):
        person = p2c[part.characteristic_id]
        ch = person.all_chars[part.characteristic_id]
        ch.parts.append(CharPartInfo(name=part.type.name, value=part.name))

        if part.type_id == models.Characteristic_Part_Type.sex:
            person.sex = part.name
        elif part.type_id == models.Characteristic_Part_Type.given_name:
            person.given_name = part.name
        elif part.type_id == models.Characteristic_Part_Type.surname:
            person.surname = part.name

    ########
    # Compute place parts once, to limit the number of queries
    # These are only used for styles, not for actual display, although we
    # could benefit from them.
    ########

    if compute_parts:
        prev_place = None
        d = None

        for p in sql_in(
                models.Place_Part.objects.order_by('place').select_related(
                    'type'), "place", places.keys()):

            # ??? We should also check the parent place to gets its own parts
            if p.place_id != prev_place:
                prev_place = p.place_id
                d = dict()
                setattr(places[prev_place], "parts", d)

            d[p.type.name] = p.name

    return persons