Question

I'm using Django Registration. It provides the view that processes registration_form.html that currently contains Username, Password1, Password2 and Email as user-enterable fields in my app. I have a very simple random username generator that I would like to use to pre-populate username in registration_form.html and make it "readonly". I'm having a hard time figuring out where in Django Registration I should make my tweaks. I believe it's in here somewhere:

class RegistrationView(_RequestPassingFormView):
"""
Base class for user registration views.

"""
disallowed_url = 'registration_disallowed'
form_class = RegistrationForm
http_method_names = ['get', 'post', 'head', 'options', 'trace']
success_url = None
template_name = 'registration/registration_form.html'

def dispatch(self, request, *args, **kwargs):
    """
    Check that user signup is allowed before even bothering to
    dispatch or do other processing.

    """
    if not self.registration_allowed(request):
        return redirect(self.disallowed_url)
    return super(RegistrationView, self).dispatch(request, *args, **kwargs)

def form_valid(self, request, form):
    new_user = self.register(request, **form.cleaned_data)
    success_url = self.get_success_url(request, new_user)

    # success_url may be a simple string, or a tuple providing the
    # full argument set for redirect(). Attempting to unpack it
    # tells us which one it is.
    try:
        to, args, kwargs = success_url
        return redirect(to, *args, **kwargs)
    except ValueError:
        return redirect(success_url)

def registration_allowed(self, request):
    """
    Override this to enable/disable user registration, either
    globally or on a per-request basis.

    """
    return True

def register(self, request, **cleaned_data):
    """
    Implement user-registration logic here. Access to both the
    request and the full cleaned_data of the registration form is
    available here.

    """
    raise NotImplementedError

UPDATE:

So based on initial responses I started with a quick edit of the existing RegistrationView as follows:

class RegistrationForm(forms.Form):
required_css_class = 'required'

# username = forms.RegexField(regex=r'^[\w.@+-]+$',
#                             max_length=30,
#                             label=_("Username"),
#                             error_messages={'invalid': _("This value may contain only letters, numbers and @/./+/-/_ characters.")})   
# My new username stuff here:                     
n = random.randint(1,9999999)
default_username = 'AnonMom%d' % (n,) 
username = forms.CharField(initial="default_username") 
email = forms.EmailField(label=_("E-mail"))
password1 = forms.CharField(widget=forms.PasswordInput,
                            label=_("Password"))
password2 = forms.CharField(widget=forms.PasswordInput,
                            label=_("Password (again)"))

I was expecting to see my default username show up in registration.form.html defined as follows:

<form method="post" action=".">{% csrf_token %}

<p><input id="id_username" maxlength="25" name="username" type="text" autocomplete="off"></p>
<p style="font-size:12px; color:#999">Make it anonymous but easy to remember. 25 chars max. No spaces.</p>  
<p><input id="id_password1" name="password1" type="password" placeholder="Password"/></p>
<p><input id="id_password2" name="password2" type="password" placeholder="Password (Confirm)"/></p>
<p><input id="id_email" name="email" type="email" placeholder="Email (Never displayed)" autocomplete="off"/></p>

But the field is empty. It's even empty if I just set initial="xxx". What am I doing wrong?

UPDATE 2:

It's all working using the code above with the following slight teak to the view and form:

class RegistrationForm(forms.Form):                           
    n = random.randint(1,9999999)
    username = forms.CharField(initial='MomzAnon%d' % (n,) ) 
    ...

<form method="post" action=".">{% csrf_token %}
    <p><input id="id_username" maxlength="25" name="username" type="text" 
    value="{{ form.username.value }}" readonly autocomplete="off"></p>
    ...

Final question: Is there any reason to subclass RegistrationForm vs just edit it? My approach seems very simple in terms of lines of code.

UPDATE 3: It seems that my random username is not being auto-generated each time I call this form. So I'm coming back to this form having created one user and finding that the auto-generated username is unchanged from the last user registration. How can I force a username regen each time this form is presented to users?

UPDATE 4: I solved the problem outlined in UPDATE 3 by moving the username logic here. This code also includes a tweak to ensure my randomly generated username is also unique:

def __init__(self, *args, **kwargs):
    super(RegistrationForm, self).__init__(*args, **kwargs)

    n = random.randint(1,999999) 
    new_username = 'anon%d' % (n,) 

    while User.objects.filter(username=new_username).exists():
        n = random.randint(1,999999)
        new_username = 'anon%d' % (n,) 

    self.fields['username'] = forms.CharField(initial=new_username)
Was it helpful?

Solution

You can subclass RegistrationForm and make username field as readonly by adding readonly widget attribute :

from registration.forms import RegistrationForm

class MyForm(RegistrationForm):
    username = forms.CharField(max_length=30, label=_("Username"),
                           widget=forms.TextInput(attrs={'readonly':'readonly'}))

In your RegistrationView subclass change form_class to your form class and override get_initial function (your generation random password code can be placed here to):

class MyReg(RegistrationView):
    form_class = MyForm

    def get_initial(self, *args, **kwargs):
        self.initial = {'username': self.gen_randrom_username()}
        return super(Myreg, self).get_initial(*args, **kwargs)

    def gen_randrom_username(self):
        # gen name
        return random_username

OTHER TIPS

You can create a new RegistrationView

from django.contrib.sites.models import RequestSite, Site
from registration import signals
from registration.models import RegistrationProfile
from registration.backends.default.views import RegistrationView

class RandomRegistrationView(RegistrationView):
    def register(self, request, **cleaned_data):
        email, password = cleaned_data['email'], cleaned_data['password1']
        username = call_random_username_genator() # <- supply your RANDOM username here

        if Site._meta.installed:
            site = Site.objects.get_current()
        else:
            site = RequestSite(request)                         
        new_user = RegistrationProfile.objects.create_inactive_user(username, email,
                                                                    password, site)
        signals.user_registered.send(sender=self.__class__,
                                     user=new_user,
                                     request=request)
        return new_user

And in your urls.py add something like

    url(r'^accounts/register/$', RandomRegistrationView.as_view(),
        name='registration_register'),

This isn't tested but it should get you close. I think you might need to create a new RegistrationForm and supply it in urls.py with

RandomRegistrationView.as_view(form_class=RandomRegistrationForm) 

Or you may simply be able to make the necessary changes in the template. I'm not 100% sure without actually implementing it.

You can subclass RegistrationForm to set initial value and readonly attribute, like this:

class MyRegistrationForm(RegistrationForm):
    def __init__(self, *args, **kwargs):
        super(MyRegistrationForm, self).__init__(*args, **kwargs)
        self.initial['username'] = random_username()
        self.fields['username'].widget.attrs.update({'readonly': 'readonly'})

and of course set the above form class as your registration form.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top