I created a site where my techs submit their inventory using model forms. Everything is working as intended but I would like to add the function of sending the whole form as an email when they submit their inventory. This would allow for my inventory team to verify counts without having to log in and check the website.
Here is my view.py I know it works if I remove the email bits and saves to my models. Currently returns an error:
'dict' object has no attribute 'splitlines'
form = Inventory_Form()
if request.method == 'POST':
form = Inventory_Form(request.POST)
tech_field = form.save(commit=False)
tech_field.technician = request.user
tech_field.save()
if form.is_valid():
form.save()
name = form.cleaned_data['initials_date']
from_email = 'operations#imbadatthis.com'
subject = 'Weekly Inventory', form.cleaned_data['initials_date']
message = form.cleaned_data
try:
send_mail(subject, message, from_email, ['myemail#n00b.com'], name)
except BadHeaderError:
return HttpResponse('Invalid header found.')
return response, redirect('inventory_submitted')
return render(request, 'inventory.html', {'form': form})
Would it be better to save the form to a csv then attach it as an email? I looked at this and also had issues with that part.
I guess the error is raised at the send_mail because of
message = form.cleaned_data
Because this is a dict and the send_mail from django expects the message to be a string.
You have to convert the dict to a string.
Maybe this helps to make a nice looking email. (documentation)
Related
I want to send mail to many users using django sendmail.
I am using orm in sqlite3 to get the list of recipients stored in db.
However, the orm result includes 'queryset', so mail cannot be sent
Is there a way to exclude 'queryset' from orm results?
as-is
I want
views.py
def send_form(request):
if request.method == 'POST':
selected_target = request.POST['target']
target = contact.objects.filter(target=selected_target).values_list('email')
return render(request, 'view/send_form.html', {'target': target})
def send_success(request):
if request.method == 'POST':
subject = request.POST['subject']
recipient = request.POST['email']
message = request.POST['message']
send_mail(
subject,
message,
recipient,
[recipient],
fail_silently=False,
)
return render(request, 'view/send_success.html')
send result
Queryset returns to you all (many) of applicable results, if you want only one email, instead of filter use get,
target_email = contact.objects.get(target=selected_target).email
but with queryset (many emails) you can send to each email in a list of queryset
target_emails = contact.objects.filter(target=selected_target)
for each_email in target_emails:
target_email = each_email.email
#this will output your needed email
print(target_email)
#and later do logic with target_email to send mail on it
I want to accomplish the following, email verification with a verification code, not link
user signs up in a sign up form
user email is passed as context to a verification code entry form
user is sent a verification code
user enters the verification code in the verification code entry form
verification code is confirmed on the backend with the email sent from the first form context
So what I'm trying to do is that when the user accesses example.com/signup and fill out the form, I then render the verification_code_entry_form, and then they enter their verification code there. Finally once they submit that, they are redirected to login. However the difference between render and redirect is tripping me up.
in urls.py
path('signup', views.signup_page, name='signup'),
path('confirm_account', views.confirm_account, name="confirm_account"),
path('send_verification_code', views.send_verification_code, name="send_verification_code"),
in views.py
def signup_page(request):
form = CreateUserForm(request.POST or None)
context = {
'form': form
}
if form.is_valid():
new_user = form.save(commit=False)
password = form.cleaned_data.get('password')
email = form.cleaned_data.get('email')
try:
...backend authentication client work goes here
except Exception as e:
...catch exceptions here
messages.error(
request,
f'An unexpected error has occured.'
)
return render(request, 'accounts/signup.html', context)
else:
# Create user and verifications
new_user.save()
# Save the email in the context to use in the verification form
context['email'] = email
form = AccountConfirmationForm(request.POST or None)
context['form'] = form
messages.success(
request,
f'Account succesfully created for {email}. Please verify your e-mail, then login.'
)
# Redirect (render?) to verification code formation
return render(request, 'confirm_account.html', context)
return render(request, 'signup.html', context)
def confirm_account_verification_code(request):
if not request.get('email'):
"""
This represents a failure of the client to properly navigate to the verification code from signup or login
So we should prompt them to reset their verification code and re-render with context
"""
messages.error(request, f"An error occurred when processing your verification code request. Please try again")
return redirect(request, "resend_verification_code")
email = request.get('email')
form = AccountConfirmationForm(request.POST or None)
context = {
'email': email,
'form': form,
}
if form.is_valid():
try:
verification_code = form.cleaned_data.get('verification_code')
...submit to backend
except Exception as e:
...handle exceptions
messages.error(
request,
f'An error occurred trying to confirm your account'
)
return render(request, "confirm_account.html", context)
else:
return redirect(reverse('signup_success') + '?first_time=yes')
return render(request, "confirm_account.html", context)
Unfortunately my expected behavior isn't happening, though I acknowledge this doesn't seem quite right. Does django actually use the view function confirm_account_verification_code() when the return render(request, 'confirm_account.html', context) is called from the sign up form? I'm not entirely sure what I'm doing wrong here.
I am trying to send a mail with an attachment using Django, the attached file is sent to the server from a user submitted form. My code is shown below
form = RequestForm(request.POST, request.FILES)
if form.is_valid():
form.save()
messages.info(request, '')
subject = ''
message = ""
attachment = request.FILES['attachment']
mail = EmailMessage(subject, message, '', [''])
mail.attach(filename=attachment.name, mimetype=attachment.content_type, content=attachment.read())
mail.send()
I am receiving the mail, but the attachment in the mail is blank, i.e it doesn't contain any content. What am I missing here?
I have solved the issue, I placed the form.save() at the bottom i.e after sending the mail and the issue resolved. This is because, once we use form.save() the attachment gets stored in its path and we need to open it before we read it.
form = RequestForm(request.POST, request.FILES)
if form.is_valid():
messages.info(request, '')
subject = ''
message = ""
attachment = request.FILES['attachment']
mail = EmailMessage(subject, message, '', [''])
mail.attach(filename=attachment.name, mimetype=attachment.content_type, content=attachment.read())
mail.send()
form.save()
I believe you need to use attach_file instead of attach. attach_file allows you to pass a path, whereas you need to pass the actual data with attach. See docs.
Also, test that your attachment is actually getting uploaded, that you specified the right enctype on your form, etc. For example:
<form enctype="multipart/form-data" action="/whatever/" method="post">
I'm need some email form and I'm trying this:
views.py
def send_email(request):
if request.method != 'POST':
form = EmailForm()
return render_to_response('mail_form.html', {'email_form': form})
form = EmailForm(request.POST, request.FILES)
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
email = form.cleaned_data['email']
attach = request.FILES['attach']
try:
mail = EmailMessage(subject, message, settings.EMAIL_HOST_USER, [email])
mail.attach(attach.name, attach.read(), attach.content_type)
mail.send()
return render(request, 'mail_form.html', {'message': 'Sent email to %s'%email})
except:
return render(request, 'mail_form.html', {'message': 'Either the attachment is too big or corrupt'})
return render(request, 'mail_form.html', {'message': 'Unable to send email. Please try again later'})
forms.py
class EmailForm(forms.Form):
email = forms.EmailField()
subject = forms.CharField(max_length=100)
attach = forms.Field(widget=forms.FileInput)
message = forms.CharField(widget = forms.Textarea)
mail_form.html
...
{{message}}
<form method="post" action="">
{% csrf_token %}
{{ email_form.as_p }}
<input type ="submit" name = "send" value = "Send"/>
</form>
...
But constantly I get an error 403. I tried different solutions from the web, but nothing helped. What I'm doing wrong? I'm understand that something wrong with csrf in views.py, but don't understand where is the problem concretely.
Your problem is render_to_reponse. It doesn't have the context instance you can add it, but render handles this for you so why not just it instead. Also you can restructure your view to be a bit cleaner.
Here's one example.
def send_email(request):
if request.method == 'POST':
form = EmailForm(request.POST, request.FILES)
if form.is_valid():
subject = form.cleaned_data['subject']
message = form.cleaned_data['message']
email = form.cleaned_data['email']
attach = request.FILES['attach']
try:
mail = EmailMessage(subject, message, settings.EMAIL_HOST_USER, [email])
mail.attach(attach.name, attach.read(), attach.content_type)
mail.send()
messages.succes(request, 'Sent an email to %s' % email)
except:
messages.error(request, 'Either the attachment is too big or corrupt')
else:
form = EmailForm()
messages.info(request, "Send an email!")
return render(request, 'mail_form.html', {'email_form': form})
Then you can use {% if messages %} in your template to display your messages to the user / iterate over them and display.
messages here is from django.contrib so you'd need to do from django.contrib import messages
Use render_to_response from django.shortcuts
Use in render_to_response context_instance = RequestContext(request)
This must fix your problem with csrf token or read https://docs.djangoproject.com/ja/1.9/ref/csrf/
Just modify your view.py like this
from django.shortcuts import render
from django.template import RequestContext
def send_email(request):
if request.method != 'POST':
form = forms.EmailForm()
return render_to_response('mail_form.html', {'email_form': form}, context_instance=RequestContext(request))
......
......
What version of django are you using?
Well, obviously you are using render() in part of your code. The problem is in your GET code--you are using render_to_response():
if request.method != 'POST':
form = EmailForm()
return render_to_response('mail_form.html', {'email_form': form})
Instead use render():
return render(request, 'mail_form.html', {'email_form': form} )
See the example in the Django docs.
The reason you need to do that is because with csrf tokens you need to:
Insert the csrf token in your form.
Include the csrf token as a cookie in the headers of the request/response.
render() accomplishes #2, but render_to_response() does not--unless you specifically tell it to, which you did not. In any case, the django 1.9 docs state:
render_to_response()
This function preceded the introduction of render() and works
similarly except that it doesn’t make the request available in the
response. It’s not recommended and is likely to be deprecated in the
future.
I'm sending a form. So if it's valid i'm setting a variable message with a message. So if the form is valid, I would like to redirect to another view but also pass the message variable. It should be a syntax issue.
On successful submission, it redirects to a view with a url membership/enroll/studies.views.dashboard which of course is wrong.
views.py
def enroll(request):
user = request.user
if request.method == 'POST':
form = SelectCourseYear(request.POST)
if form.is_valid():
student = form.save(commit=False)
student.user = request.user
student.save()
message = 'Successfully Enrolled'
return redirect('studies.views.dashboard', {'message': message,})
else:
form = SelectCourseYear()
return render(request, 'registration/step3.html',)
Consider making use of sessions to store arbitrary data between requests: https://docs.djangoproject.com/en/dev/topics/http/sessions/
request.session['message'] = 'Successfully Enrolled'
Alternatively, if you just want to display a message to the user, you might be happy with the contrib.messages framework: https://docs.djangoproject.com/en/dev/ref/contrib/messages/
from django.contrib import messages
messages.success(request, 'Successfully Enrolled')
Based on your use case above, I'm guessing that contrib.messages is more appropriate for your scenario.