gfks
: Utilites for Generic Foreign Keys¶
The lino.modlib.gkfs
plugin adds some utilities for working with
generic foreign keys. You should install it if
your models contain GenericForeignKey fields or inherit from the
Controllable
mixin.
This is a tested document. The following instructions are used for initialization:
>>> from lino import startup
>>> startup('lino_book.projects.min2.settings.demo')
>>> from lino.api.doctest import *
The Controllable
model mixin¶
- class lino.modlib.gkfs.Controllable¶
Mixin for models that are "controllable" by another database object.
Defines three fields
owner_type
,owner_id
andowner
. And a class attributeowner_label
.For example in
lino_xl.lib.cal
, the owner of a calendar entry is some other database object that caused the event's creation.Or in
lino_xl.lib.sales
an invoice may cause one or several Tasks to be automatically generated when a certain payment mode is specified.Controllable objects are "governed" or "controlled" by their controller (stored in a field called
owner
): The controller may decide to delete or modify some or all of her controlled objects.Non-automatic tasks always have an empty
owner
field. Some fields are read-only on an automatic Task because it makes no sense to modify them.- owner¶
- owner_id¶
- owner_type¶
- update_controller_field(cls, verbose_name=None, **kwargs)¶
Update attributes of the
owner
field and its underlying fieldsowner_id
andowner_type
.This can be used to make the controller optional (i.e. specify whether the
owner
field may be NULL). Example:class MyModel(Controllable): .... MyModel.update_controller_field(blank=False, null=False)
When verbose_name is specified, all three fields will be updated, appending " (object)" and " (type)" to
owner_id
andowner_type
respectively.
- update_owned_instance(self, controllable)¶
If this (acting as a controller) is itself controlled, forward the call to the controller.
- owner_label¶
Deprecated. This is (and always was) being ignored. Use
update_controller_field()
instead. The labels (verbose_name) of the fields owned_type, owned_id and owned are derived from this attribute which may be overridden by subclasses.
- controller_is_optional = True
Deprecated. This is (and always was) being ignored. Use
update_controller_field()
instead.
The ContentTypes
table¶
The ContentTypes
table shows all models defined in your application.
>>> rt.show(gfks.ContentTypes)
==== ============== =========================
ID app label python model class name
---- -------------- -------------------------
1 system siteconfig
2 users user
3 users authority
4 countries country
5 countries place
6 contacts uploadvcardfile
7 contacts partner
8 contacts person
9 contacts companytype
10 contacts company
11 contacts roletype
12 contacts role
13 contenttypes contenttype
14 gfks helptext
15 checkdata message
16 cal remotecalendar
17 cal room
18 cal eventtype
19 cal guestrole
20 cal calendar
21 cal subscription
22 cal task
23 cal eventpolicy
24 cal entryrepeater
25 cal recurrentevent
26 cal event
27 cal guest
28 sessions session
==== ============== =========================
Customized help texts¶
Note that customized help texts are currently not being used because they are difficult to maintain and because we now have Help Texts.
- customized help text¶
A help text that has been locally overridden. It is stored in the database and loaded at startup. It can be modified by an end user with appropriate permissions.
- class lino.modlib.gkfs.HelpText¶
Django model to represent a customized help text.
>>> rt.show('gfks.HelpTexts', language="en")
========== =========================== ========================================================== ==== ===========
Field Verbose name HelpText ID Model
---------- --------------------------- ---------------------------------------------------------- ---- -----------
language Language (database field) Die Sprache, in der Dokumente ausgestellt werden sollen. 1 Partner
field Field (database field) The name of the field. 2 Help Text
========== =========================== ========================================================== ==== ===========
Broken GFKs¶
- class lino.modlib.gkfs.BrokenGFKs¶
Shows all database objects that have a broken GeneriForeignKey field.
Fields¶
- class lino.modlib.gkfs.GenericForeignKey¶
Add verbose_name and help_text to Django's GFK.
Used by
Controllable
.
- class lino.modlib.gkfs.GenericForeignKeyIdField¶
Use this instead of models.PositiveIntegerField for fields that are part of a GFK and you want Lino to render them using a Combobox.
Used by
lino.modlib.gfks.mixins.Controllable
.Note: type_field is a mandatory argument, but you can specify anything because it is being ignored.
The gfk2lookup()
function¶
The gfk2lookup
function is mostly for
internal use, but occasionally you might want to use it in your application
code.
>>> from lino.core.utils import full_model_name as fmn
>>> from lino.core.gfks import gfk2lookup
>>> from lino.modlib.gfks.mixins import Controllable
List of models which inherit from Controllable
:
>>> print(' '.join([fmn(m) for m in rt.models_by_base(Controllable)]))
cal.Event cal.Task checkdata.Message
>>> obj = contacts.Person.objects.all()[0]
>>> d = gfk2lookup(cal.Event.owner, obj)
>>> pprint(d)
{'owner_id': 114, 'owner_type': <ContentType: Person>}
If the object has a non-integer primary key, then it cannot be target of a GFK. In this case we filter only on the content type because anyway the list will be empty. countries.Country is actually the only model with a non-integer primary key.
>>> obj = countries.Country.objects.all()[0]
>>> gfk2lookup(cal.Event.owner, obj)
{'owner_type': <ContentType: Country>}