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.
Related
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 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')
I'm using an HTML template form, from where if someone contacts me through that form I want to save it in my DB.But I could make it to save the data in DB.My codes are below.
MY HTML
<form method="POST" action="{% url 'home' %}">
{% csrf_token %}
<input type="text" name="name">
<input type="email" name="email">
<input type="text" name="subject">
<textarea class="form-control" name="message"></textarea>
<a class="contact-btn" href="" role="button">submit</a>
</form>
MY VIEW
def home(request):
if request.method == 'POST':
name = request.POST.get("name")
email = request.POST.get("email")
subject = request.POST.get("subject")
message = request.POST.get("message")
contact_details = contact()
contact_details.name = name
contact_details.email = email
contact_details.subject = subject
contact_details.message = message
contact_details.save()
return redirect
return render(request,'home.html')
URL
path('', contact.views.home, name='home'),
MODEL
class contact(models.Model):
name = models.CharField(max_length=255)
email = models.CharField(max_length=70)
subject = models.CharField(max_length=70)
message = models.TextField()
When I enter some data in the form field and press submit button nothing happens. Sometimes the home page reloaded while I press the submit button but nothing is going in my DB.In the admin panel, I saw only my created model object(I create 1 manually) but nothing else is going on to my DB.
As dirk says, you don't have a submit button. You just have a link styled to look like a button. But just because it looks like one, doesn't mean it will act as one.
<button class="contact-btn" type="submit">submit</button>
I am using both POST and GET method through python requests to fetch datas and submit data in an API.
class ApiLoginView(TemplateView):
template_name = 'index.html'
def post(self,request):
email = request.POST.get('email')
print(email)
password = request.POST.get('password')
print(password)
API_KEY = 'xxxxxxxxxxxxxxxxxxxxxxx'
API_URL = 'http://dev.com/rest/storeLogin'
parameter = {
'authToken':API_KEY,
'email':email,
'password':password,
}
r = session.post(url = API_URL, params=parameter)
print(r.json()['code'])
return render(request,'index.html')
With this above views.py class method i'm trying to post data.and I have an readymade HTML form for login ready.
<form class="my-login-form" action="/login" method="post">
{% csrf_token %}
<div class="field-wrap">
<input type="email" name="email" required autocomplete="off" placeholder="Email Id"/>
</div>
<div class="field-wrap">
<input type="password" name="password" required autocomplete="off" placeholder="Password">
</div>
<button class="button button-block"/>Login</button>
<div class="forgot"><a class="user-form-toggle" href="#forgot">Forgot Password?</a></div>
</form>
So my dilemma is how to map both class based view and html form. Right now it seems html form is stand alone!
You should check djangorestframework. It's a good framework for defining REST APIs with multiple formats, filters, etc, by doing mostly configuration instead of code.
in Django I make a form which get an email address and save it in database and this my form.py:
class NewsletterUserSignUpForm(forms.ModelForm):
class Meta:
model = NewsletterUsers
fields = ['email']
def clean_email(self):
email = self.cleaned_data.get('email')
return email
and this is my views.py :
def newsletter_signup(request):
form = NewsletterUserSignUpForm(request.POST or None)
if form.is_valid():
instance = form.save(commit=False)
if NewsletterUsers.objects.filter(email=instance.email).exists():
messages.warning(request, 'Your Email Already Exist In Our DataBase.',
'alert alert-warning alert-dismissible')
else:
instance.save()
messages.success(request, 'Your Has Been Submitted To Our DataBase.',
'alert alert-success alert-dismissible')
context = {
'form': form,
}
return render(request, 'newsletter/subscribe.html', context)
the problem is here that this form has it own input which the input must put inside it but I want to design my own template and get input in my template then pass it to this form and my question is how do I can pass inputs in my .html template file to my form?
this is my html file and don't know to put what in href for input tag :
<form method="post" class="login100-form validate-form">
{% csrf_token %}
<span class="login100-form-title p-b-43">
Subscribe
</span>
<div>
<inputtype="email" name="Email">
<span class="label">Email</span>
</div>
<button type="submit" href="">
Subscribe
</button>
</div>
and what should I put in my href and how pass input to form from here?
In addition, I'm sorry for writing mistakes in my question.
From what I understand, you want to create your own custom input box and when that box is filled, you want the form input box to also get filled.
Hide the form input box using display:none.
Create your own custom input box, use javascript to fill the form input box when custom input box is filled.
Ex :
<script>
form_input_box = document.getElementById('id_of_form_input_box')
custom_input_box = documen.getElementById('id_of_custom_input_box')
$("id_of_custom_input_box").change(function(){
form_input_box.value = custom_input_box.value
});
</script>
the problem it was for my html code, I Should add an id and name attribute to my input tag and use this id and name for getting input from html and pass it to my form, and for href attribute I write the url that redirect to my form.
fixed html code:
<form method="post" class="login100-form validate-form">
{% csrf_token %}
<span class="login100-form-title p-b-43">
Subscribe
</span>
<div class="wrap-input100 container-login100-form-btn rs1 rs2 validate-input padding-50"
data-validate="Username is required">
<input id="email" maxlength="100" class="input100" type="email" name="email">
<span class="label-input100">Email</span>
</div>
<div class="container-login100-form-btn">
<button type="submit" href="{% url 'newsletter_subscribe' %}" class="login100-form-btn">
Subscribe
</button>
</div>
<div class="text-center w-full p-t-23">
<a style="font-size: 15px" href="{% url 'newsletter_unsubscribe' %}" class="txt1">
Click Here To Unsubscribe.
</a>
</div>
</form>