I have a template for a form already designed (using bootstrap-studio).
I just need to get the data from it and send it as a mail to my email id.
It would also be great if the page could get redirected to a new one after pressing submit.
I have already set up the settings.py and am able to send the 'message' part of the form.
if request.method == 'POST':
message = request.POST['message']
send_mail(
'Contact Form',
message,
settings.EMAIL_HOST_USER,
['abcd#gmail.com'],
fail_silently=False
)
return render(request, 'contact.html')
What I need is to be able to send an email with 'message', 'name', 'email',
included in it.
I tried writing
message = request.POST['message','name','email']
Didn't get expected results.
contact.html:
<form method="post">
{% csrf_token %}
<h2 class="text-center">Contact us</h2>
<div class="form-group"><input class="form-control" type="text" name="name" placeholder="Name"></div>
<div class="form-group"><input class="form-control " type="email" name="email" placeholder="Email"></div>
<div class="form-group"><textarea class="form-control" name="message" placeholder="Message" rows="14"></textarea></div>
<div class="form-group"><button class="btn btn-primary" type="submit">send </button></div>
</form>
</div>
To fetch data from form you have to do it invidually.
message = request.POST["message"]
name = request.POST["name"]
email = request.POST["email"]
Then you can use this data to pass into send_mail() function as arguments.
To redirect to another page after submitting the form, use this logic:
from django.shortcuts import redirect
if request.method == 'POST':
message = request.POST['message']
name = request.POST["name"]
email = request.POST["email"]
send_mail(
'Contact Form',
message,
settings.EMAIL_HOST_USER,
[email,],
fail_silently=False
)
return redirect("/home/")
return render(request, 'contact.html')
Related
I am trying to use the ajax post function to post data from my contact form in one of my templates. However, I am getting a 'django.utils.datastructures.MultiValueDictKeyError' when I make the request.
The error is a server error and it is displayed as shown
django.utils.datastructures.MultiValueDictKeyError: 'name'
It is being triggered in the view.py folder on the line with the code
name = request.POST['name']
Here is my model for the message:
class Message(models.Model):
name = models.CharField(max_length=255)
email = models.CharField(max_length=255)
content = models.TextField(max_length=10000)
created_at = models.DateTimeField(auto_now_add=True)
This is my view.py:
def save_message(request):
if request.method=='POST':
name = request.POST['name']
email = request.POST['email']
content = request.POST['content']
Message.objects.create(
content = content,
name = name,
email = email
)
messages.success(request, f'Your message has been sent. Expect a response soon!')
return JsonResponse({'bool':True})
This is the form in the index template
{% csrf_token %}
<form class="contactForm" id="contactForm">
<div class="form-floating">
<input class="form-control" class="message-name" id="name" type="text" placeholder="Enter your name..." />
</div>
<div class="form-floating">
<input class="form-control" class="message-email" id="email" type="email" placeholder="Enter your email..." />
</div>
<div class="form-floating">
<textarea class="form-control" id="message" class="message-text" placeholder="Enter your message here..."></textarea>
</div>
<br />
<button class="btn btn-primary text-uppercase save-message" id="submitButton" type="submit">Send</button>
</form>
And this is my ajax:
{% block script %}
<script>
$(document).ready(function(){
// This is for the post messages for non-logged in users
$(".save-message").on('click',function(){
var _content=$(".message-text").val();
var _messageName=$(".message-name").val();
var _messageEmail=$(".message-email").val();
// Ajax
$.ajax({
url:"/save-message",
type:"POST",
data:{
content:_content,
name:_messageName,
email:_messageEmail,
csrfmiddlewaretoken:"{{csrf_token}}"
},
dataType:'json',
beforeSend:function(){
$(".save-message").addClass('disabled').text('Saving...');
},
success:function(res){
if(res.bool==true){
$(".message-text").val('');
}
$(".save-message").removeClass('disabled').text('submit');
}
});
});
});
</script>
{% endblock %}
Using request.POST[] is for data sent with regular HTML forms, but not when sending data using AJAX (even if it is sent via POST). To access that you need the raw, request.body, and to parse that you need json, which also means you need to import json:
import json
def save_message(request):
if request.method=='POST':
data = json.loads(request.body)
name = data['name']
email = data['email']
content = data['content']
Message.objects.create(
content = content,
name = name,
email = email
)
messages.success(request, f'Your message has been sent. Expect a response soon!')
return JsonResponse({'bool':True})
The error would have occurred with email = request.POST['email'] or content = request.POST['content'] because request.POST is empty, so the keys, name, email, content, or any other key would have raised the MultiValueDictKeyError:.
Source: Django Docs:
HttpRequest.body
The raw HTTP request body as a bytestring. This is
useful for processing data in different ways than conventional HTML
forms: binary images, XML payload etc. For processing conventional
form data, use HttpRequest.POST.
Please can anyone help me with this issue. I am trying to allow the users of my website to send out review request to customers by filling out a form on their profile page. They only have to provide the email address of the recipient then the backend would use this to configure a HTML message then send to the recipient. Currently, the whole system works just fine if I hard code the recipient email address. But once I try to get the email from request.POST['receiver'] it seems not to be passing the argument to the function.
Here is the view function:
def request_review_api(request):
receiver_email = request.POST['receiver']
print(receiver_email)
request_review(request, receiver_email)
return redirect('profile_company')
#login_required(login_url='loginpage_company')
#allowed_users_company(allowed_roles=['company'])
def request_review(request, receiver_email):
company = get_object_or_404(Company, user=request.user)
company_id = company.pk
print(company)
html_tpl_path = 'companyusers/request_review.html'
context_data = {'company': company, 'company_id': company_id,}
email_html_template = get_template(html_tpl_path).render(context_data)
receiver = receiver_email
email_msg = EmailMessage('Review Request',
email_html_template,
settings.EMAIL_HOST_USER,
[receiver],
reply_to=['no-reply#bbb.com'],
)
# this part allows the message to be send as html instead of plain text
email_msg.content_subtype = 'html'
email_msg.send(fail_silently=False)
This is what I have in my Template:
<p class="tm-request-review-display card-text">
<form class="tm-request-review-display" action="{%url
'request_review' %}" method="POST"> {% csrf_token %}
<div class="form-group">
<div class="col-md">
<input type="email" class="form-control" name="receiver"
id="receiver" placeholder="Enter Reviewer's Email">
</div>
</div>
<div class="form-group">
<div class="col-md">
<input class="btn btn-primary btn-sm" type="submit"
value="Send Request">
</div>
</div>
</form>
</p>
The email gets sent successfully once I hard code the recipient email like this:
def request_review_api(request):
request_review(request)
return redirect('profile_company')
#login_required(login_url='loginpage_company')
#allowed_users_company(allowed_roles=['company'])
def request_review(request):
company = get_object_or_404(Company, user=request.user)
company_id = company.pk
print(company)
html_tpl_path = 'companyusers/request_review.html'
context_data = {'company': company, 'company_id': company_id,}
email_html_template = get_template(html_tpl_path).render(context_data)
receiver_email = 'sndnd#yahoo.com'
email_msg = EmailMessage(' Review Request',
email_html_template,
settings.EMAIL_HOST_USER,
[receiver_email],
reply_to=['no-reply#yahoo.ng'],
)
# this part allows the message to be send as html instead of plain text
email_msg.content_subtype = 'html'
email_msg.send(fail_silently=False)
The code is perfect. The mistake was that the email request.post was getting was an invalid email.
Thanks guys for helping. It works perfectly now.
I am passing a some information to view function by submitting a form and view requires has #login_required decorator. Here is the template where i'm passing email ID using a from
<form action="{% url 'become_booster' %}" method="post">
{% csrf_token %}
<input type="hidden" name="email" value="{{ profile_user.email }}" />
<div class="form-group">
<div class="col-md-12 col-sm-12">
<input type="submit" class="btn btn-success btn-sm" value="Become a Booster">
</div>
</div>
</form>
Here is the view function
#login_required
def become_booster(request):
if request.method == "POST":
email = request.POST.get('email')
user = CustomUser.objects.filter(email= email)[0]
tiers = Tiers.objects.filter(user=user)
form = SubscriptionForm
return render(request,'select_tier.html',{'tiers':tiers,'form':form})
This is working fine when the user logedin already. When user didn't login, #login_required sends them to login and when it comes back request.method is no longer POST. It no longer has that email info. Can someone help me with this. Thanks!
#login_required decorator is used to available that function to registered user who are actually logged in or send to login page or registration page. if you remove #login_required from your view function it will be available for unregistered and all type of users.
Try this,
from django.shortcuts import *
#login_required(login_url='become_booster')
def become_booster(request):
if request.method == "POST":
email = request.POST.get('email')
user = get_object_or_404(CustomUser, email=email)
tiers = get_list_or_404(Tiers, user=user)
form = SubscriptionForm
return render(request,'select_tier.html',{'tiers':tiers,'form':form})
elif request.method == 'GET':
# Something like this
# return render(request, 'your_template.html', {'profile_user': user_object_which_contains_email})
I am trying to style errors using twitter bootstrap in my Django project. Right now, I have a simple form that asks for a person's email address, has them press a button, and then submits it to the database. It also has validation checking to see if the email is unique in the database. If it is not unique, it raises an error saying "This email is already registered". However, when the error is raised, for a duplicate email, it brings an ugly bullet point list next to the input field with the text This email is already registered. I'm trying to style it to where it has a little dialog show under the input text with a yellow i icon like it does when the input does not include an # sign, i.e. it isn't an email. The ugly bullet point also appears when a valid domain isn't included in the email, e.g. there isn't a .com appended.
I think the problem lies with the way my form html is set up, or how the view handles the form's errors. Maybe, because the form field is an EmailField, the is_valid indicator doesn't validate and therefore shows the twitter bootstrap alert.
How do I get it to show the alert every time? Below is my code:
form part of the index.html
<form class="form-inline" method="post">
<div class="input-group input-group-newsletter">
<div class="form-group">
{% csrf_token %}
{{ form }}
</div>
<div class="form-group">
<div class="input-group-append">
<button class="btn btn-secondary" type="submit">Button Text</button>
</div>
</div>
</div>
</form>
views.py
from django.shortcuts import render, HttpResponse
from django.views.generic import TemplateView
from appname.forms import AppForm
class AppView(TemplateView):
template_name = 'apps/index.html'
def get(self, request):
form = AppForm()
return render(request, self.template_name, {'form': form})
def post(self, request):
form = AppForm(request.POST)
if form.is_valid():
email = form.cleaned_data['email']
form.save()
form = AppForm()
args = {'form': form, 'email': email, 'signedup': True}
else:
args = {'form': form, 'signedup': False}
return render(request, self.template_name, args)
forms.py
from django import forms
from .models import AppModel
class AppForm(forms.ModelForm):
email = forms.EmailField(required=True,
label='',
widget=forms.EmailInput(attrs={'class': 'form-control',
'placeholder': 'Enter email...',
'name': 'email',
'aria-label': 'Enter email...',
'aria-describedby': 'basic-addon'}))
class Meta:
model = AppModel
fields = ('email',)
def clean_email(self, *args, **kwargs):
email = self.cleaned_data.get("email")
if AppModel.objects.filter(email__iexact=email).exists():
raise forms.ValidationError("This email is already registered.")
return email
You may want to try Django messages framework. This site shows how its done. I have tried it myself and works fine, though I haven't tried putting icons into it.
https://simpleisbetterthancomplex.com/tips/2016/09/06/django-tip-14-messages-framework.html
Update based on the comment below:
Here are the snippets in my project
in settings.py
from django.contrib.messages import constants as messages
...
MESSAGE_TAGS = {
messages.DEBUG: 'alert-info',
messages.INFO: 'alert-info',
messages.SUCCESS: 'alert-success',
messages.WARNING: 'alert-warning',
messages.ERROR: 'alert-danger',
}
messages.html template which can be included in any template where you want to have notifications
{% if messages %}
{% for message in messages %}
<div class="alert {{ message.tags }} alert-dismissible " role="alert">
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
{{ message }}
</div>
{% endfor %}
{% endif %}
log-in.html template
<body>
{% include 'trip_monitor/messages.html' %}
<div class="login-form">
<form method="post">
{% csrf_token %}
<h2 class="text-center">Materials Management</h2>
<p align="center">Please <strong>log in</strong> to continue.</p>
<div class="form-group">
<input name="username" type="text" class="form-control" placeholder="Username" required="required" autofocus>
</div>
<div class="form-group">
<input name="password" type="password" class="form-control" placeholder="Password" required="required" id="password">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-block">Log in</button>
</div>
</form>
</div>
</body>
views.py
from django.contrib import messages
def login(request):
if request.method == 'POST':
_username = request.POST['username']
_password = request.POST['password']
user = authenticate(request, username=_username, password=_password)
if user is not None:
auth_login(request, user)
return redirect('/trip/')
else:
messages.error(request, 'Username or Password is incorrect!') # this will be shown as pop-up message
return render(request, 'trip_monitor/login.html')
elif request.method == 'GET':
if request.user.is_authenticated:
return redirect('/trip/')
else:
return render(request, 'trip_monitor/login.html')
views.py to save the password:
elif 'reset_password' in request.POST:
if request.POST['reset_password'].strip():
saveuser = User.objects.get(id=user.id)
saveuser.set_password(request.POST['reset_password']);
saveuser.save()
userform = UserForm(instance=saveuser)
return redirect('incident.views.about_me')
popup box to get the old password and new password
<div id="overlay_form" style="display:none">
<form method="post" action=".">
{% csrf_token %}
<h2>Reset Password</h2><br />
<table>
<tr><td>Enter your old password</td><td>
<input type="text" name="old_password" id="old_password" maxlength="30" /></td></tr>
<tr><td>Enter your new password</td><td><input type="text" name="new_password" id="new_password" maxlength="30" /></td></tr>
<tr><td>Confirm your new password</td><td><input type="text" name="reset_password" id="reset_password" maxlength="30" /></td></tr>
</table>
<div style="width:180px;float:right;margin:20px 5px 0 10px">
{% include "buttons/save.html" %}
<button style="margin-right:10px;" type="button" id="close" name="cancel" class="forward backicon">
<img src="{{ STATIC_URL }}images/button-icon-ir-back.png" width="12" height="17" alt="" />
Cancel</button>
</div>
</form>
</div>
I am able to save the new password,but i want to know the following things
How to check the entered old password is correct with existing password.
How to validate new password field and confirm password field.Which validation is better to perform.
Need some help.
This is how you would check for old password - before the set_password,
user.check_password(request.POST['reset_password'])
Also, check for password confirmation in the following way.
elif 'reset_password' in request.POST:
old_password = request.POST['old_password'].strip()
reset_password = request.POST['reset_password'].strip()
new_password = request.POST['new_password'].strip()
if old_password && reset_password && reset_password == new_password:
saveuser = User.objects.get(id=user.id)
if user.check_password(old_password):
saveuser.set_password(request.POST['reset_password']);
saveuser.save()
userform = UserForm(instance=saveuser)
return redirect('incident.views.about_me')
It is a much better approach to use a form.
Django Code to check if the password entered by user matches the actual old password; if it does not, raise validation error in django form. Also, update the password if both of the passwords match.
Tested on (Django 1.10, Python 3.4)
forms.py
from django import forms
class changePassForm(forms.Form):
old_password_flag = True #Used to raise the validation error when it is set to False
old_password = forms.CharField(label="Old Password", min_length=6, widget=forms.PasswordInput())
new_password = forms.CharField(label="New Password", min_length=6, widget=forms.PasswordInput())
re_new_password = forms.CharField(label="Re-type New Password", min_length=6, widget=forms.PasswordInput())
def set_old_password_flag(self):
#This method is called if the old password entered by user does not match the password in the database, which sets the flag to False
self.old_password_flag = False
return 0
def clean_old_password(self, *args, **kwargs):
old_password = self.cleaned_data.get('old_password')
if not old_password:
raise forms.ValidationError("You must enter your old password.")
if self.old_password_flag == False:
#It raise the validation error that password entered by user does not match the actucal old password.
raise forms.ValidationError("The old password that you have entered is wrong.")
return old_password
views.py
def settings(request):
if request.user.is_authenticated:
form = changePassForm(request.POST or None)
old_password = request.POST.get("old_password")
new_password = request.POST.get("new_password")
re_new_password = request.POST.get("re_new__password")
if request.POST.get("old_password"):
user = User.objects.get(username= request.user.username)
#User entered old password is checked against the password in the database below.
if user.check_password('{}'.format(old_password)) == False:
form.set_old_password_flag()
if form.is_valid():
user.set_password('{}'.format(new_password))
user.save()
update_session_auth_hash(request, user)
return redirect('settings')
else:
return render(request, 'settings.html', {"form": form})
else:
return redirect('login')
settings.html
<h1>Settings Page</h1>
<h2>Change Password</h2>
<form action="" method="POST">
{% csrf_token %}
{{ form.as_p }}
<input type="Submit" value="Update"></input>
</form>
<form class="form-horizontal" action="/your_views/reset_password/" method="post">
{% csrf_token %}
<div class="form-group">
<div class="col-md-12">
<input type="password" placeholder="Old password" id="old_password" name="old_password" autocomplete="off" required class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<input type="password" placeholder="New password" id="password1" name="password1" autocomplete="off" required class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<input type="password" placeholder="Re-new password" id="password2" name="password2" autocomplete="off" required class="form-control">
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<button type="submit" class="btn btn-block btn-success" style="background: #00A79D;">Reset</button>
</div>
</div>
</form>
I implemented a method for Sign In with JWT and what it does is:
Fetches the email and password that is send with the request and
converts it into a string variable
I check if the email already
exists in the custom user model i made.
If the user already
exists, i convert the object model to dictionary so that i can get
its particular password.
In that i match the password
corresponding to user model and the password that is send with the
post request.
if the email exists in the user model and the password corresponding to that user model matches the password that is sent with the post request i use the pyJWT to make the JWT with my custom data and return the response.
In all other cases the email and password don't match and i return "No Match"
Suppose the request is {"email":"xyz#gmail.com", "password":"12345" }
#api_view(['POST'])
def signin(request):
email = list(request.data.values())[0] #gets email value from post request {"email":"xyz#gmail.com", "password":"123"} -> this xyz#gmail.com
password = list(request.data.values())[1] #gets password value from post request {"email":"xyz#gmail.com", "password":"123"} -> this 123
usr = User.objects.filter(email=email).exists() #checks if email exists
if usr:
dictionary = User.objects.filter(email=email).values()[0] #converts object to dictionary for accessing data like dictionary["password"] dictionary["first_name"] etc
if usr and dictionary["password"] == password: #check if email and its corresponing password stored matches the password that is sent
branch = dictionary["branch"]
id = dictionary["id"]
encoded_jwt = jwt.encode({'email': email,}, 'secret', algorithm='HS256')
return Response({'token':encoded_jwt,'email':email,'branch':branch,'id':id})
else:
return Response({'No Match'})
return Response({'No Match'})