|pypi| |actions| |codecov| |downloads|
edc-visit-tracking
------------------
Track study participant visit reports.
Declaring a visit model
+++++++++++++++++++++++
A **visit_model** is declared using the model mixin `VisitModelMixin`. Normally, a **visit_model** will be declared with additional model mixins, but `VisitModelMixin` must be there.
.. code-block:: python
class SubjectVisit(VisitModelMixin, BaseUuidModel):
...
Also, ensure the `Meta` class attributes of `VisitModelMixin` are inherited. These include required constraints and ordering.
.. code-block:: python
class SubjectVisit(VisitModelMixin, BaseUuidModel):
...
class Meta(VisitModelMixin.Meta):
pass
Among other features, `VisitModelMixin` adds a `OneToOneField` foreign key to the **visit_model** that points to `edc_appointment.Appointment`.
Important: A **visit model** is a special model in the EDC. A model declared with the model mixin, `VisitModelMixin`, is the definition of a **visit model**. CRFs and Requisitions have a foreign key pointing to a **visit model**. A number of methods on CRFs and Requisitions detect their **visit model** foreign key name, model class and value by looking for the FK declared with `VisitModelMixin`.
For a subject that requires ICF the **visit model** would use the `RequiresConsentModelMixin`:
.. code-block:: python
class SubjectVisit(
VisitModelMixin,
RequiresConsentFieldsModelMixin,
BaseUuidModel,
):
class Meta(VisitModelMixin.Meta, BaseUuidModel.Meta):
pass
If the subject does not require ICF, such as an infant, don't include the `RequiresConsentModelMixin`:
.. code-block:: python
class InfantVisit(
VisitModelMixin,
BaseUuidModel
):
class Meta(VisitModelMixin.Meta, , BaseUuidModel.Meta):
pass
A more complete declaration will include model mixins from other libraries. For example:
.. code-block:: python
from edc_consent.model_mixins import RequiresConsentFieldsModelMixin
from edc_metadata.model_mixins.creates import CreatesMetadataModelMixin
from edc_model.models import BaseUuidModel
from edc_offstudy.model_mixins import OffstudyVisitModelMixin
from edc_sites.managers import CurrentSiteManager
from edc_sites.model_mixins import SiteModelMixin
from edc_visit_tracking.managers import VisitModelManager
from edc_visit_tracking.model_mixins import VisitModelMixin
class SubjectVisit(
SiteModelMixin,
VisitModelMixin,
CreatesMetadataModelMixin,
RequiresConsentFieldsModelMixin,
OffstudyNonCrfModelMixin,
BaseUuidModel,
):
objects = VisitModelManager()
on_site = CurrentSiteManager()
history = edc_models.HistoricalRecords()
class Meta(VisitModelMixin.Meta, BaseUuidModel.Meta):
pass
Declaring a CRF
+++++++++++++++
The `CrfModelMixin` is required for all CRF models. CRF models have a `OneToOneField` key to a **visit model**.
.. code-block:: python
class CrfOne(CrfModelMixin, OffstudyCrfModelMixin, RequiresConsentModelMixin,
UpdatesCrfMetadataModelMixin, BaseUuidModel):
subject_visit = models.OneToOneField(SubjectVisit)
f1 = models.CharField(max_length=10, default='erik')
vl = models.CharField(max_length=10, default=NO)
rdb = models.CharField(max_length=10, default=NO)
class Meta:
consent_model = 'myapp.subjectconsent' # for RequiresConsentModelMixin
Declaring forms:
++++++++++++++++
The `VisitFormMixin` includes a number of common validations in the `clean` method:
.. code-block:: python
class SubjectVisitForm(VisitFormMixin, FormValidatorMixin, forms.ModelForm):
form_validator_cls = VisitFormValidator
class Meta:
model = SubjectVisit
`PreviousVisitModelMixin`
+++++++++++++++++++++++++
The `PreviousVisitModelMixin` ensures that visits are entered in sequence. It is included with the `VisitModelMixin`.
`VisitTrackingModelFormMixin`
+++++++++++++++++++++++++++++
see `DEFAULT_REPORT_DATETIME_ALLOWANCE`
Missed Visit Report
+++++++++++++++++++
A detail report should be submitted for scheduled visits that are missed.
By selecting the reason ``missed visit`` on ``SubjectVisit``, only the missed visit CRF will be required
for the timepoint. All other CRFs and requisitions will be excluded.
Unscheduled visits cannot be missed. (To change this behaviour see `settings` attrubute `EDC_VISIT_TRACKING_ALLOW_MISSED_UNSCHEDULED`)
The model mixin ``SubjectVisitMissedModelMixin`` provides the basic features of a `SubjectVisitMissed` model.
In your subject app declare:
.. code-block:: python
from django.db.models import PROTECT
from edc_crf.model_mixins import CrfWithActionModelMixin
from edc_model import models as edc_models
from edc_visit_tracking.model_mixins import SubjectVisitMissedModelMixin
class SubjectVisitMissed(SubjectVisitMissedModelMixin, edc_models.BaseUuidModel):
missed_reasons = models.ManyToManyField(
SubjectVisitMissedReasons, blank=True, related_name="+"
)
class Meta(CrfWithActionModelMixin.Meta, edc_models.BaseUuidModel.Meta):
verbose_name = "Missed Visit Report"
verbose_name_plural = "Missed Visit Report"
In your list model app, e.g. ``meta_lists``, declare the list model:
.. code-block:: python
class SubjectVisitMissedReasons(ListModelMixin):
class Meta(ListModelMixin.Meta):
verbose_name = "Subject Missed Visit Reasons"
verbose_name_plural = "Subject Missed Visit Reasons"
... and update the ``list_data`` dictionary, for example:
.. code-block:: python
list_data = {
...
"meta_lists.subjectvisitmissedreasons": [
("forgot", "Forgot / Can’t remember being told about appointment"),
("family_emergency", "Family emergency (e.g. funeral) and was away"),
("travelling", "Away travelling/visiting"),
("working_schooling", "Away working/schooling"),
("too_sick", "Too sick or weak to come to the centre"),
("lack_of_transport", "Transportation difficulty"),
(OTHER, "Other reason (specify below)",),
],
...
}
Window period
+++++++++++++
By default, the visit `report_datetime` is validated to stay within the same window period as the appointment.
This may be too restrictive in some cases.
To bypass this override ```validate_visit_datetime_in_window_period``` in the ```VisitFormValidator```
.. code-block:: python
from edc_visit_tracking.form_validators import VisitFormValidator as BaseVisitFormValidator
class VisitFormValidator(BaseVisitFormValidator):
...
def validate_visit_datetime_in_window_period():
pass
...
Be sure that your appointment form validator is enforcing window periods before
bypassing this check.
See also `edc_appointment`.
.. |pypi| image:: https://img.shields.io/pypi/v/edc-visit-tracking.svg
:target: https://pypi.python.org/pypi/edc-visit-tracking
.. |actions| image:: https://github.com/clinicedc/edc-visit-tracking/actions/workflows/build.yml/badge.svg
:target: https://github.com/clinicedc/edc-visit-tracking/actions/workflows/build.yml
.. |codecov| image:: https://codecov.io/gh/clinicedc/edc-visit-tracking/branch/develop/graph/badge.svg
:target: https://codecov.io/gh/clinicedc/edc-visit-tracking
.. |downloads| image:: https://pepy.tech/badge/edc-visit-tracking
:target: https://pepy.tech/project/edc-visit-tracking
Raw data
{
"_id": null,
"home_page": "https://github.com/clinicedc/edc-visit-tracking",
"name": "edc-visit-tracking",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.11",
"maintainer_email": null,
"keywords": "django, edc, visit tracking, clinicedc, clinical trials",
"author": "Erik van Widenfelt",
"author_email": "ew2789@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/06/81/883dd2c2717ae15ee22f4e40fa59bd419939d769bd8f3029914ab45e852d/edc-visit-tracking-0.3.91.tar.gz",
"platform": null,
"description": "|pypi| |actions| |codecov| |downloads|\n\nedc-visit-tracking\n------------------\n\nTrack study participant visit reports.\n\n\nDeclaring a visit model\n+++++++++++++++++++++++\n\nA **visit_model** is declared using the model mixin `VisitModelMixin`. Normally, a **visit_model** will be declared with additional model mixins, but `VisitModelMixin` must be there.\n\n\n.. code-block:: python\n\n class SubjectVisit(VisitModelMixin, BaseUuidModel):\n ...\n\nAlso, ensure the `Meta` class attributes of `VisitModelMixin` are inherited. These include required constraints and ordering.\n\n\n.. code-block:: python\n\n class SubjectVisit(VisitModelMixin, BaseUuidModel):\n\n ...\n\n class Meta(VisitModelMixin.Meta):\n pass\n\nAmong other features, `VisitModelMixin` adds a `OneToOneField` foreign key to the **visit_model** that points to `edc_appointment.Appointment`.\n\n Important: A **visit model** is a special model in the EDC. A model declared with the model mixin, `VisitModelMixin`, is the definition of a **visit model**. CRFs and Requisitions have a foreign key pointing to a **visit model**. A number of methods on CRFs and Requisitions detect their **visit model** foreign key name, model class and value by looking for the FK declared with `VisitModelMixin`.\n\n\nFor a subject that requires ICF the **visit model** would use the `RequiresConsentModelMixin`:\n\n.. code-block:: python\n\n class SubjectVisit(\n VisitModelMixin,\n RequiresConsentFieldsModelMixin,\n BaseUuidModel,\n ):\n\n class Meta(VisitModelMixin.Meta, BaseUuidModel.Meta):\n pass\n\n\nIf the subject does not require ICF, such as an infant, don't include the `RequiresConsentModelMixin`:\n\n.. code-block:: python\n\n class InfantVisit(\n VisitModelMixin,\n BaseUuidModel\n ):\n\n class Meta(VisitModelMixin.Meta, , BaseUuidModel.Meta):\n pass\n\n\nA more complete declaration will include model mixins from other libraries. For example:\n\n.. code-block:: python\n\n from edc_consent.model_mixins import RequiresConsentFieldsModelMixin\n from edc_metadata.model_mixins.creates import CreatesMetadataModelMixin\n from edc_model.models import BaseUuidModel\n from edc_offstudy.model_mixins import OffstudyVisitModelMixin\n from edc_sites.managers import CurrentSiteManager\n from edc_sites.model_mixins import SiteModelMixin\n from edc_visit_tracking.managers import VisitModelManager\n from edc_visit_tracking.model_mixins import VisitModelMixin\n\n class SubjectVisit(\n SiteModelMixin,\n VisitModelMixin,\n CreatesMetadataModelMixin,\n RequiresConsentFieldsModelMixin,\n OffstudyNonCrfModelMixin,\n BaseUuidModel,\n ):\n\n objects = VisitModelManager()\n\n on_site = CurrentSiteManager()\n\n history = edc_models.HistoricalRecords()\n\n class Meta(VisitModelMixin.Meta, BaseUuidModel.Meta):\n pass\n\nDeclaring a CRF\n+++++++++++++++\n\nThe `CrfModelMixin` is required for all CRF models. CRF models have a `OneToOneField` key to a **visit model**.\n\n.. code-block:: python\n\n class CrfOne(CrfModelMixin, OffstudyCrfModelMixin, RequiresConsentModelMixin,\n UpdatesCrfMetadataModelMixin, BaseUuidModel):\n\n subject_visit = models.OneToOneField(SubjectVisit)\n\n f1 = models.CharField(max_length=10, default='erik')\n\n vl = models.CharField(max_length=10, default=NO)\n\n rdb = models.CharField(max_length=10, default=NO)\n\n class Meta:\n consent_model = 'myapp.subjectconsent' # for RequiresConsentModelMixin\n\nDeclaring forms:\n++++++++++++++++\nThe `VisitFormMixin` includes a number of common validations in the `clean` method:\n\n.. code-block:: python\n\n class SubjectVisitForm(VisitFormMixin, FormValidatorMixin, forms.ModelForm):\n\n form_validator_cls = VisitFormValidator\n\n class Meta:\n model = SubjectVisit\n\n`PreviousVisitModelMixin`\n+++++++++++++++++++++++++\n\nThe `PreviousVisitModelMixin` ensures that visits are entered in sequence. It is included with the `VisitModelMixin`.\n\n`VisitTrackingModelFormMixin`\n+++++++++++++++++++++++++++++\n\n see `DEFAULT_REPORT_DATETIME_ALLOWANCE`\n\n\nMissed Visit Report\n+++++++++++++++++++\n\nA detail report should be submitted for scheduled visits that are missed.\nBy selecting the reason ``missed visit`` on ``SubjectVisit``, only the missed visit CRF will be required\nfor the timepoint. All other CRFs and requisitions will be excluded.\n\nUnscheduled visits cannot be missed. (To change this behaviour see `settings` attrubute `EDC_VISIT_TRACKING_ALLOW_MISSED_UNSCHEDULED`)\n\nThe model mixin ``SubjectVisitMissedModelMixin`` provides the basic features of a `SubjectVisitMissed` model.\n\nIn your subject app declare:\n\n.. code-block:: python\n\n from django.db.models import PROTECT\n from edc_crf.model_mixins import CrfWithActionModelMixin\n from edc_model import models as edc_models\n from edc_visit_tracking.model_mixins import SubjectVisitMissedModelMixin\n\n class SubjectVisitMissed(SubjectVisitMissedModelMixin, edc_models.BaseUuidModel):\n\n missed_reasons = models.ManyToManyField(\n SubjectVisitMissedReasons, blank=True, related_name=\"+\"\n )\n\n class Meta(CrfWithActionModelMixin.Meta, edc_models.BaseUuidModel.Meta):\n verbose_name = \"Missed Visit Report\"\n verbose_name_plural = \"Missed Visit Report\"\n\nIn your list model app, e.g. ``meta_lists``, declare the list model:\n\n.. code-block:: python\n\n class SubjectVisitMissedReasons(ListModelMixin):\n class Meta(ListModelMixin.Meta):\n verbose_name = \"Subject Missed Visit Reasons\"\n verbose_name_plural = \"Subject Missed Visit Reasons\"\n\n... and update the ``list_data`` dictionary, for example:\n\n.. code-block:: python\n\n list_data = {\n ...\n \"meta_lists.subjectvisitmissedreasons\": [\n (\"forgot\", \"Forgot / Can\u2019t remember being told about appointment\"),\n (\"family_emergency\", \"Family emergency (e.g. funeral) and was away\"),\n (\"travelling\", \"Away travelling/visiting\"),\n (\"working_schooling\", \"Away working/schooling\"),\n (\"too_sick\", \"Too sick or weak to come to the centre\"),\n (\"lack_of_transport\", \"Transportation difficulty\"),\n (OTHER, \"Other reason (specify below)\",),\n ],\n ...\n }\n\n\nWindow period\n+++++++++++++\n\nBy default, the visit `report_datetime` is validated to stay within the same window period as the appointment.\nThis may be too restrictive in some cases.\n\nTo bypass this override ```validate_visit_datetime_in_window_period``` in the ```VisitFormValidator```\n\n.. code-block:: python\n\n from edc_visit_tracking.form_validators import VisitFormValidator as BaseVisitFormValidator\n\n class VisitFormValidator(BaseVisitFormValidator):\n\n ...\n\n def validate_visit_datetime_in_window_period():\n pass\n\n ...\n\nBe sure that your appointment form validator is enforcing window periods before\nbypassing this check.\n\nSee also `edc_appointment`.\n\n\n.. |pypi| image:: https://img.shields.io/pypi/v/edc-visit-tracking.svg\n :target: https://pypi.python.org/pypi/edc-visit-tracking\n\n.. |actions| image:: https://github.com/clinicedc/edc-visit-tracking/actions/workflows/build.yml/badge.svg\n :target: https://github.com/clinicedc/edc-visit-tracking/actions/workflows/build.yml\n\n.. |codecov| image:: https://codecov.io/gh/clinicedc/edc-visit-tracking/branch/develop/graph/badge.svg\n :target: https://codecov.io/gh/clinicedc/edc-visit-tracking\n\n.. |downloads| image:: https://pepy.tech/badge/edc-visit-tracking\n :target: https://pepy.tech/project/edc-visit-tracking\n",
"bugtrack_url": null,
"license": "GPL license, see LICENSE",
"summary": "Base classes for visit reports/tracking in clinicedc/edc",
"version": "0.3.91",
"project_urls": {
"Homepage": "https://github.com/clinicedc/edc-visit-tracking"
},
"split_keywords": [
"django",
" edc",
" visit tracking",
" clinicedc",
" clinical trials"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "194593200171cc0a85b06c374dd2470b14430d22d2e43ae5b9846a0585d15859",
"md5": "6b4cbe84ac7756c81f1e8b4cf629835d",
"sha256": "b5591b98ade130782ebc6fd3ce14e3fcc583f6274f233c03e335f36c9e29f317"
},
"downloads": -1,
"filename": "edc_visit_tracking-0.3.91-py3-none-any.whl",
"has_sig": false,
"md5_digest": "6b4cbe84ac7756c81f1e8b4cf629835d",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.11",
"size": 87270,
"upload_time": "2024-03-27T03:56:00",
"upload_time_iso_8601": "2024-03-27T03:56:00.373232Z",
"url": "https://files.pythonhosted.org/packages/19/45/93200171cc0a85b06c374dd2470b14430d22d2e43ae5b9846a0585d15859/edc_visit_tracking-0.3.91-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "0681883dd2c2717ae15ee22f4e40fa59bd419939d769bd8f3029914ab45e852d",
"md5": "2728f48e764180a3f98e587e36373cbd",
"sha256": "0726288981e4c962400a5ae3012cec37f63d7ac50a9fee7f984e53346e7e9d76"
},
"downloads": -1,
"filename": "edc-visit-tracking-0.3.91.tar.gz",
"has_sig": false,
"md5_digest": "2728f48e764180a3f98e587e36373cbd",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.11",
"size": 65673,
"upload_time": "2024-03-27T03:56:03",
"upload_time_iso_8601": "2024-03-27T03:56:03.859235Z",
"url": "https://files.pythonhosted.org/packages/06/81/883dd2c2717ae15ee22f4e40fa59bd419939d769bd8f3029914ab45e852d/edc-visit-tracking-0.3.91.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-03-27 03:56:03",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "clinicedc",
"github_project": "edc-visit-tracking",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"lcname": "edc-visit-tracking"
}