1

I've got a Django app I've been working on, and I finally got registration working pretty consistently. However, for the login page I can only login using the admin account. I have tried using my own login view as well as using the django.contrib.auth.views.login view. When I try to login using one of the users I registered in my app it says that the username or password is incorrect, which is not true.

I am using a custom user model, which is shown here:

models.py:

# from https://medium.com/@ramykhuffash/33e47976b517
class UserManager(BaseUserManager):
    """
    A custom user manager to deal with emails as unique identifiers for auth
    instead of usernames. The default that's used is "UserManager"
    """
    def _create_user(self, email, password, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        if not email:
            raise ValueError('The Email must be set')
        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save()
        return user

    def create_superuser(self, email, password, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        extra_fields.setdefault('is_active', True)
        if extra_fields.get('is_staff') is not True:
            raise ValueError('Superuser must have is_staff=True.')
        if extra_fields.get('is_superuser') is not True:
            raise ValueError('Superuser must have is_superuser=True.')
        return self._create_user(email, password, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(unique=True, null=True)
    is_staff = models.BooleanField(
        _('staff status'),
        default=False,
        help_text=_('Designates whether the user can log into this site.'),
    )
    is_active = models.BooleanField(
        _('active'),
        default=True,
        help_text=_(
            'Designates whether this user should be treated as active. '
            'Unselect this instead of deleting accounts.'
        ),
    )
    USERNAME_FIELD = 'email'
    objects = UserManager()

    def __str__(self):
        return self.email

    def get_full_name(self):
        return self.email

    def get_short_name(self):
        return self.email

    def email_user(self, subject, message, from_email=None, **kwargs):
        send_mail(subject, message, from_email, [self.email], **kwargs)

Here is the code where I serve up the pages:

urls.py:

from django.conf.urls import url
from django.contrib.auth.views import logout, login

from myprojectimport views

urlpatterns = [
    url(r'^signup$', views.signup, name='signup'),
    url(r'^login$', login, {'template_name': 'login.html'}),
    url(r'^logout$', views.logout, name='logout'),
    url(r'^do-logout$', logout, {'next_page': 'login'}, name='do-logout')
]

Here are my views.

views.py:

def signup(request):
    if request.user.is_authenticated():
        print 'authenticated!'
        return redirect('resident_list')
    if request.method == 'POST':
        print 'request is POST'
        form = SignUpForm(request.POST)

        if form.is_valid():
            print 'form is valid'
            print form
            email = form.cleaned_data['email']

            user = form.save(commit=False)
            user.is_active = False
            user.username = email
            user.save()

            profile = Profile(user=user, email_confirmed=False)

            profile.save()

            current_site = get_current_site(request)

            subject = 'Activate Your Account'
            message = render_to_string('email/account_activation_email.html', {
                'user': user,
                'domain': current_site.domain,
                'uid': urlsafe_base64_encode(force_bytes(user.pk)),
                'token': account_activation_token.make_token(user),
            })
            user.email_user(subject, message)
            print 'sent email to ' + str(user)
            return redirect('activation_sent')
        else:
            print 'form is not valid'
            print form
            print form.data['first_name']
            print form.data['last_name']
            print form.data['email']
    else:
        form = SignUpForm()

    print 'returning the sign up page'
    return render(request, 'signup.html', {'form': form})

def activation_sent(request):
    return render(request, 'activation_sent.html')

def login(request):
    if request.user.is_authenticated():
        print 'authenticated!'
        return redirect('resident_list')
    else:
        print 'user is not authenticated'
        print request.method
        if request.method == 'POST':
            print 'request posted'
            form = LoginForm(request.POST)
            print form.errors
            if form.is_valid():
                print 'form is valid'
                form_user = form.save(commit=False)
                username = form.cleaned_data['username']
                user = User.objects.get_by_natural_key(username)

                django.contrib.auth.login(request, user)
                return redirect('resident_list')
            else:
                print 'form is not valid'
                print 'errors are ' + form.errors
                return render(request, 'login.html', {'form': form})
        else:
            print 'didn\'t even post any data... was this a GET??'
            form = LoginForm()
            return render(request, 'login.html', {'form': form})


def logout(request):
    if request.method == 'POST':
        return redirect('do-logout')
    return render(request, 'logout.html')

Here's my forms....

forms.py:

class Email(forms.EmailField):
    def clean(self, value):
        super(Email, self).clean(value)
        try:
            User.objects.get(email=value)
            print 'user already exists'
            raise forms.ValidationError(
                "This email is already registered. Use the 'forgot password' link on the login page")
        except User.DoesNotExist:
            return value



class SignUpForm(UserCreationForm):
    def __init__(self, *args, **kwargs):
        super(SignUpForm, self).__init__(*args, **kwargs)
        self.fields.pop('password2')
        print self.fields

    email = Email(label="Email", widget=forms.TextInput(
        attrs={
            'class': 'form-control',
            'placeholder': 'Email',
        }))

    first_name = forms.CharField(label="First name", widget=forms.TextInput(
        attrs={
            'class': 'form-control',
            'placeholder': 'First Name',
        }))
    last_name = forms.CharField(widget=forms.TextInput(
        attrs={
            'class': 'form-control',
            'placeholder': 'Last Name',
        }))

    password1 = forms.CharField(widget=forms.TextInput(
        attrs={
            'type': 'password',
            'class': 'form-control',
            'placeholder': 'Password'
        }))

    agrees_to_legal = forms.BooleanField()

    class Meta:
        model = User
        fields = ("first_name", "last_name", "email", "password1")


class LoginForm(forms.ModelForm):

    username = forms.CharField(label="Username", widget=forms.TextInput(
        attrs={
            'class': 'form-control',
            'placeholder': 'Email',
        }))

    password = forms.CharField(widget=forms.TextInput(
        attrs={
            'type': 'password',
            'class': 'form-control',
            'placeholder': 'Password'
        }))

    class Meta:
        model = User
        fields = ("username", "password")

My HTML templates just drop in the form elements, I think it would be too much to post those.

When I POST from the registration page, it tries to send out an email (another separate issue) but in the Django admin panel a new User is created. But then when I go to /login and try to login with that new user, I can't do it. Am I missing something here?

Forest Kunecke
  • 2,160
  • 15
  • 32
  • 1
    did you set the `AUTH_USER_MODEL` as your own custom model `User` in settings ? – Sachin Aug 08 '17 at 22:52
  • Yeah, and I even went so far as to try [this](https://stackoverflow.com/a/37332393/1822214) solution here and it still didn't work. – Forest Kunecke Aug 08 '17 at 22:58
  • Try printing the value of this method `from django.contrib.auth import get_user_model`. – Sachin Aug 08 '17 at 23:04
  • I figured it out. I stopped using a custom user model and just used the solution on [this](https://stackoverflow.com/a/37332393/1822214) page. I'll put together an answer in a bit. I think I just copied too much code into my app haha. – Forest Kunecke Aug 08 '17 at 23:24

2 Answers2

0

I have the same custom user setup as you do, the process i use for authenticating and logging in a user is:

from django.contrib.auth import authenticate, login

@require_POST
def login_form(request):
    user = authenticate(email=request.POST.get("email"), password=request.POST.get("password"))
    if user is not None:
        login(request, user)
    else:
        return WRONG USER OR PASS
LanfeaR
  • 241
  • 1
  • 8
0

I think in your urls.py you are calling django auth login instead of your login method from your app
url(r'^login$', login, {'template_name': 'login.html'}), should be
url(r'^login$', views.login, {'template_name': 'login.html'}),

Srinivas
  • 464
  • 3
  • 17