|pypi| |actions| |coverage|
edc-identifier
--------------
Add research subject identifiers and other useful identifiers to your project
Installation
------------
Add to settings:
.. code-block:: python
INSTALLED_APPS = [
...
'edc_identifier.apps.AppConfig',
...
]
Identifiers for research subjects
---------------------------------
Create subject identifiers.
.. code-block:: python
from edc_identifier.subject_identifier import SubjectIdentifier
subject_identifier = SubjectIdentifier(
subject_type_name='subject',
model='edc_example.enrollment',
protocol='000',
device_id='99',
study_site='40')
>>> subject_identifier.identifier
'000-40990001-6'
Maternal and Infant Identifiers
-------------------------------
See also, ``edc_pregnancy`` model mixins ``DeliveryMixin``, ``BirthMixin``.
For example:
.. code-block:: python
from edc_identifier.maternal_identifier import MaternalIdentifier
maternal_identifier = MaternalIdentifier(
subject_type_name='maternal',
model='edc_example.enrollment',
study_site='40',
last_name='Carter')
>>> maternal_identifier.identifier
'000-40990001-6'
Add infants
.. code-block:: python
>>> maternal_identifier.deliver(2, model='edc_example.maternallabdel')
>>> [infant.identifier for infant in maternal_identifier.infants]
['000-40990001-6-25', '000-40990001-6-26']
``maternal_identifier.infants`` is a list of ``InfantIdentifier`` instances
Reload class:
.. code-block:: python
>>> maternal_identifier = MaternalIdentifier(identifier='000-40990001-6')
>>> maternal_identifier.identifier
'000-40990001-6'
>>> [infant.identifier for infant in maternal_identifier.infants]
['000-40990001-6-25', '000-40990001-6-26']
Only allocate an identifier to one infant of twins:
.. code-block:: python
>>> maternal_identifier.deliver(2, model='edc_example.maternallabdel', birth_orders='2')
>>> [infant.identifier for infant in maternal_identifier.infants]
[None, '000-40990001-6-26']
Of triplets, allocate identifiers to the 2nd and 3rd infants only:
.. code-block:: python
>>> maternal_identifier.deliver(3, model='edc_example.maternallabdel', birth_orders='2,3')
>>> [infant.identifier for infant in maternal_identifier.infants]
[None, '000-40990001-6-37', '000-40990001-6-38']
Research subject identifier classes can create a Registered Subject instance
See also ``edc_registration``
``SubjectIdentifier`` by default does not create a ``RegisteredSubject`` instance unless ``create_registration=True``.
By default, ``MaternalIdentifier`` and ``InfantIdentifier`` create ``RegisteredSubject`` instances that can be updated with full details later with the Delivery and Birth models. Continuing from above:
.. code-block:: python
maternal_identifier = MaternalIdentifier(identifier='000-40990001-6')
maternal_identifier.deliver(1, model='edc_example.maternallabdel', create_registration=True)
# mother
>>> RegisteredSubject.objects.get(subject_identifier='000-40990001-6')
<RegisteredSubject '000-40990001-6'>
# infant is linked to the mother
>>> RegisteredSubject.objects.get(linked_identifier='000-40990001-6')
<RegisteredSubject '000-40990001-6-10'>
# infant
>>> obj = RegisteredSubject.objects.get(subject_identifier='000-40990001-6-10')
>>> obj.first_name
'Baby1Carter' ## generates a temp name until Birth form is added with complete information.
>>> obj.relative_identifier
'000-40990001-6'
Subject type "Caps" are enforced by the research subject identifier classes
See also ``edc_protocol``
Limits on the number of identifiers that can be allocated per subject type are enforced when identifiers are created. ``edc_identifier`` reads the "caps" from ``edc_protocol.apps.AppConfig`` linking the subject type, e.g. ``subject``, or ``maternal`` or ``infant``, to the relevant cap and not allowing the number of allocated identifiers to exceed the cap.
(Subject type "Caps" still working? needs to be verified)
Numeric Identifiers
-------------------
The numeric identifier uses a check-digit and may have a separator if specified.
.. code-block:: python
from edc_identifier import NumericIdentifier
class MyIdentifier(NumericIdentifier):
pass
>>> id = MyIdentifier(None)
>>> id
MyIdentifier('00000000018')
>>> next(id)
'00000000026'
>>> next(id)
'00000000034'
# add a separator
class MyIdentifier(NumericIdentifier):
identifier_pattern = r'^[0-9]{4}\-[0-9]{4}\-[0-9]{4}$'
checkdigit_pattern = r'^\-[0-9]{1}$'
separator = '-'
seed = ['3200-0000-0000']
>>> id = MyIdentifier(None)
>>> id
MyIdentifier('3200-0000-0001-1')
>>> next(id)
'3200-0000-0002-9'
>>> next(id)
'3200-0000-0003-7'
# start from the last identifier, increment is immediate and automatic
>>> id = MyIdentifier('3200-0000-3222-0')
>>> id
MyIdentifier('3200-0000-3223-8')
Alphanumeric Identifiers
------------------------
.. code-block:: python
from edc_identifier import AlphanumericIdentifier
class MyIdentifier(AlphanumericIdentifier):
alpha_pattern = r'^[A-Z]{3}$'
numeric_pattern = r'^[0-9]{4}$'
seed = ['AAA', '0000']
>>> id = MyIdentifier(None)
>>> id
MyIdentifier('AAA00015')
Your identifier will starts with 'AAA0001' plus the checkdigit "5". Subsequent calls to next increment like this:
.. code-block:: python
>>> print(next(id))
AAA00023
>>> print(next(id))
AAA00031
>>> print(next(id))
AAA00049
The identifier increments on the numeric sequence then the alpha:
.. code-block:: python
>>> id = MyIdentifier('AAA99991)
>>> id
MyIdentifier('AAB00013')
>>> next(id)
'AAB00021'
>>> next(id)
'AAB00039'
>>> next(id)
'AAB00047'
>>> id = MyIdentifier('AAB99999')
>>> id
MyIdentifier('AAC00010')
...
See ``getresults-receive`` for sample usage with ``settings`` and a ``History`` model.
Short Identifiers
-----------------
Creates a small identifier that is almost unique, for example, across 25 Edc devices in a community. We use these as sample requisition identifiers that are transcribed manually onto a tube from the Edc screen in a household. Once the sample is received at the local lab it is allocated a laboratory-wide unique specimen identifier.
.. code-block:: python
from edc_identifier import ShortIdentifier
>>> ShortIdentifier()
ShortIdentifier('46ZZ2')
Add a static prefix -- ``prefix(2) + identifier(5)``:
.. code-block:: python
from edc_identifier import ShortIdentifier
class MyIdentifier(ShortIdentifier):
prefix_pattern = r'^[0-9]{2}$'
>>> options = {'prefix': 22}
>>> id = MyIdentifier(options=options)
>>> id
MyIdentifier('22UYMBT')
>>> next(id)
'22KM84G'
Add a checkdigit -- ``prefix(2) + identifier(5) + checkdigit(1)``:
.. code-block:: python
from edc_identifier import ShortIdentifier
class MyIdentifier(ShortIdentifier):
prefix_pattern = r'^[0-9]{2}$'
checkdigit_pattern = r'^[0-9]{1}$'
>>> options = {'prefix': 22}
>>> id = MyIdentifier(options=options)
>>> id
MyIdentifier('223GF8A3')
>>> next(id)
'22DXVW23'
We use this in edc-quota to get a confirmation code:
.. code-block:: python
from edc_identifier import ShortIdentifier
class ConfirmationCode(ShortIdentifier):
identifier_type = 'confirmation'
prefix_pattern = ''
>>> code = ConfirmationCode()
>>> print(code)
CAT33
>>> next(code)
3FU7D
Add more to the prefix, such as device code and community code.
.. code-block:: python
from edc_identifier.short_identifier import ShortIdentifier
class RequisitionIdentifier(ShortIdentifier):
identifier_type = 'requisition'
prefix_pattern = r'^[0-9]{4}$'
template = '{device_id}{community_id}{random_string}'
@property
def options(self):
if 'prefix' not in self._options:
self._options.update(
{'prefix': str(self._options.get('device_id')) + str(self._options.get('community_id'))})
return self._options
>>> options = {'device_id': 22, 'community_id': '12'}
>>> id = RequisitionIdentifier(options=options)
>>> id
RequisitionIdentifier('22126MZXD')
>>> next(id)
'2212Y899C'
... if you prefer not to use the ``IdentifierHistory`` model, for example, if you are filling in a model field on ``save()``:
.. code-block:: python
from my_app.models import Requisition
class RequisitionIdentifier(ShortIdentifier):
identifier_type = 'requisition'
requisition_model = Requisition
def is_duplicate(self, identifier):
try:
self.requisition_model.get(requisition_identifier=identifier)
return True
except self.requisition_model.DoesNotExist:
pass
return False
def update_history(self):
pass
Batch Identifier
----------------
To have an identifier prefixed by the current date stamp:
.. code-block:: python
from edc_identifier.batch_identifier import BatchIdentifier
>>> datetime.today().strftime('%Y%m%d)
20150817
>>> id = BatchIdentifier()
>>> id
BatchIdentifier('201508170001')
>>> next(id)
'201508170002'
.. |pypi| image:: https://img.shields.io/pypi/v/edc-identifier.svg
:target: https://pypi.python.org/pypi/edc-identifier
.. |actions| image:: https://github.com/clinicedc/edc-identifier/workflows/build/badge.svg?branch=develop
:target: https://github.com/clinicedc/edc-identifier/actions?query=workflow:build
.. |coverage| image:: https://coveralls.io/repos/github/clinicedc/edc-identifier/badge.svg?branch=develop
:target: https://coveralls.io/github/clinicedc/edc-identifier?branch=develop