Cutomize dj_rest_auth Password reset email - django

I want to send customized emails when a user request a password reset. I am using dj_rest_auth with django. Here is what I have done: 1. Defined a custom serializer that inherits from PasswordResetSerializer of dj_rest_auth
class CustomPasswordResetSerializer(PasswordResetSerializer):
def get_email_options(self):
return {
'html_mail_template_name': 'registration/password_reset_email.html',
}
Then in settings.py pointed to this serializer:
REST_AUTH_SERIALIZERS = {
'LOGIN_SERIALIZER': 'users.serializers.CustomLoginSerializer',
'PASSWORD_RESET_SERIALIZER': 'users.serializers.CustomPasswordResetSerializer',
}
Then configured templates in settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Then I created templates folder in project root, created a registration folder inside it and placed password_reset_email.html inside it.
This is what I found as an exact solution formy problem after googling some time,but this is not working for me. What did I miss?

This answer helped me
https://stackoverflow.com/a/70624462/15624533
I just put my files (html or txt) directly to templates folder, and changed 'account/email/password_reset_key' to just 'password_reset_key' in send_mail method.

I faced the same challenge and got the solution from this issue on GitHub. https://github.com/iMerica/dj-rest-auth/issues/9 . It's easier than you think
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': 'example#yourdomain.com',
'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)
If you only want to customize email parameters nothing more or less, you can ignore overriding save() method and override get_email_options() instead
from dj_rest_auth.serializers import PasswordResetSerializer
class MyPasswordResetSerializer(PasswordResetSerializer):
def get_email_options(self) :
return {
'email_template_name': 'password_reset_email.html'
}
then point to your custom serializer in settings.py
REST_AUTH_SERIALIZERS = {
'PASSWORD_RESET_SERIALIZER': 'path.to.your.CustomPasswordResetSerializer'
}

Related

Template in Django not found

In the code below, my problem is that template file 'UserAccount' is not found. I set the app in the settings and create a directory in the app and an html file in the directory.
from django.shortcuts import render
# Create your views here.
def login(request):
context = {}
return render(request, 'UserAccount/login.html', context)
this should be your settings.py:
INSTALLED_APPS = [
# django essentials
"django.contrib.admin",
...
# my apps
"myapp", #the app name is "myapp"
]
...
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [str(BASE_DIR.joinpath("template"))], # change this line in your settings
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
],
},
},
]
now create a directory in the same directory as your apps. sth like this:
myapp
app_two
template
...
now in template directory create another directory with the name of your app. in tha t put your html fiels. like this:
| myapp
| app_two
| template
|----myapp
|----sth.html
|----sth_2.html
|----app_two
now when you want to reference them do it like this:
return render(request, 'myapp/sth.html', context)
General tips on asking question on Stackoverflow:
for title : a summary of your problem with keywords like "django" or "django-views"
for putting your code use three backticks --> code
search a lot before asking question. there is a huge chance that someone had posted the same problem before you and you can find your answer there

django can't find template when trying to use forms

I am trying to follow the django documentation howto create a form using sjango form class. I am doing every step but when trying to access my form it says that is cannot find the template:
django.template.exceptions.TemplateDoesNotExist: lform
heres is my forms.py:
class LoginForm(Form):
uname=CharField(label='user name',max_length=20)
passw=CharField(label='password', max_length=20)
the template lform.html:
<form action="ulogin" method="post">
{% csrf_token %}
{{ form }}
<input type="submit" value="Submit">
</form>
and my view. I think the problem is in the render function:
def testform(request):
if request.method=='POST':
form=LoginForm(request.POST)
if form_is_valid():
return render('index')
else:
HttpResponseRedirect('index')
else:
form=LoginForm()
return render(request,'lform',{'form':form})
and url.py:
path('lform',views.testform,name='lform')
the last line in the view function,
return render(request,'lform',{'form':form})
gives the error any suggestions?
ok, the error was simply that the path to templates was missing somehow. I moved the template further up in the directory and now it displays the form. Thanks for all answers.
You are trying to render the template lform. Your template is lform.html.
You need to provide complete path to your template relative with your template path settings.
Correct your template name:
def testform(request):
if request.method=='POST':
form=LoginForm(request.POST)
if form_is_valid():
return render('index')
else:
HttpResponseRedirect('index')
else:
form=LoginForm()
return render(request,'lform.html',{'form':form})
In your settings.
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': ["templates"],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]

Template Does not Exist on IIS+Django

