Question

I'm trying to Authenticate users by their emails instead of username.

I'm using django-userena and by using its Docs,etc. I set almost anything that is needed. Something like : USERENA_WITHOUT_USERNAMES = True in its setting, etc.

But after signing up, I've faced a chain of problems. like trying to pass my username in the url for authentication, signup completion problems, etc.

I changed some view functions that need username as an argument, but this method neither solved my problem , nor is a correct (and maybe secure) way to do it.

for instance, by routing to this URL http://127.0.0.1:8000/accounts/signup/complete/ (after $ ./manage.py check_permissions ) I get this error:

global name 'username' is not defined
/userena/views.py in directto_user_template
user = get_object_or_404(User, username_iexact=username)

Is there anything that I'm missing ??

UPDATE: Here is the output that I get:

Caught NoReverseMatch while rendering: Reverse for 'userena_activate' with arguments '('xyz@xyz.com', '70b60d1d97015e03ba8d57f31e4c7ff14d6ab753')' and keyword arguments '{}' not found.

It's clear that userena tries to the email as username with URL :

userena/templates/userena/emails/activation_email_message.txt, error at line 8

1   {% load i18n %}{% autoescape off %}
2   {% if not without_usernames %}{% blocktrans with user.username as username %}Dear {{ username }},{% endblocktrans %}
3   {% endif %}
4   {% blocktrans with site.name as site %}Thank you for signing up at {{ site }}.{% endblocktrans %}
5   
6   {% trans "To activate your account you should click on the link below:" %}
7   
8   {{ protocol }}://{{ site.domain }}{% url userena_activate user.username activation_key %}
9   
10  {% trans "Thanks for using our site!" %}
11  
12  {% trans "Sincerely" %},
13  {{ site.name }}
14  {% endautoescape %}

UPDATE 2: Alright . by reading the source code for SignupFormOnlyEmail class form, it says that a random username is generated automatically.

class SignupFormOnlyEmail(SignupForm):
    """
    Form for creating a new user account but not needing a username.

    This form is an adaptation of :class:`SignupForm`. It's used when
    ``USERENA_WITHOUT_USERNAME`` setting is set to ``True``. And thus the user
    is not asked to supply an username, but one is generated for them. The user
    can than keep sign in by using their email.

    """
    def __init__(self, *args, **kwargs):
        super(SignupFormOnlyEmail, self).__init__(*args, **kwargs)
        del self.fields['username']

    def save(self):
        """ Generate a random username before falling back to parent signup form """
        while True:
            username = sha_constructor(str(random.random())).hexdigest()[:5]
            try:
                User.objects.get(username__iexact=username)
            except User.DoesNotExist: break

        self.cleaned_data['username'] = username
        return super(SignupFormOnlyEmail, self).save()

UPDATE :

I finally solved the problem. I was also using django-email-as-username beside to django-userena. This was the cause of my problem. Apparently, they have some conflicts. WATCH OUT

Was it helpful?

Solution

You've defined url route userena_activate with keyword arguments (username and activation_key), but you call it just with arguments, change template to keyword arguments:

{% url userena_activate username=user.username activation_key=activation_key %}

edit due to comment:

I'm not sure if I understand your problem corectly, but I think there's a problem elsewhere. Yours error message says:

Caught NoReverseMatch while rendering: Reverse for 'userena_activate' with arguments '('xyz@xyz.com', '70b60d1d97015e03ba8d57f31e4c7ff14d6ab753')' and keyword arguments '{}' not found.

It seems you pass valid arguments to function, but you pass them wrong way. URL route in urls.py is defined in a way to expect kwargs, but you pass just args, which mismatch its definition. That is why you get this error message. Simple pass arguments as kwargs (that means each argument is passed with its name and value as showed above).

urls.py difference between argument and keyword argument:

url(r'^(?P<username>[\.\w]+)/activate/(?P<activation_key>\w+)/$', userena_views.activate, name='userena_activate'),
         ^ this is _keyword argument_ 'username', expects value with argument value AND name

and

url(r'^page/(.*)/$', userena_views.ProfileListView.as_view(), name='userena_profile_list_paginated'),
            ^ this is argument, expects only value, not argument name

OTHER TIPS

A really simple alternative for using the email address as the username (effectively) is django-easy-userena - this is an upward compatible fork of Userena that adds a few nice features:

  • use email address as effective user ID - generates a random numeric username that is hidden in forms and confirmation emails
  • fewer dependencies - doesn't require django-guardian or easy-thumbnails
  • terms of service agreement field is built in, displays as checkbox

I've had good results with this - installation was manual for some reason (copy userena dir to site-packages) but it worked without hassles.

I like the overall Userena approach, but easy-userena is a better fit for what I need.

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