Django inheriting password reset view

Hello. I want to customise the default Django password reset view in order to allow users to enter their username or email, and then receive an email with a reset link.

Does anybody know how to implement this functionality, as I have tried by inheriting the Password Reset form and password reset view, however there is very little documentation on this. Here are the two files I need to edit in order to implement this. Also on the form, I only want one field, where a user can enter their username or email.

Can anybody point me in the right direction, i.e which function to edit, and where to add the necessary code. Thanks.

Files:
PasswordResetView

PasswordResetForm

Will Vincent has a good tutorial here: https://learndjango.com/tutorials/django-password-reset-tutorial

-Jorge

@jlgimeno thanks for the link, however this was not what I was looking for unfortunately

Well, in a way it is - a good starting point anyway.

You’re not going to “edit” any system files, you’re going to build your functionality on top of those functions.

For example, you specify that you want to customize the password reset form.
Looking at the documentation for PasswordResetView, it says (in part):

  • template_name : The full name of a template to use for displaying the password reset form. Defaults to registration/password_reset_form.html if not supplied.

Notice that the directory is just specified as “registration/password_reset_form.html”. If you read the Templates documentation, you’ll see that Django will search multiple locations for a file. So to override the default template, you can create a registration directory within your templates directory, and that will be the template that is rendered.

However, you’re also looking at changing functionality, so that means you’re looking to alter the view as well.

So, overall, you’re looking at:

  • Creating your custom password_reset_form.html template.

  • Creating your custom password reset form

    • This form can extend from PasswordResetForm.

    • Since you want the user to be able to enter either username or email in that one field, you’ll probably want to override the get_users method for your form. The supplied get_users function assumes an email address was entered. You might want to write your version to check to see if an email was entered. If not, check to see if a username was entered and find the corresponding email address(es) for that username. Look at the get_users method in PasswordResetForm to see how the provided method does this for some ideas.

  • Creating a “password reset view”

    • This view can inherit from PasswordResetView

    • Specify the form_class attribute for your custom form.

  • Creating a url for your “password reset view”

  • If you’re creating a new template for your form, you might also want to create a similar template for the PasswordResetDone view in registration/password_reset_done.html

  • Linking your page to your custom view rather than the default url.

(I know that sometimes this feels like you’re touching lots of different things - and that’s ok. You’re making small changes to bits and pieces rather than needing to write a whole lot of code yourself.)

@KenWhitesell Thanks man, helps a lot, but when you mean override the get_users method, do you mean inherit from existing PasswordResetView and make a function with the name get_users to override this function from the parent class? And by inheriting, all the other functionality for the view will still be implemented right ? Am I correct here? Thanks.

First, for clarity and accuracy, it’s the get_users in the PasswordResetForm, not PasswordResetView.

But yes, something like (short version, not complete):

class MyPasswordResetForm(PasswordResetForm):
    def get_users(self, username_or_email):
        ...

Yes, you are correct. By inheriting from a parent class, all functions and attributes will apply, except for those overridden by the child class.

Since you’re inheriting from PasswordResetForm, all other attributes and functions from it will apply. Off the top of my head, I don’t see where anything else would be needed here (I’m far from sure about that, but that’s my gut hunch at the moment).

Ken

Ok thank you for the help, Eesa

hey @eqmunir did you implemented the solution? im looking for similar solution. if possible any link or steps you can put here or anyone from this conversation.

Thanks.

For future readers, follow following steps

  1. Create custom form, and subclass from PasswordResetForm like below
class MyPasswordResetForm(PasswordResetForm):
  1. Override email field like below
email = forms.CharField(label="Username or Email", max_length=20, required=False, help_text="You can enter username or email id of your account. make sure its correct otherwise, you may not receive an reset email.")
  1. Finally add below code, make sure you change from_user email to yours.
def get_username_or_email_users(self, username_or_email):
        return list(User.objects.filter(Q(username__iexact=username_or_email) | Q( email__iexact=username_or_email)))

def save(self, *args, **kwargs):
  email_or_username = self.cleaned_data.get("email")
  from_user = "Webmail Email Goes here"
  users_emails = self.get_username_or_email_users(email_or_username)
  current_site = get_current_site(kwargs.get("request"))
  token_generator = kwargs.get("token_generator")
  extra_email_context = kwargs.get("extra_email_context")
  use_https = kwargs.get("use_https")
  site_name = current_site.name
  domain = current_site.domain
  
  if users_emails:
      for user in users_emails:

          context = { 'email': user.email, 'domain': domain, 'site_name': site_name, 'uid': urlsafe_base64_encode(force_bytes(user.pk)), 'user': user, 'token': token_generator.make_token(user), 'protocol': 'https' if use_https else 'http', **(extra_email_context or {}), }

          self.send_mail( kwargs.get('subject_template_name'), kwargs.get('email_template_name'), context, from_user, user.email, html_email_template_name=kwargs.get('html_email_template_name'), )