3

I'd like to customize the user sign-up form in Django/Mezzanine to allow only certain email addresses, so I tried to monkey-patch as follows:

# Monkey-patch Mezzanine's user email address check to allow only
# email addresses at @example.com.
from django.forms import ValidationError
from django.utils.translation import ugettext
from mezzanine.accounts.forms import ProfileForm
from copy import deepcopy
original_clean_email = deepcopy(ProfileForm.clean_email)
def clean_email(self):
    email = self.cleaned_data.get("email")
    if not email.endswith('@example.com'):
        raise ValidationError(
            ugettext("Please enter a valid example.com email address"))
    return original_clean_email(self)
ProfileForm.clean_email = clean_email

This code is added at the top of one of my models.py.

However, when I runserver I get the dreaded

django.core.exceptions.AppRegistryNotReady: Models aren't loaded yet.

If I add

import django
django.setup()

then python manage.py runserver just hangs until I ^C.

What should I be doing to add this functionality?

xnx
  • 24,509
  • 11
  • 70
  • 109
  • Out of interest, why did you think that adding `django.setup()` was a possible fix? It's meant for when your using Django in standalone scripts, you shouldn't ever use it in your `models.py`. – Alasdair May 10 '16 at 14:05
  • 1
    I know that now! I've used it in standalone scripts to set up the models I need and didn't realise that it wouldn't work within an actual Django project. – xnx May 10 '16 at 14:12

1 Answers1

2

Create a file myapp/apps.py for one of your apps (I've use myapp here), and define an app config class that does the monkeypatching in the ready() method.

from django.apps import AppConfig

class MyAppConfig(AppConfig):
    name = 'myapp'

    def ready(self):
        # do the imports and define clean_email here
        ProfileForm.clean_email = clean_email

Then use 'myapp.apps.MyAppConfig' instead of 'myapp' in your INSTALLED_APPS setting.

INSTALLED_APPS = [
    ...
    'myapp.apps.MyAppConfig',
    ...
]

You might need to put Mezzanine above the app config for it to work.

Alasdair
  • 298,606
  • 55
  • 578
  • 516
  • Thanks, Alasdair. I found I needed to add `name = 'myapp'` to the `MyAppConfig` class definition. Can you provide a link to the relevant Django documentation or tutorial in your answer? It doesn't seem easy to find. – xnx May 10 '16 at 13:58
  • I'm not sure of the best place to link to. You might find the the docs for [django apps](https://docs.djangoproject.com/en/1.9/ref/applications/#configuring-applications) helpful. In particular, the [`ready`](https://docs.djangoproject.com/en/1.9/ref/applications/#django.apps.AppConfig.ready) method is the appropriate place to register signals, and in your case, do the required monkeypatching. – Alasdair May 10 '16 at 14:00
  • I didn't realise that `name` was required, I've updated the answer. – Alasdair May 10 '16 at 14:03