Docker-mailman: Remove example.com as the default SITE in django

Created on 21 Apr 2017  ·  9Comments  ·  Source: maxking/docker-mailman

Right now, when an instance comes up, the default site is set to example.com (for some reason).

Change that or add instructions to change site id to the actual domain being used.

bug documentation web

All 9 comments

What worse, if I delete example.com from sites list I get 'Server error (500)' and installation becomes unusable.

Here is what in the mailman-web logs:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/django/core/handlers/exception.py", line 39, in inner
    response = get_response(request)
  File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 249, in _legacy_get_response
    response = self._get_response(request)
  File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 187, in _get_response
    response = self.process_exception_by_middleware(e, request)
  File "/usr/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 185, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/usr/local/lib/python2.7/site-packages/postorius/views/list.py", line 593, in list_index
    'domain_count': len(choosable_domains)})
  File "/usr/local/lib/python2.7/site-packages/django/shortcuts.py", line 30, in render
    content = loader.render_to_string(template_name, context, request, using=using)
  File "/usr/local/lib/python2.7/site-packages/django/template/loader.py", line 68, in render_to_string
    return template.render(context, request)
  File "/usr/local/lib/python2.7/site-packages/django/template/backends/django.py", line 66, in render
    return self.template.render(context)
  File "/usr/local/lib/python2.7/site-packages/django/template/base.py", line 206, in render
    with context.bind_template(self):
  File "/usr/local/lib/python2.7/contextlib.py", line 17, in __enter__
    return self.gen.next()
  File "/usr/local/lib/python2.7/site-packages/django/template/context.py", line 236, in bind_template
    updates.update(processor(self.request))
  File "/usr/local/lib/python2.7/site-packages/django_mailman3/context_processors.py", line 33, in common
    context["site_name"] = get_current_site(request).name
  File "/usr/local/lib/python2.7/site-packages/django/contrib/sites/shortcuts.py", line 15, in get_current_site
    return Site.objects.get_current(request)
  File "/usr/local/lib/python2.7/site-packages/django/contrib/sites/models.py", line 65, in get_current
    return self._get_site_by_id(site_id)
  File "/usr/local/lib/python2.7/site-packages/django/contrib/sites/models.py", line 35, in _get_site_by_id
    site = self.get(pk=site_id)
  File "/usr/local/lib/python2.7/site-packages/django/db/models/manager.py", line 85, in manager_method
    return getattr(self.get_queryset(), name)(*args, **kwargs)
  File "/usr/local/lib/python2.7/site-packages/django/db/models/query.py", line 385, in get
    self.model._meta.object_name
DoesNotExist: Site matching query does not exist.

@ulrith Yeah, you need to change the default SITE_ID in Django's settings to whatever site you are using.

By default the value is 1 in the container's settings.py and it corresponds to example.com.

You should change it to 2, which I suppose which would point to your domain in settings_local.py. You can add the following:
SITE_ID=2

@maxking It would be better if I can replace example.com by my actual domain with some command like I mentioned in this comment. Or by sql query in database container... Can you help?

@ulrith Yep, Django command line will drop you into a python REPL where you can do anything you wish, even to the production database ;-)

maxking@mailman:~$ docker exec -it mailman-web python manage.py shell
Python 2.7.13 (default, Jun 21 2017, 18:14:15) 
[GCC 4.9.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> from django.db import models
>>> from django.contrib.sites.models import Site
>>> Site.objects.all()
<QuerySet [<Site: lists.araj.me>]>
>>> Site.objects.create(name='Random Domain', domain='mail.araj.me')
<Site: mail.araj.me>
>>> Site.objects.all()
<QuerySet [<Site: lists.araj.me>, <Site: mail.araj.me>]>
>>> for each in Site.objects.all():
...     print(each.domain, each.id)
... 
(u'lists.araj.me', 2)
(u'mail.araj.me', 3)

If you need to read more about this, here is a link to Django's Sites framework.

@maxking Actually I'm not familiar with Python. Could you please give me a code snippet (ideally one liner) which will replace Site: example.com to Site: mydomain.tld for the newly installed Mailman 3?

OK, so as it turns out, Django creates the default examples.com site itself and there is no way to actually stop this behavior.

So, here are your options if you want to create a new website during the startup.

  • The "right" way to do this would be using Django's fixtures. Fixtures allow you to load hardcoded data into the database for whatever purpose you may have. So, you manually create a file which is serialized as JSON, YAML or XML and run the command: python manage.py loaddata <nameoffixture> and django loads that data up in the database. For example:

The file below is saved to fixtures/gen_site.yaml:

- model: sites.Site
  pk: 100
  fields:
    domain: gmail.com
    name: Google

Then, you run python manage.py loaddata gen_site and you have your Site auto created. Then you change your SITE_ID=100 in the settings_local.py and things should work!

However, doing this right now with the containers is probably difficult as there is no easy way to actually run custom commands on startup (also called entrypoint in Docker terminology). I have opened a new issue #61 to track that problem.

  • Second option for you will be to manually run this command:
python manage.py shell -c "from django.contrib.sites.models import Site; mysite,_=Site.objects.get_or_create(id=101, name='mysite.tld', domain='mysite.tld'); print(mysite.id, mysite.name)"

Note that the above command is meant for django, so you need to append docker-compose exec -T mailman-web before the above command.
This command will create a new site named mysite.tld. It will also print out the id which you'd then have to put under SITE_ID=101 and restart your Django instance for this to take effect. This command will not fail if the site already exists in the database.
I would say this is also not the best way to do it because firstly, you need to restart the container for this to take effect (only first time, but that is equally bad) and secondly, there is no way to automatically edit the settings_local.py to reflect the new SITE_ID without manual intervention, unless ofcourse if you write some sed or awk magic.

  • The third option is to just edit the example.com domain and update it to whatever domain you want.
python manage.py shell -c "from django.contrib.sites.models import Site; Site.objects.filter(domain='example.com').update(name='My Site', domain='mysite.tld')"

This would not require any changes anywhere, but in my local testing I found out that the display name on top doesn't change unless I restart the Django server, and it will only be required for the very first time. According to me, this looks like the best option, after the first one, which I am willing to add support for in the container images.

@maxking The last option works like a charm! Thanks

Should be resolved.

DEFAULT_FROM_DOMAIN environment variable now also replaces the default example.com domain.

The description however isn't changed and can be changed from the Django admin site.

Fixed in #95

Was this page helpful?
0 / 5 - 0 ratings

Related issues

daamien picture daamien  ·  12Comments

strarsis picture strarsis  ·  5Comments

belzebubek picture belzebubek  ·  12Comments

morbidick picture morbidick  ·  7Comments

jacquev6 picture jacquev6  ·  3Comments