{"id":21001472,"url":"https://github.com/divio/django-multisite-plus","last_synced_at":"2025-05-14T23:32:39.696Z","repository":{"id":38444448,"uuid":"302082827","full_name":"divio/django-multisite-plus","owner":"divio","description":null,"archived":false,"fork":false,"pushed_at":"2024-03-07T13:58:02.000Z","size":102,"stargazers_count":1,"open_issues_count":1,"forks_count":4,"subscribers_count":8,"default_branch":"master","last_synced_at":"2025-04-03T01:11:09.436Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/divio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.rst","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2020-10-07T15:40:24.000Z","updated_at":"2022-03-09T11:38:29.000Z","dependencies_parsed_at":"2024-03-07T11:29:28.731Z","dependency_job_id":"9ed320fa-e5e8-4631-80b0-1bb9a20a0995","html_url":"https://github.com/divio/django-multisite-plus","commit_stats":{"total_commits":43,"total_committers":5,"mean_commits":8.6,"dds":0.6046511627906976,"last_synced_commit":"d87de8bcce985d1a37e7651eb7e5ffbab06d1c4d"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divio%2Fdjango-multisite-plus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divio%2Fdjango-multisite-plus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divio%2Fdjango-multisite-plus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divio%2Fdjango-multisite-plus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/divio","download_url":"https://codeload.github.com/divio/django-multisite-plus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254248443,"owners_count":22039008,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T08:15:25.721Z","updated_at":"2025-05-14T23:32:34.659Z","avatar_url":"https://github.com/divio.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# django-multisite-plus\n\nAn extension to django-multisite and djangocms-multisite that brings:\n\n* Packaging as an Addon for Divio Cloud and configuration of django-multisite\n  and djangocms-multisite\n* Tools to help handling moving database dumps between environments\n  (live/stage/test/local) and still maintaining sensible domain names.\n* single-process and multi-process deployment options\n\n## Running the tests\n\nTests are run by tox and pytest. To run them, you need to have Docker, `tox`,\nand `tox-docker` installed locally, they can be run simply by executing `tox`.\n\n\n## Installation on Divio Cloud\n\nInstall the Addon.\nTo be able to use the multisite setup locally, define the\n``DJANGO_MULTISITE_PLUS_REWRITE_DOMAIN_FORMAT`` environment variable (and/or\nset a value in the configuration form as a default).\n\n```python\nDJANGO_MULTISITE_PLUS_REWRITE_DOMAIN_FORMAT='{}.192.168.99.100.xip.io'\n```\n\nThis controls how you'll access the various sites. ``{}`` will be replaced with\nthe site slug. In the example above we're using ``xip.io`` a service that\nreturns the ip in the name for any domain following that format. Alternatively\nyou could create an entry in ``/etc/hosts`` for every domain you want to\nsupport and point it to your local ip. Or have a local proxy that handles name\nresolution.\n\nThe ``DJANGO_MULTISITE_PLUS_REWRITE_DOMAINS`` environment variable controls\nwhether the domain names are re-written based on\n``DJANGO_MULTISITE_PLUS_REWRITE_DOMAIN_FORMAT`` on every app startup. Set it to\n``True`` for local development and test servers. On the live server, when the\n``real_domain`` should be used, set ``DJANGO_MULTISITE_PLUS_USE_REAL_DOMAIN``\nto ``True``.\n\nNow either create multiple Site entries (in admin under \"Multisite+\") and set\nthe slug and real domain accordingly (real domain can be blank). Or set the\n``DJANGO_MULTISITE_PLUS_SITES`` in ``settings.py`` like this and make sure\n``DJANGO_MULTISITE_PLUS_AUTO_POPULATE_SITES`` is ``True``:\n\n```python\nDJANGO_MULTISITE_PLUS_SITES = {\n    'portal': {\n        'id': 1,\n        'real_domain': 'www.example.com',\n        'name': 'Example Portal',\n    },\n    'site1': {\n        'id': 2,\n        'real_domain': 'www.site1.com',\n        'name': 'Site 1',\n    },\n    'site2': {\n        'id': 3,\n        'real_domain': 'www.site2.com',\n        'name': 'Site 2',\n    },\n}\n```\n\n``id`` is the ``django.contrib.sites.Site.id`` and is **optional**. If left out\nthe slug (the key in the dict) will be used to create or update the existing\ndatabase entries. If present the site with the given id will be updated or\ncreated.\n\n## single-process vs multi-process\n\n``DJANGO_MULTISITE_PLUS_MODE`` can be either ``single-process`` or\n``multi-process``.\n\n**``single-process``** means that only one python process will be run, which\nwill serve all domains. This makes requests slower (~400ms) because of some\nreloading that needs to be done, but is much easier to deploy and does not use\nmuch resources (ram). To accomplish this it uses the dynamic ``SITE_ID`` and\nmonkeypatches that come with ``django-multisite``.\n\n**``multi-process``** means that there will be a process per ``SITE_ID``. The\nsetup uses a combination of\n[uwsgi emperor mode](http://uwsgi-docs.readthedocs.io/en/latest/Emperor.html)\n(by reading domains directly from the postgres database from\n``django.contrib.sites.Site``) and\n[uwsgi fastrouter](http://uwsgi-docs.readthedocs.io/en/latest/Fastrouter.html)\nto route incoming requests to the correct process. With the ``multi-process``\napproach requests can be served faster, but it uses much more ram (multiplied\nby the amount of sites).\n\n## required uwsgi plugins\n\nThe ``multi-process`` mode requires the ``emperor_pg`` uwsgi plugin. It is\ncumbersome to compile a custom version of uwsgi with this plugin, so we build\nthe default uwsgi wheel on the divio cloud with support already in there. At\nthe time of writing alpine is not supported yet. If this stops working, ask a\nDivio Cloud SRE to update\nhttps://wheels.aldryn.net/admin/wheelsproxy/package/59573/change/ . This is the\nsetup command we run on the wheels proxy before building the uwsgi wheel:\n\n```\necho '[uwsgi]\\nmain_plugin=python,gevent,emperor_pg\\ninherit = base' \u003e/tmp/profile.ini \u0026\u0026 export UWSGI_PROFILE=/tmp/profile.ini\n```\n\n## avoid slow requests on new workers\n\nuwsgi will sometimes restart workers and start new workers on-the-fly. The\nfirst request to a django process is really  slow though, because django loads\nthe bulk of its code at that time. This can produce slow requests at random\ntimes. To avoid this we can load the bulk of the django app already at wsgi\ninit time. Replace ``wsgi.py`` with the following:\n\n```python\nimport os\nfrom aldryn_django import startup\n\napplication = startup.wsgi(path=os.path.dirname(__file__))\n\n# Django loads most of its code when the first request comes in. But that\n# means that the first request of a new worker will always be really\n# slow. So we simulate a request here to warm the process up.\ntry:\n    from django.test.client import Client\n    client = Client()\n    response = client.get('/', follow=True)\n    print('Process warmed up with initial request.')\nexcept Exception as exc:\n    print('Failed to warm up process with initial request.')\n```\n\n## Multi-process tips\n\n### Adding extra params to the vassals on a domain-level\n\nNow the \u003cSite\u003e model can carry additional configurations to be used on\nvassal/socket INI file. For example, one change the number of workers for a\ngiven \u003cSite\u003e by simply:\n\n```python\nfrom django_multisite_plus.models import Site\nsite = Site.objects.get(id=XXXXX)\nsite.extra_uwsgi_ini = '''\nworkers = 5\n'''\nsite.save()\n```\n\nPlease note that those change will take effect only after a server restart.\n\n## Future package structure\n\n* Some of the features of django-multisite-plus may be worth merging into\n  django-multisite.\n* The configuration of djangocms-multisite could be moved to a separate Addon\n  so this package does not need to depend on django-cms.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdivio%2Fdjango-multisite-plus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdivio%2Fdjango-multisite-plus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdivio%2Fdjango-multisite-plus/lists"}