After the deployment process of my Django website on IIS i am getting an error like below,
TemplateDoesNotExist at /test/new_site/list/
Template-loader postmortem
Django tried loading these templates, in this order:
Using engine django:
django.template.loaders.app_directories.Loader: D:\workspace\One_Site_Project\env_one_site_37\lib\site-packages\django\contrib\admin\templates\test\new_site_list.html (Source does not exist)
django.template.loaders.app_directories.Loader: D:\workspace\One_Site_Project\env_one_site_37\lib\site-packages\django\contrib\auth\templates\test\new_site_list.html (Source does not exist)
django.template.loaders.app_directories.Loader: D:\workspace\One_Site_Project\env_one_site_37\lib\site-packages\rest_framework\templates\test\new_site_list.html (Source does not exist)
I don't know why IIS is searching my templates files in virtualenv directory.
My view rendering code is,
#method_decorator(csrf_exempt, name='dispatch')
class NewSiteListUpdate(View):
"""
This class is used to list all the new site activity, also update an activity
"""
def get(self, request, *args, **kwargs):
"""
List all the activity info or a particular activity info
:param request:
:param args:
:param kwargs:
:return:
"""
if request.user.is_staff:
self.data = ActivityInformation.objects.all()
self.radius = 11111
return render(request, 'test/new_site_list.html', {'data': self.data})
Below is my template settings in settings.py file,
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [BASE_DIR + '/template/'],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
# 'builtins': [
# 'src.huawei.templatetags.custom_tags'
# ],
'libraries':{
'custom_tags': 'templatetags.custom_tags',
},
},
},
]
Below is my project structure,
This is working fine in my local system. I tried to add the template folder in to the virtual directory also, but no use, still the same error is showing. I followed this tutorial in order to set up my application on IIS.
I am using python 3.7 and IIS 8.5
I spend my two days for solving this issue but i did not find any solution related to this.
Any help would be greatly appreciated. Thanks in Advance.
I think that you have to modify some part in your code
settings.py
try to change 'DIRS': [BASE_DIR + '/template/'], to 'DIRS'=[os.path.join(BASE_DIR, 'template'), ]
views.py
The path made by the render function will be : ../template/huawei/new_site_list.html but in your project structure your don't have a folder huawei. You must write : return render(request, 'test/new_site_list.html', {'data': self.data})

How can I access environment variables directly in a Django template?

I'm looking to do something like this non-working code in my Django template:
{% if os.environ.DJANGO_SETTINGS_MODULE == "settings.staging" %}
Is something like this possible? My workaround is creating a context processor to make the variable available across all templates, but wanted to know if there is a more direct way to achieve the same result.
Use context_processor, do as below and you should be able to access os.environ['DJANGO_SETTINGS_MODULE'] as SETTING_TYPE in templates. Example you can use {% if SETTING_TYPE == "settings.staging" %}
project/context_processors.py
import os
def export_vars(request):
data = {}
data['SETTING_TYPE'] = os.environ['DJANGO_SETTINGS_MODULE']
return data
project/settings.py (your actual settings file)
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
...
'project.context_processors.export_vars',
...
]
}
}
]
Extending on #vinay kumar's comment, you can create a custom template filter in the following way:
application/template_tags_folder/template_tags_file.py
from django.template.defaulttags import register
import os
#register.filter
def env(key):
return os.environ.get(key, None)
And then in your template you can access it this way:
template.html
{% if 'DJANGO_SETTINGS_MODULE'|env == 'app_name.staging_settings' %}
Finally I leave a django docs reference and a stackoverflow reference for creating custom template tags and filters in django.

Upload custom templates in django

I want users to be able, to upload their custom html templates including css styling and png and jpeg images. These html files shall be retrievable through django. That means that they can see the resulting html content in form of a normal webpage. In order to be able to do that, I (seemingly, don't know a better approach yet) have to upload the html files in the template directory.
This is my current model:
class StylesheetFile(models.Model):
HTML = 'HTML'
CSS = 'CSS'
JPEG = 'JPEG'
PNG = 'PNG'
# Currently supported mimetypes
MIMETYPE_CHOICES = (
(HTML, 'text/html' ),
(CSS , 'text/css' ),
(JPEG, 'image/jpeg'),
(PNG , 'image/png' ),
)
mimetype = models.CharField(max_length=64, choices = MIMETYPE_CHOICES)
company = models.ForeignKey(Company)
file = models.FileField(upload_to=get_upload_path)
And this is the current function to determine the upload_path:
def get_upload_path(instance, filename):
if instance.mimetype == 'HTML':
return os.path.join(
settings.TEMPLATES[0]['DIRS'][1],
instance.company.name,
filename)
if instance.mimetype == 'CSS':
return os.path.join(
"custom_css",
instance.company.name,
filename)
if instance.mimetype == 'JPEG' or instance.mimetype == 'PNG':
return os.path.join(
"custom_img",
instance.company.name,
filename)
Template settings
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [
'/home/ubuntu/app/templates/',
'/home/ubuntu/app/custom_templates',
],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
When I do this the css stylings, png and jpeg files are getting uploaded correctly, but the html files not. I receive following error:
The joined path (/home/ubuntu/app/custom_templates/FooCompany/factors.html) is located outside of the base path component (/home/ubuntu/app/static/media)
What can I do to prevent this error? Is there some best practice approach to my problem or do I have to go for some workaround like setting one of m y TEMPLATE_DIRS to /home/ubuntu/app/static/media/custom_templates. Maybe this is not even a workaround and legit practice.. I don't know really know.. Help is appreciated a lot!
You cannot use FileField to upload files outside of MEDIA_ROOT. That's an important security measure.
You could set TEMPLATE_DIRS to something inside MEDIA_ROOT and most likely this would work, but this makes my cringe really hard. That would essentially gave the users an ability to overwrite any template for any page on the site.
You don't have to save those templates as HTML files to use them as Django templates. You can save them in a database and render them directly from string:
from django.template import engines
from django.http import HttpResponse
# Get the template from database
template_from_db = YourCustomTemplateModel.objects.get(name='homepage')
template_string = template_from_db.content
# Create a django Template object
template = engines['django'].from_string(template_string)
# Render the template to a string
context = {'foo': 'bar'}
page_content = template.render(context=context)
# Send page to a the browser
return HttpResponse(page_content)
You should however think really hard about the security implications of doing this in general. Are you really comfortable with template creators being able to set arbitrary JavaScript on your domain (think cross-site scripting vulnerability)? What about calling arbitrary methods (or at least the ones not having any arguments) and accessing arbitrary arguments on objects you pass in the context dictionary?