Comments (33)
I was able to do it similarly as you suggested.
I will share it here for anyone who comes later
Create your custom password reset serializer
from dj_rest_auth.serializers import PasswordResetSerializer
class CustomPasswordResetSerializer(PasswordResetSerializer):
def save(self):
request = self.context.get('request')
# Set some values to trigger the send_email method.
opts = {
'use_https': request.is_secure(),
'from_email': '[email protected]',
'request': request,
# here I have set my desired template to be used
# don't forget to add your templates directory in settings to be found
'email_template_name': 'password_reset_email.html'
}
opts.update(self.get_email_options())
self.reset_form.save(**opts)
UPDATE:
If you only want to customize email parameters nothing more or less, you can ignore overriding save()
method and override get_email_options()
instead, check it in source code here.
Ex:
from dj_rest_auth.serializers import PasswordResetSerializer
class MyPasswordResetSerializer(PasswordResetSerializer):
def get_email_options(self) :
return {
'email_template_name': 'password_reset_email.html'
}
get_email_options()
is being called in save()
just to update opts
dict with any other options before triggering reset_form, here in source code.
then point to your custom serializer in settings.py
REST_AUTH_SERIALIZERS = {
'PASSWORD_RESET_SERIALIZER': 'path.to.your.CustomPasswordResetSerializer'
}
from dj-rest-auth.
I was able to do it similarly as you suggested.
I will share it here for anyone comes laterCreate your custom password reset serializer
from dj_rest_auth.serializers import PasswordResetSerializer class CustomPasswordResetSerializer(PasswordResetSerializer): def save(self): request = self.context.get('request') # Set some values to trigger the send_email method. opts = { 'use_https': request.is_secure(), 'from_email': '[email protected]', 'request': request, # here I have set my desired template to be used # don't forget to add your templates directory in settings to be found 'email_template_name': 'password_reset_email.html' } opts.update(self.get_email_options()) self.reset_form.save(**opts)UPDATE:
If you only want to customize email parameters nothing more or less, you can ignore overriding
save()
method and overrideget_email_options()
instead, check it is source code here.Ex:
from dj_rest_auth.serializers import PasswordResetSerializer class MyPasswordResetSerializer(PasswordResetSerializer): def get_email_options(self) : return { 'email_template_name': 'password_reset_email.html' }
get_email_options()
is being called insave()
just to updateopts
dict with any other options before triggering reset_form, here in source code.then point to your custom serializer in settings.py
REST_AUTH_SERIALIZERS = { 'PASSWORD_RESET_SERIALIZER': 'path.to.your.CustomPasswordResetSerializer' }
After some digging, I found that the password reset email template is coming from django/contrib/admin/templates/registration/password_reset_email.html
.
Overwriting templates\registration\password_reset_email.html
with your own custom content works fine without custom Serialization.
Although, to send the HTML content you will have to write a custom password reset serializer as @mohmyo suggested and replace this 'email_template_name': 'password_reset_email.html'
with 'html_email_template_name': 'password_reset_email.html'
.
@mohmyo Thanks for your Solution;)
from dj-rest-auth.
Here is how I got it running. These are custom serializers:
from django.conf import settings
from dj_rest_auth.forms import AllAuthPasswordResetForm
from django.utils.encoding import force_str
from allauth.account.forms import default_token_generator
from django.utils.http import urlsafe_base64_decode as uid_decoder
from django.contrib.auth.forms import PasswordResetForm
class PasswordResetSerializer(PasswordResetSerializer):
@property
def password_reset_form_class(self):
use_custom_email_template = bool(self.get_email_options().get("html_email_template_name", ''))
if 'allauth' in settings.INSTALLED_APPS and not use_custom_email_template:
return AllAuthPasswordResetForm
else:
return PasswordResetForm
def get_email_options(self):
return {
'html_email_template_name': 'account/email/password_reset_email.html',
}
class CustomPasswordResetConfirmSerializer(PasswordResetConfirmSerializer):
def validate(self, attrs):
# Decode the uidb64 (allauth use base36) to uid to get User object
try:
uid = force_str(uid_decoder(attrs['uid']))
self.user = Account.objects.get(pk=uid)
except (TypeError, ValueError, OverflowError, ObjectDoesNotExist):
raise ValidationError({'uid': ['Invalid value']})
# Have to use allauth default token generator instead of django's default one
if not default_token_generator.check_token(self.user, attrs['token']):
raise ValidationError({'token': ['Invalid value']})
self.custom_validation(attrs)
# Construct SetPasswordForm instance
self.set_password_form = self.set_password_form_class(
user=self.user, data=attrs,
)
if not self.set_password_form.is_valid():
raise serializers.ValidationError(self.set_password_form.errors)
return attrs
You also have to set custom serializers in settings.py
I combined approaches from this answer #345
and this one #428
from dj-rest-auth.
For anyone attempting to do this with the following dependencies:
django-allauth = "==0.50.0"
dj-rest-auth = {extras = ["with_social"], version = "==4.0.0"}
None of the above answers fully worked for me as most options were deprecated after dj-rest-auth
~2.x
. Instead, after some debugging, I found this solution:
Customising reset password URL
settings.py
REST_AUTH = {
'PASSWORD_RESET_SERIALIZER': 'yourAuthApp.serializers.CustomPasswordResetSerializer'
}
yourAuthApp
serializers
from dj_rest_auth.serializers import PasswordResetSerializer
from decouple import config
RESET_PASSWORD_REDIRECT_URL = config('RESET_PASSWORD_REDIRECT_URL')
def custom_url_generator(request, user, temp_key):
return f'{RESET_PASSWORD_REDIRECT_URL}?token={temp_key}'
class CustomPasswordResetSerializer(PasswordResetSerializer):
def get_email_options(self):
return {
'url_generator': custom_url_generator
}
.env
# Reset password settings
RESET_PASSWORD_REDIRECT_URL=http://localhost:3000/auth/reset
You don't need to use environment variables, but I encourage doing so. The above code allows customising the URL that will be sent to your users while using the default email template provided by allauth. Not sure this is documented somewhere, but the official docs cannot find a definition of get_email_options
: https://dj-rest-auth.readthedocs.io/en/4.0.1/search.html?q=get_email_option&check_keywords=yes&area=default.
Using a custom mail template
Two ways to achieve this:
Easy: overriding the original mail structure
On your project's root directory, create a templates > account > email
directory. Now add a base_message.txt
and base_message.txt
files. You can take the structure from the official allauth templates directory: https://github.com/pennersr/django-allauth/tree/main/allauth/templates/account/email
And that's it; if you leave the {{ password_reset_url }}
intact, its value should be taken from the custom_url_generator
we defined before.
A bit more messy
You will have to override your CustomPasswordResetSerializer
password_reset_form_class
function to use a CustomAllAuthPasswordResetForm
that should inherit from from dj_rest_auth.forms import AllAuthPasswordResetForm
. You will then need to override the forms save
method to update the following line:
get_adapter(request).send_mail(
'account/email/password_reset_key', email, context
)
with the path to your custom template.
Neither method seems perfect to me but I went for the first as I find it more maintainable. If someone finds a reference to how to do this in a better way please let me know.
from dj-rest-auth.
@aaronamelgar Nope, I have updated my above code snippet regarding the base class, check it out.
the reason you are seeing this is that registration
is a separated module in dj_rest_auth
from dj-rest-auth.
I was able to do it similarly as you suggested.
I will share it here for anyone comes laterCreate your custom password reset serializer
from dj_rest_auth.serializers import PasswordResetSerializer class CustomPasswordResetSerializer(PasswordResetSerializer): def save(self): request = self.context.get('request') # Set some values to trigger the send_email method. opts = { 'use_https': request.is_secure(), 'from_email': '[email protected]', 'request': request, # here I have set my desired template to be used # don't forget to add your templates directory in settings to be found 'email_template_name': 'password_reset_email.html' } opts.update(self.get_email_options()) self.reset_form.save(**opts)UPDATE:
If you only want to customize email parameters nothing more or less, you can ignore overriding
save()
method and overrideget_email_options()
instead, check it is source code here.Ex:
from dj_rest_auth.serializers import PasswordResetSerializer class MyPasswordResetSerializer(PasswordResetSerializer): def get_email_options(self) : return { 'email_template_name': 'password_reset_email.html' }
get_email_options()
is being called insave()
just to updateopts
dict with any other options before triggering reset_form, here in source code.then point to your custom serializer in settings.py
REST_AUTH_SERIALIZERS = { 'PASSWORD_RESET_SERIALIZER': 'path.to.your.CustomPasswordResetSerializer' }
@mohmyo I have followed this and the template variables such as {{ password_reset_url }}
are not being rendered in the email.
Email I receive looks like this
Hello fro !
You're receiving this e-mail because you or someone else has requested a password for your user account.
It can be safely ignored if you did not request a password reset. Click the link below to reset your password.
Thank you for using !
Am I missing something??
from dj-rest-auth.
You are welcome @Abishek05, glad it helped.
from dj-rest-auth.
Just a heads-up: this works till version 2.1.4. Later versions will ignore get_email_options
override. Checkout the reported bug.
from dj-rest-auth.
This is how I do it on my projects (DRF API Server + React SPA or Next.js):
Declare a custom serializer for registration that inherits from the base. Then you have complete control over what is included in the email.
from dj_rest_auth.registration.serializers import RegisterSerializer
class CustomRegistrationSerializer(RegisterSerializer):
def save(self, request):
# handle all setup logic and email here.
then, in your Django settings:
REST_AUTH_REGISTER_SERIALIZERS = {
'REGISTER_SERIALIZER': 'path.to.your.CustomRegistrationSerializer'
}
from dj-rest-auth.
I will try it and get back to you, thanks
from dj-rest-auth.
@mohmyo did you create your own base class for PasswordResetSerializer?
I only see RegisterSerializer in dj_rest_auth.registration.serializers
from dj-rest-auth.
please help me for password reset, its giving error as following
NoReverseMatch at /dj-rest-auth/password/reset/
Reverse for 'password_reset_confirm' with keyword arguments '{'uidb64': 'MQ', 'token': 'aay6u3-6409cacfd1a2284e6bfb54f61514d66b'}' not found. 1 pattern(s) tried: ['password-reset/confirm/(?P[0-9A-Za-z_\-]+)/(?P[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$']
from dj-rest-auth.
This has been answered many times, see closed issues and you will find so many helpful discussions with the solution
from dj-rest-auth.
Like this
#118 (comment)
from dj-rest-auth.
How to do the same (Edit the email template) for email sent to verify the email after registration?
from dj-rest-auth.
This part is controlled by django-allauth
, see
from dj-rest-auth.
Thanks, it is done 😎. If anyone having trouble getting the key sent at the end of the url you can use {{ key }} in that template to access the key and later goto the verify email address and post the key by frontend.
from dj-rest-auth.
@mohmyo How does your template look like? Where do you exactly put a custom URL pointing to the frontend?
from dj-rest-auth.
@colonder can you be more specific?
from dj-rest-auth.
As password_reset_url
parameter isn't passed to Django PasswordResetForm then I will assume that you have created your custom template, right?
from dj-rest-auth.
Hello @mohmyo and @Abishek05 , even after doing it with your approach I'm getting error which is
django_1 | [pid: 56|app: 0|req: 3/3] 172.18.0.1 () {42 vars in 696 bytes} [Tue Jan 5 20:09:35 2021] OPTIONS /api/auth/password/reset/ => generated 0 bytes in 0 msecs (HTTP/1.1 200) 7 headers in 365 bytes (1 switches on core 0) django_1 | [pid: 56|app: 0|req: 4/4] 172.18.0.1 () {42 vars in 696 bytes} [Tue Jan 5 20:09:35 2021] POST /api/auth/password/reset/ => generated 222495 bytes in 113 msecs (HTTP/1.1 500) 5 headers in 170 bytes (1 switches on core 0)
I'm contributing to an open-source org, Now let me tell you about the structure of the org, basically apps/accounts/templates/account/password_reset_email.html
and serializer file apps/accounts/serializers.py
where I defined my CustomPasswordResetSerializer
serializer.py
`class CustomPasswordResetSerializer(PasswordResetSerializer):
def get_email_options(self) :
return {
'html_email_template_name': 'account/password_reset_email.html'
}`
settings.py file
REST_AUTH_SERIALIZERS = { "PASSWORD_RESET_SERIALIZER": "accounts.serializers.CustomPasswordResetSerializer" }
Will you please help me with what to do in this situation, Also if I need to do the complete process by overwriting how would I do that because here we have templates for each app so we cannot define the TEMPLATE_DIR in the settings file?
I've been stuck to this issue for the past 4-5 days, please help me out.
Thanks
from dj-rest-auth.
Hello @lkbhitesh07, is there a better error trace than the one you posted? I'm not sure where to look, and there is a lot of things that can be the cause of the issue here.
So, let's start with a better error trace and the file structure of your project.
from dj-rest-auth.
@mohmyo Thanks for replying also, I just solved this issue a few minutes back but I'm experiencing a very strange problem. I mean after customizing the PasswordResetSerializer, I made a folder templates/registration and put the templates inside, the strange part is, it's not getting recognized. I mean I have to define it like this -
class CustomPasswordResetSerializer(PasswordResetSerializer):
def get_email_options(self):
super().get_email_options()
return {
'subject_template_name': 'registration/password_reset_subject.txt',
'email_template_name': 'registration/password_reset_email.txt',
}
Otherwise, it's not getting recognized if I'll just do password_reset_subject.txt
it will throw me an error that password_reset_subject.txt
is not defined.
also one more interesting thing is that I have to put this file password_reset_email.txt
as the txt extension, if I'll put it in html extension the variables will not pass.
Please do let me know if you need any more information
Thanks
from dj-rest-auth.
There is no need to do super().get_email_options()
, If you look into get_email_options()
you will find that it is already empty and it got called later at save()
to inject any additional options later on. In other words, get_email_options()
has nothing to do with the flow unless it is being overridden.
So it should be like what I have posted earlier here
from dj_rest_auth.serializers import PasswordResetSerializer
class MyPasswordResetSerializer(PasswordResetSerializer):
def get_email_options(self) :
return {
'email_template_name': 'password_reset_email.html'
}
The issue for template folder not recognized may be related to some configuration to your project.
here an example of a project structure and the right config for it
project structure
|-app1
|-core
|-settings
|-base.py
|-templates
|-password_reset_email.html
settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, '../', 'templates'), ], # note that ../ is here because our base.py is under two levels
'APP_DIRS': True,
'OPTIONS': {
........
},
},
]
from dj-rest-auth.
@mohmyo Just one more small help please, I mean we have a directory just like below so how should I add that? What should I put in 'DIRS' as I have templates folder according to different apps.
|-apps
|-app1
|-templates
|-registration
|-app2
|-templates
|-core
|-settings
|-common.py
Thanks for all your help.
from dj-rest-auth.
I think this will help you a lot to pick the right DIRS
for your project
https://docs.djangoproject.com/en/3.1/howto/overriding-templates/
from dj-rest-auth.
@mohmyo Yeah actually I already tried that out but didn't get it working that's why I asked you in case I was making some mistake. The error looks something like this -
django_1 | ERROR 2021-01-10 00:01:04,301 log 59 140635120949120 Internal Server Error: /api/auth/password/reset/
django_1 | Traceback (most recent call last):
django_1 | File "/usr/local/lib/python3.7/site-packages/django/core/handlers/exception.py", line 34, in inner
django_1 | response = get_response(request)
django_1 | File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 115, in _get_response
django_1 | response = self.process_exception_by_middleware(e, request)
django_1 | File "/usr/local/lib/python3.7/site-packages/django/core/handlers/base.py", line 113, in _get_response
django_1 | response = wrapped_callback(request, *callback_args, **callback_kwargs)
django_1 | File "/usr/local/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
django_1 | return view_func(*args, **kwargs)
django_1 | File "/usr/local/lib/python3.7/site-packages/django/views/generic/base.py", line 71, in view
django_1 | return self.dispatch(request, *args, **kwargs)
django_1 | File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 505, in dispatch
django_1 | response = self.handle_exception(exc)
django_1 | File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 465, in handle_exception
django_1 | self.raise_uncaught_exception(exc)
django_1 | File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 476, in raise_uncaught_exception
django_1 | raise exc
django_1 | File "/usr/local/lib/python3.7/site-packages/rest_framework/views.py", line 502, in dispatch
django_1 | response = handler(request, *args, **kwargs)
django_1 | File "/usr/local/lib/python3.7/site-packages/dj_rest_auth/views.py", line 233, in post
django_1 | serializer.save()
django_1 | File "/usr/local/lib/python3.7/site-packages/dj_rest_auth/serializers.py", line 194, in save
django_1 | self.reset_form.save(**opts)
django_1 | File "/usr/local/lib/python3.7/site-packages/django/contrib/auth/forms.py", line 311, in save
django_1 | user_email, html_email_template_name=html_email_template_name,
django_1 | File "/usr/local/lib/python3.7/site-packages/django/contrib/auth/forms.py", line 252, in send_mail
django_1 | body = loader.render_to_string(email_template_name, context)
django_1 | File "/usr/local/lib/python3.7/site-packages/django/template/loader.py", line 61, in render_to_string
django_1 | template = get_template(template_name, using=using)
django_1 | File "/usr/local/lib/python3.7/site-packages/django/template/loader.py", line 19, in get_template
django_1 | raise TemplateDoesNotExist(template_name, chain=chain)
django_1 | django.template.exceptions.TemplateDoesNotExist: password_reset_email.html
Thanks for your support.
from dj-rest-auth.
can you share your TEMPLATES
value?
from dj-rest-auth.
Here, this is the complete file, and it is in, BASE_DIR/apps/accounts/registration/password_reset_email.html.
{% load i18n %}{% autoescape off %}Hello from {{ site_name }}!
You're receiving this e-mail because you or someone else has requested a password for your user account at {{ site_domain }}.
It can be safely ignored if you did not request a password reset.
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}
Thanks
from dj-rest-auth.
I think you can try this
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, '../', 'apps/app1/templates'), ],
'APP_DIRS': True,
'OPTIONS': {
........
},
},
]
def get_email_options(self) :
return {
'email_template_name': 'registration/password_reset_email.html'
}
from dj-rest-auth.
Hi @mohmyo ,
I've a question that in PasswordResetView , Initially Link going on email is "http://127.0.0.1:8000/........". I want to change it to the other URL(i.e. url on which Frontend(Angular) is hosted on). How can I do it?
Thanks in advance.
from dj-rest-auth.
I add uid
def custom_url_generator(self, request, user, temp_key):
return f'{RESET_PASSWORD_REDIRECT_URL}?uid={user.id}&token={temp_key}'
base_message.txt and password_reset_key_message.txt files can added for custom template (base_message.txt duplicated)
I can't manage override template files with first method because django loads app directory templates first. so I have to move custom templates in my custom app then I move app name in settings.py over "allauth" app. I did not try second method for change template
The answer above was the most suitable for me. (django 5 dj-rest-auth 5)
from dj-rest-auth.
Hey @Erwol, thank you so much! What you suggested really helped me out. I was stuck on this problem for a few days, but now I've got it sorted.
from dj-rest-auth.
Related Issues (20)
- Support django 5+ HOT 1
- Need Customized Email Template for User Registration
- How to set the jwt token expiration correctly? HOT 2
- How to manually generate uid and token for password reset
- Doesn't support Android Credential Manager for Google login from android
- allauth ACCOUNT_UNIQUE_EMAIL doesn't work as expected HOT 1
- How to change activate_url in dj-rest-auth after registration? HOT 1
- "Partitioned" attribute needed for the set-cookie header
- Password Reset Custom Email HOT 1
- For apps defined in the settings save will give an error
- erroneous imports leading to breakage in `django-allauth 0.62.x` HOT 1
- AssertionError at /api/google/login/: No exception message supplied
- Feature Request: Allow configuration for auto linking social account and local account for google provider
- Getting ConnectionRefusedError when register a new user. But the user saving to database. If I refresh the page, showing user exists. HOT 1
- Getting "password is too common" error, but the user is still being created in the database with the provided data.
- Encountering MultipleObjectsReturned Exception During Social Authentication
- OAuth2Provider.get_scope() takes 1 positional argument but 2 were given HOT 5
- Feature Request: Extensibility of the fields when using the RegisterSerializer
- Breaking Bug since Allauth v0.63.1 when registering using Google "User is already registered with this e-mail address" HOT 2
- Google Social Login Returining "Failed to exchange code for access token" HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from dj-rest-auth.