|pypi| |actions| |codecov| |downloads|
edc-sites
---------
Site definitions to work with Django's `Sites Framework`__ and django_multisite_.
Define a ``sites.py``. This is usually in a separate project module. For example, for project ``meta`` there is a module ``meta_sites`` that contains a ``sites.py``.
Register your sites in ``sites.py``.
.. code-block:: python
# sites.py
from edc_sites.site import sites
from edc_sites.single_site import SingleSite
suffix = "example.clinicedc.org"
sites.register(
SingleSite(
10,
"hindu_mandal",
title="Hindu Mandal Hospital",
country="tanzania",
country_code="tz",
domain=f"hindu_mandal.tz.{suffix}",
),
SingleSite(
20,
"amana",
title="Amana Hospital",
country="tanzania",
country_code="tz",
domain=f"amana.tz.{suffix}",
),
)
A ``post_migrate`` signal is registered in ``apps.py`` to update the django model ``Site`` and the
EDC model ``SiteProfile`` on the next migration:
.. code-block:: python
# apps.py
from edc_sites.add_or_update_django_sites import add_or_update_django_sites
def post_migrate_update_sites(sender=None, **kwargs):
sys.stdout.write(style.MIGRATE_HEADING("Updating sites:\n"))
add_or_update_django_sites(verbose=True)
sys.stdout.write("Done.\n")
sys.stdout.flush()
Now in your code you can use the ``sites`` global to inspect the trial sites:
.. code-block:: python
from edc_sites.site import sites
In [1]: sites.all()
Out[1]:
{10: SingleSite(site_id=10, name='hindu_mandal', domain='hindu_mandal.tz.example.clinicedc.org', country='tanzania', description='Hindu Mandal Hospital'),
20: SingleSite(site_id=20, name='amana', domain='amana.tz.example.clinicedc.org', country='tanzania', description='Amana Hospital')}
In [2]: sites.get(10)
Out[2]: SingleSite(site_id=10, name='hindu_mandal', domain='hindu_mandal.tz.example.clinicedc.org', country='tanzania', description='Hindu Mandal Hospital')
In [3]: sites.get_by_attr("name", 'hindu_mandal')
Out[3]: SingleSite(site_id=10, name='hindu_mandal', domain='hindu_mandal.tz.example.clinicedc.org', country='tanzania', description='Hindu Mandal Hospital')
In [4]: sites.get(10).languages
Out[4]:
{'sw': 'Swahili',
'en-gb': 'British English',
'en': 'English',
'mas': 'Maasai',
'ry': 'Runyakitara',
'lg': 'Ganda',
'rny': 'Runyankore'}
Take a look at the ``Sites`` class in edc_sites.site for more available methods.
For another deployment, we have alot of sites spread out over a few countries.
For example:
.. code-block:: python
from edc_sites.site import sites
from edc_sites.single_site import SingleSite
suffix = "inte.clinicedc.org"
sites.register(
SingleSite(
101,
"hindu_mandal",
title="Hindu Mandal Hospital",
country="tanzania",
country_code="tz",
domain=f"hindu_mandal.tz.{suffix}",
),
SingleSite(
102,
"amana",
title="Amana Hospital",
country="tanzania",
country_code="tz",
domain=f"amana.tz.{suffix}",
),
SingleSite(
201,
"kojja",
country="uganda",
country_code="ug",
domain=f"kojja.ug.{suffix}",
),
SingleSite(
202,
"mbarara",
country="uganda",
country_code="ug",
domain=f"mbarara.ug.{suffix}",
),
)
You can use the ``sites`` global to get the trial sites for a country:
.. code-block:: python
from edc_sites.site import sites
In [1]: sites.get_by_country("uganda")
Out[1]:
{201: SingleSite(site_id=201, name='kojja', domain='kojja.ug.inte.clinicedc.org', country='uganda', description='Kojja'),
202: SingleSite(site_id=202, name='mbarara', domain='mbarara.ug.inte.clinicedc.org', country='uganda', description='Mbarara')}
In a multisite, multi-country deployment, managing the SITE_ID is complicated. We use django_multisite_ which nicely reads
the SITE_ID from the url. django_multisite will extract `kojja` from https://kojja.ug.example.clinicedc.org to do a model lookup
to get the SITE_ID.
Viewing data from multiple sites using ``view_auditallsites``
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The mixins provided by``edc_sites`` limit the EDC to only present data linked to the current site.
To expand access beyond the current site, ``edc_sites`` provides a special permission codename;
``view_auditallsites``. If a user has this permission, they will be shown data from the current
site plus any additional sites granted in their user profile.
The permission codename ``view_auditallsites`` cannot be allocated to a user with add/edit/delete
permissions to ANY model in the system. That is, the permission codename ``view_auditallsites``
is reserved for VIEW ONLY access, e.g the AUDITOR_ROLE. The one exception is for ``edc_auth``
and``auth`` models accessible to users granted ACCOUNT_MANAGER_ROLE permissions.
In your code, you can check if a user has access to more than just the current site using function
``may_view_other_sites``:
.. code-block:: python
if may_view_other_sites(request):
queryset = self.appointment_model_cls.objects.all()
else:
queryset = self.appointment_model_cls.on_site
To get a list of sites that the user has access to in the current request, use function
``get_view_only_site_ids_for_user``.
.. code-block:: python
from edc_model_admin.utils import add_to_messages_once
site_ids = get_view_only_site_ids_for_user(request.user, request.site, request=request)
Default Site and tests
++++++++++++++++++++++
Edc sites may be configured to register a default site. This may be useful for testing where
you are not registering any sites manually or through ``autodiscover``.
In ``settings``::
EDC_SITES_REGISTER_DEFAULT=True
The default site id is 1.
If your tests depend on a test app that has a ``sites.py``, you might need to set the SITE_ID in your tests.
Use the ``override_settings`` decorator on the test class or on a specific test.
For example:
.. code-block:: python
@override_settings(SITE_ID=20)
class TestLpFormValidator(TestCase):
def setUp(self):
...
@override_settings(SITE_ID=40)
def test_lp_not_done(self):
...
.. |pypi| image:: https://img.shields.io/pypi/v/edc-sites.svg
:target: https://pypi.python.org/pypi/edc-sites
.. |actions| image:: https://github.com/clinicedc/edc-sites/actions/workflows/build.yml/badge.svg
:target: https://github.com/clinicedc/edc-sites/actions/workflows/build.yml
.. |codecov| image:: https://codecov.io/gh/clinicedc/edc-sites/branch/develop/graph/badge.svg
:target: https://codecov.io/gh/clinicedc/edc-sites
.. |downloads| image:: https://pepy.tech/badge/edc-sites
:target: https://pepy.tech/project/edc-sites
.. _django_multisite: https://github.com/ecometrica/django-multisite.git
.. _sites_framework: https://docs.djangoproject.com/en/dev/ref/contrib/sites/
__ sites_framework_
Raw data
{
"_id": null,
"home_page": "https://github.com/clinicedc/edc-sites",
"name": "edc-sites",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.12",
"maintainer_email": null,
"keywords": "django Edc sites, clinicedc, clinical trials",
"author": "Erik van Widenfelt",
"author_email": "ew2789@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/d8/c1/548e24b8100c76ac87885c8323ab2bec9454984115e5c31d9b96776d5ce3/edc_sites-0.3.66.tar.gz",
"platform": null,
"description": "|pypi| |actions| |codecov| |downloads|\n\nedc-sites\n---------\n\nSite definitions to work with Django's `Sites Framework`__ and django_multisite_.\n\nDefine a ``sites.py``. This is usually in a separate project module. For example, for project ``meta`` there is a module ``meta_sites`` that contains a ``sites.py``.\n\nRegister your sites in ``sites.py``.\n\n.. code-block:: python\n\n # sites.py\n from edc_sites.site import sites\n from edc_sites.single_site import SingleSite\n\n\tsuffix = \"example.clinicedc.org\"\n\n\tsites.register(\n\t SingleSite(\n\t 10,\n\t \"hindu_mandal\",\n\t title=\"Hindu Mandal Hospital\",\n\t country=\"tanzania\",\n\t country_code=\"tz\",\n\t domain=f\"hindu_mandal.tz.{suffix}\",\n\t ),\n\t SingleSite(\n\t 20,\n\t \"amana\",\n\t title=\"Amana Hospital\",\n\t country=\"tanzania\",\n\t country_code=\"tz\",\n\t domain=f\"amana.tz.{suffix}\",\n\t ),\n\t)\n\n\nA ``post_migrate`` signal is registered in ``apps.py`` to update the django model ``Site`` and the\nEDC model ``SiteProfile`` on the next migration:\n\n.. code-block:: python\n\n\t# apps.py\n\n from edc_sites.add_or_update_django_sites import add_or_update_django_sites\n\n\tdef post_migrate_update_sites(sender=None, **kwargs):\n\t sys.stdout.write(style.MIGRATE_HEADING(\"Updating sites:\\n\"))\n\t add_or_update_django_sites(verbose=True)\n\t sys.stdout.write(\"Done.\\n\")\n\t sys.stdout.flush()\n\n\n\nNow in your code you can use the ``sites`` global to inspect the trial sites:\n\n.. code-block:: python\n\n from edc_sites.site import sites\n\n In [1]: sites.all()\n Out[1]:\n {10: SingleSite(site_id=10, name='hindu_mandal', domain='hindu_mandal.tz.example.clinicedc.org', country='tanzania', description='Hindu Mandal Hospital'),\n 20: SingleSite(site_id=20, name='amana', domain='amana.tz.example.clinicedc.org', country='tanzania', description='Amana Hospital')}\n\n In [2]: sites.get(10)\n Out[2]: SingleSite(site_id=10, name='hindu_mandal', domain='hindu_mandal.tz.example.clinicedc.org', country='tanzania', description='Hindu Mandal Hospital')\n\n In [3]: sites.get_by_attr(\"name\", 'hindu_mandal')\n Out[3]: SingleSite(site_id=10, name='hindu_mandal', domain='hindu_mandal.tz.example.clinicedc.org', country='tanzania', description='Hindu Mandal Hospital')\n\n In [4]: sites.get(10).languages\n Out[4]:\n {'sw': 'Swahili',\n 'en-gb': 'British English',\n 'en': 'English',\n 'mas': 'Maasai',\n 'ry': 'Runyakitara',\n 'lg': 'Ganda',\n 'rny': 'Runyankore'}\n\n\nTake a look at the ``Sites`` class in edc_sites.site for more available methods.\n\nFor another deployment, we have alot of sites spread out over a few countries.\n\nFor example:\n\n.. code-block:: python\n\n from edc_sites.site import sites\n from edc_sites.single_site import SingleSite\n\n suffix = \"inte.clinicedc.org\"\n\n sites.register(\n SingleSite(\n 101,\n \"hindu_mandal\",\n title=\"Hindu Mandal Hospital\",\n country=\"tanzania\",\n country_code=\"tz\",\n domain=f\"hindu_mandal.tz.{suffix}\",\n ),\n SingleSite(\n 102,\n \"amana\",\n title=\"Amana Hospital\",\n country=\"tanzania\",\n country_code=\"tz\",\n domain=f\"amana.tz.{suffix}\",\n ),\n SingleSite(\n 201,\n \"kojja\",\n country=\"uganda\",\n country_code=\"ug\",\n domain=f\"kojja.ug.{suffix}\",\n ),\n SingleSite(\n 202,\n \"mbarara\",\n country=\"uganda\",\n country_code=\"ug\",\n domain=f\"mbarara.ug.{suffix}\",\n ),\n )\n\nYou can use the ``sites`` global to get the trial sites for a country:\n\n.. code-block:: python\n\n from edc_sites.site import sites\n\n In [1]: sites.get_by_country(\"uganda\")\n Out[1]:\n {201: SingleSite(site_id=201, name='kojja', domain='kojja.ug.inte.clinicedc.org', country='uganda', description='Kojja'),\n 202: SingleSite(site_id=202, name='mbarara', domain='mbarara.ug.inte.clinicedc.org', country='uganda', description='Mbarara')}\n\n\nIn a multisite, multi-country deployment, managing the SITE_ID is complicated. We use django_multisite_ which nicely reads\nthe SITE_ID from the url. django_multisite will extract `kojja` from https://kojja.ug.example.clinicedc.org to do a model lookup\nto get the SITE_ID.\n\nViewing data from multiple sites using ``view_auditallsites``\n+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n\nThe mixins provided by``edc_sites`` limit the EDC to only present data linked to the current site.\nTo expand access beyond the current site, ``edc_sites`` provides a special permission codename;\n``view_auditallsites``. If a user has this permission, they will be shown data from the current\nsite plus any additional sites granted in their user profile.\n\nThe permission codename ``view_auditallsites`` cannot be allocated to a user with add/edit/delete\npermissions to ANY model in the system. That is, the permission codename ``view_auditallsites``\nis reserved for VIEW ONLY access, e.g the AUDITOR_ROLE. The one exception is for ``edc_auth``\nand``auth`` models accessible to users granted ACCOUNT_MANAGER_ROLE permissions.\n\nIn your code, you can check if a user has access to more than just the current site using function\n``may_view_other_sites``:\n\n.. code-block:: python\n\n if may_view_other_sites(request):\n queryset = self.appointment_model_cls.objects.all()\n else:\n queryset = self.appointment_model_cls.on_site\n\nTo get a list of sites that the user has access to in the current request, use function\n``get_view_only_site_ids_for_user``.\n\n.. code-block:: python\n\n from edc_model_admin.utils import add_to_messages_once\n\n site_ids = get_view_only_site_ids_for_user(request.user, request.site, request=request)\n\n\nDefault Site and tests\n++++++++++++++++++++++\n\nEdc sites may be configured to register a default site. This may be useful for testing where\nyou are not registering any sites manually or through ``autodiscover``.\n\nIn ``settings``::\n\n EDC_SITES_REGISTER_DEFAULT=True\n\n\nThe default site id is 1.\n\nIf your tests depend on a test app that has a ``sites.py``, you might need to set the SITE_ID in your tests.\n\nUse the ``override_settings`` decorator on the test class or on a specific test.\n\nFor example:\n\n.. code-block:: python\n\n @override_settings(SITE_ID=20)\n class TestLpFormValidator(TestCase):\n def setUp(self):\n ...\n\n @override_settings(SITE_ID=40)\n def test_lp_not_done(self):\n ...\n\n\n\n\n.. |pypi| image:: https://img.shields.io/pypi/v/edc-sites.svg\n :target: https://pypi.python.org/pypi/edc-sites\n\n.. |actions| image:: https://github.com/clinicedc/edc-sites/actions/workflows/build.yml/badge.svg\n :target: https://github.com/clinicedc/edc-sites/actions/workflows/build.yml\n\n.. |codecov| image:: https://codecov.io/gh/clinicedc/edc-sites/branch/develop/graph/badge.svg\n :target: https://codecov.io/gh/clinicedc/edc-sites\n\n.. |downloads| image:: https://pepy.tech/badge/edc-sites\n :target: https://pepy.tech/project/edc-sites\n\n.. _django_multisite: https://github.com/ecometrica/django-multisite.git\n\n.. _sites_framework: https://docs.djangoproject.com/en/dev/ref/contrib/sites/\n__ sites_framework_\n",
"bugtrack_url": null,
"license": "GPL license, see LICENSE",
"summary": "Simple classes related to the django sites framework for clinicedc projects",
"version": "0.3.66",
"project_urls": {
"Homepage": "https://github.com/clinicedc/edc-sites"
},
"split_keywords": [
"django edc sites",
" clinicedc",
" clinical trials"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "3d7c73ab152b08b0c781d2e28d95c3203fcfe80a583ccb6892b6a78e9b16a5cb",
"md5": "7290247de31112e6f675fe5213401778",
"sha256": "982a464ce455e484effc034bdb8b8d178762db96b4dbb7638ca1d87b803dfe3e"
},
"downloads": -1,
"filename": "edc_sites-0.3.66-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7290247de31112e6f675fe5213401778",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.12",
"size": 58934,
"upload_time": "2024-11-20T22:08:36",
"upload_time_iso_8601": "2024-11-20T22:08:36.049662Z",
"url": "https://files.pythonhosted.org/packages/3d/7c/73ab152b08b0c781d2e28d95c3203fcfe80a583ccb6892b6a78e9b16a5cb/edc_sites-0.3.66-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "d8c1548e24b8100c76ac87885c8323ab2bec9454984115e5c31d9b96776d5ce3",
"md5": "4d7e87982e4fc401c5c613a58cdb04cd",
"sha256": "7951c5a8e8838fb9088ecaaa65f1cd8c4ad70f767b2f0f16dee00019bb1afbef"
},
"downloads": -1,
"filename": "edc_sites-0.3.66.tar.gz",
"has_sig": false,
"md5_digest": "4d7e87982e4fc401c5c613a58cdb04cd",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.12",
"size": 50015,
"upload_time": "2024-11-20T22:08:37",
"upload_time_iso_8601": "2024-11-20T22:08:37.361991Z",
"url": "https://files.pythonhosted.org/packages/d8/c1/548e24b8100c76ac87885c8323ab2bec9454984115e5c31d9b96776d5ce3/edc_sites-0.3.66.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-20 22:08:37",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "clinicedc",
"github_project": "edc-sites",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"lcname": "edc-sites"
}