Welcome | Get started | Dive | Contribute | Topics | Reference | Changes | More
households
: Handling households and their members¶
This page assumes you have read The households plugin.
Side note: Code snippets (lines starting with >>>
) in this document get
tested as part of our development workflow. The following
initialization snippet tells you which demo project is being used in
this document.
>>> import lino
>>> lino.startup('lino_book.projects.avanti1.settings')
>>> from lino.api.doctest import *
Households¶
- class lino_xl.lib.households.Household¶
Django model to represent a household.
- type¶
The type of this household. See household types
- create_household(cls, ar, head, partner, type)¶
Create a household with the given head, partner and type.
A household is a subclass of lino_xl.lib.contacts.Partner
.
>>> issubclass(households.Household, contacts.Partner)
True
Household types¶
There are different types of households.
- class lino_xl.lib.households.Type¶
Django model to represent a household type.
>>> rt.show(households.Types)
==== ==================== ========================= ======================
ID Designation Designation (de) Designation (fr)
---- -------------------- ------------------------- ----------------------
1 Married couple Ehepaar Couple marié
2 Divorced couple Geschiedenes Paar Couple divorcé
3 Factual household Faktischer Haushalt Cohabitation de fait
4 Legal cohabitation Legale Wohngemeinschaft Cohabitation légale
5 Isolated Getrennt Isolé
6 Other Sonstige Autre
==== ==================== ========================= ======================
Memberships¶
- class lino_xl.lib.households.Member¶
Django model to represent a household membership.
- household¶
- person¶
- role¶
- dependency¶
- primary¶
Whether this is the primary household of this person. Checking this field will automatically disable any other primary memberships.
- start_date¶
Since when this membership exists. This is usually empty.
- end_date¶
Until when this membership exists.
- class lino_xl.lib.households.Members¶
- class lino_xl.lib.households.MembersByHousehold¶
- class lino_xl.lib.households.PopulateMembers¶
Populate household members from data in human links.
The default role of a new household member is “Child”. A household member can either refer to an existing person, of e.g. specify only a first name.
>>> m = households.Member(first_name="Tom")
>>> print(m)
Tom (Child)
>>> p = contacts.Person.objects.first()
>>> m = households.Member(person=p)
>>> print(m)
Mr Aábdeen Abad (Child)
>>> print(p)
Mr Aábdeen Abad
Configuration¶
- class lino_xl.lib.households.MemberRoles¶
The list of allowed choices for the role of a household member.
See
role
.
>>> rt.show('households.MemberRoles')
======= ============ ===================
value name text
------- ------------ -------------------
01 head Head of household
02 spouse Spouse
03 partner Partner
04 cohabitant Cohabitant
05 child Child
06 relative Relative
07 adopted Adopted child
08 foster Foster-child
10 other Other
======= ============ ===================
How to represent a household member¶
SiblingsByPerson¶
The SiblingsByPerson
table shows the family composition of a person,
i.e. all members of the current household of that person.
>>> SiblingsByPerson = rt.models.households.SiblingsByPerson
This works of course only when Lino can determine the “one and only” current household. If the person has only one membership (at a given date), then there is no question.
When there are several memberships, then ideally one of them should be marked as primary.
But even when a person has multiple household memberships and none of them is primary, Lino can look at the end_date.
The active household is determined as follows:
If the person has only one household, use this.
Otherwise, if one household is marked as primary, use this.
Otherwise, if there is exactly one membership whose end_date is either empty or in the future, take this.
If no active household can be determined, the panel just displays an appropriate message.
Let’s get a list of the candidates to inspect:
>>> Person = rt.models.contacts.Person
>>> Member = rt.models.households.Member
>>> MemberRoles = rt.models.households.MemberRoles
>>> heads = Person.objects.filter(household_members__role=MemberRoles.head).distinct()
>>> for m in heads.order_by('id'):
... qs = Member.objects.filter(role=MemberRoles.head, person=m.person)
... all = qs.count()
... primary = qs.filter(primary=True).count()
... if all > 1 and not primary:
... print("{} ({}) is head of {} households".format(
... m.person, m.person.pk, all))
Mr Aleksándr Alvang (178) is head of 2 households
The most interesting is Aleksándr Alvang (178):
>>> ses = rt.login('robin')
>>> p = Person.objects.get(pk=178)
>>> ses.show('households.MembersByPerson', master_instance=p)
Mr Aleksándr Alvang is
`☐ <javascript:window.App.runAction({ "actorId": "households.Members", "an": "set_primary", "onMain": false, "rp": null, "sr": 11, "status": { } })>`__Head of household in `Aleksándr & Agápiiá Alvang-Bek-Murzin (Other) <…>`__
`☐ <javascript:window.App.runAction({ "actorId": "households.Members", "an": "set_primary", "onMain": false, "rp": null, "sr": 5, "status": { } })>`__Head of household in `Aleksándr & Cátává Alvang-Maalouf (Factual household) <…>`__
**Join an existing household** or **create a new one**.
>>> ses.show('households.MembersByPerson', p, nosummary=True)
======================================================= =================== ========= ============ ============
Household Role Primary Start date End date
------------------------------------------------------- ------------------- --------- ------------ ------------
Aleksándr & Agápiiá Alvang-Bek-Murzin (Other) Head of household No
Aleksándr & Cátává Alvang-Maalouf (Factual household) Head of household No 04/03/2002
======================================================= =================== ========= ============ ============
>>> rt.show(SiblingsByPerson, p)
========== =================== ======================== ============ ============ ======== ============ ============= ========
Age Role Person First name Last name Gender Birth date Nationality School
---------- ------------------- ------------------------ ------------ ------------ -------- ------------ ------------- --------
43 years Partner Mrs Agápiiá Bek-Murzin Agápiiá Bek-Murzin Female 1973-09-04
23 years Head of household Mr Aleksándr Alvang Aleksándr Alvang Male 1993-09-09
========== =================== ======================== ============ ============ ======== ============ ============= ========
Let’s use the get_json_soup
function
to analyze
>>> avanti.Client.objects.get(pk=178).user.username
'romain'
>>> soup = get_json_soup('romain', 'avanti/MyClients/178', 'households.MembersByPerson')
>>> links = soup.find_all('a')
>>> len(links)
6
>>> print(links[4].string)
Joindre un ménage existant
>>> print(links[4].get('href'))
...
javascript:window.App.runAction({ "actorId": "households.MembersByPerson", "an":
"insert", "onMain": false, "rp": null, "status": { "base_params": { "mk": 178,
"mt": ..., "person": 178 }, "data_record": { "data": { "disabled_fields": {
"birth_date": true, "first_name": true, "gender": true, "last_name": true },
"household": null, "householdHidden": null, "person": "ALVANG Aleks\u00e1ndr
(178/romain)", "personHidden": 178, "primary": false, "role": "Enfant",
"roleHidden": "05" }, "phantom": true, "title": "Ins\u00e9rer Membre de m\u00e9nage" }, "param_values": { "aged_from": null, "aged_to": null, "end_date":
null, "gender": null, "genderHidden": null, "start_date": null }, "record_id":
null } })
Class reference¶
- class lino_xl.lib.households.Households¶
- class lino_xl.lib.households.HouseholdsByType¶
- class lino_xl.lib.households.Types¶
- class lino_xl.lib.households.MemberDependencies¶
The list of allowed choices for the charge of a household member.
Don’t read on¶
The following covers a problem that occurred 20181023 and was detected by welfare but not yet by book.
>>> ses = rt.login('romain')
>>> print(p.id)
178
>>> test_client.force_login(ses.user)
>>> def check(uri, fieldname):
... url = '/api/%s?fmt=json&an=detail' % uri
... res = test_client.get(url, REMOTE_USER=ses.user.username)
... assert res.status_code == 200
... d = json.loads(res.content)
... if not fieldname in d['data']:
... raise Exception("20181023 '{}' not in {}".format(
... fieldname, d['data'].keys()))
... return d['data'][fieldname]
>>> uri = 'avanti/MyClients/{}'.format(p.id)
>>> html = check(uri, 'households.MembersByPerson')
>>> soup = beautiful_soup(html)
>>> links = soup.find_all('a')
>>> len(links)
6