using Flask Mail to send the rendered form - flask

I am using flask_mail to send emails, while this works for text message, I need some help if i need to send a template itself (what does this mean: so I am rendering a report that contains multiple tables and a text area on the top with a submit button, once the user fills the text area and click on submit, I need flask to send the report containing table along with text data ).
This code fetches data from service now incident table
def incident():
service_now_url = SERVICE_NOW_URL
request_str = req
user = 'username'
pwd = 'password'
url = service_now_url + request_str
headers = {"Accept": "application/json"}
response = requests.get(url, auth=(user, pwd), headers=headers)
json_str = response.json()
records = json_str['result']
return records
This code below is used for rendering the text field and the table.
#app.route('/submit', methods=['GET','POST'])
def submit():
rec = incident()
form = Description(request.form)
shift = form.Shift.data
return render_template('index.html', rec=rec, state=STATES, form=form)
So for sending the email so far, I have written the function below, this sends an email but with table header only and no data.
def send_email(shift):
msg = Message(subject=shift ,recipients=['user#gmail.com'])
msg.html=render_template('index.html')
mail.send(msg)
I am not a Flask expert and still, in the learning phase, any help would be greatly appreciated.
#George thanks for your help, but this is not working, I have pasted below the html template with the modification suggested by you.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title> {{ title }} : Graph</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style/main.css') }}">
{% if sending_mail %}
<style>
{{ get_resource_as_string('static\style\main.css') }}
</style>
{% endif %}
</head>
<body>
<form action="/submit">
<p> {{ shiftsum }}</p>
<div align='left'>
<h1>Task</h1>
<table id="customers">
<th>Task Number</th>
<th>Description</th>
<th>State</th>
{% for records in rec %}
<tr>
<td>{{records['number'] }}</td>
<td>{{records['short_description']}}</td>
<td>{{ state[records['state']]}}</td>
</tr>
{% endfor %}
</table>
</div>
</form>
</body>
</html>

Change the definition of send_email() to as given below,
def send_email(shift, rec, STATES):
msg = Message(subject=shift ,recipients=['user#gmail.com'])
msg.html=render_template('index.html', rec=rec, state=STATES)
mail.send(msg)
And in the index.html make sure you enclose the form inside {% if form %} ... {% endif %} where ... indicates your form code.
I hope this helps.
Update (for fixing the missing css styles)
Add the following in your flask script below app = Flask(__name__) or in respective blueprint file,
def get_resource_as_string(name, charset='utf-8'):
with app.open_resource(name) as f:
return f.read().decode(charset)
app.jinja_env.globals['get_resource_as_string'] = get_resource_as_string
Add the following in the index.html
{% if sending_mail %}
<style>
{{ get_resource_as_string('static/css/styles.css') }}
</style>
{% endif %}
Where static/css/styles.css should be replaced with path to your css file. If more than one css file is there, just add {{ get_resource_as_string('static/css/styles.css') }} for each one of them, with their respective path as argument of get_resource_as_string()
Make the following changes in send_email(),
def send_email(shift, rec, STATES):
msg = Message(subject=shift ,recipients=['user#gmail.com'])
msg.html=render_template('index.html', rec=rec, state=STATES, sending_mail=True)
mail.send(msg)
I have added sending_mail=True as argument to the render_template() so whenever sending_mail is set, the render_template will add the content from the css files to the <style>...</style>.
I hope this fixes the missing css styles.

#George thanks for your help, anyways I have found out what was the missing link here,
so the thing is most of the email client doesn't support CSS that are stored locally(this what I found out, could be other things as well), so I used inline CSS and that is working perfectly and now I can see all the formatting that has been done inline in the HTML Template while sending the email.
thanks again for your help.

Related

Add Task doesnot working in django in ToDo List

this is task_list.html
<!--if we didnt create this tasklis.html we get error becoz as said in views .py it looks for tempate
we diidnt cdreated any list on template et-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>To Do List By Manasi</title>
</head>
<body>
{% if request.user.is_authenticated %}
<p>{{ request.user }}</p>
Logout
{% else %}
Login
{% endif %}
<hr>
<h2>WELCOME To My To List! </h2>
Add task
<table bgcolor="yellow" align="center" border="2px">
<tr>
<th>Task Name</th><th> Task Details</th><th>Edit Task</th><th align="center">Delete Task</th>
</tr>
{% for task in tasks %} <!--for task in object_list %}this is when we havent created objet context list yet in view.pywhen view.py only contains model=Task-->
<tr><td align="center">{{task.title}}</td><td align="center">View</td><td align="center">Edit</td>
<td align="center">Delete Task</td></tr> <!--i think this 'task' in url is context_objct_name in views.py but its false-->
{% empty %} <!--this is django template format for empty condition likewise ele etc.-->
<tr><td>No item</td></tr>
{% endfor %}
</table>
</body>
</html>
**this is task_form.html for add task ie.create task**
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Create task Form</title>
</head>
<body>
<h1>Create task form</h1>
Go Back
<form method="POST" action="">
{% csrf_token %} {{form.as_p}}
<input type="submit" name="Submit">
</form>
<!--django creates form for user model automatically on the basis of model attributes we provides while creating a form-->
<!--you wiill see the boxes an all is like a admin panel have but here is in horizotal manner so put as_p for vertical-->
</body>
</html>
I am creating a project "TO Do App" using django in pycharm.I created model for task first then create a taskview and detail vview and still here things are woked.then i created Create view and template for add task and things were worked. then created deleteview things are ok even i created login view. and then i created logout view,User registration.as i create user registration sucessfully i tried by registeriing for different users and creating their own tasklist but now add task is not working.
able to click on add task and afte filling details and presiing submit button i couldnt able to see the tasks in tasklist.
i can see these added tasks in admin panel but i cant see tasklist in list view template after creating logout and login and user registration.
also i couldnt see any errror after submiting task.
here is task_form.html page to after pressing add task in task_list.html it redirects to task_form.html
views.py screenshot 1:
viwes.py screenshot 2:
if your all the views like registration , login are working perfectly then there could be an error in the views where you render your task_list.html
can you share your view which renders your task_list.html and model of the to_do list

Pass variable to view Django

Im pretty new to django. I have created an website that outputs data from an API to an table in django.
I created an app called 'display_networks'. Inside the views.py of this app i have the following code:
from django.shortcuts import render
from django.views.generic import TemplateView
from .services import get_networks
# Create your views here.
class GetNetworks(TemplateView):
template_name = 'networks.html'
#context == dict
def get_context_data(self, *args, **kwargs):
context = {
'networks' : get_networks(),
}
return context
As you can see i import an function called 'get_networks' from .services (services.py).
Inside services.py i have the following code:
import os
import requests
import json
# Headers
apikey = 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
headers = {'x-cisco-meraki-api-key': format(str(apikey)), 'Content-Type': 'application/json'}
# Headers
def get_networks():
url = 'https://api.meraki.com/api/v0/organizations/XXXXX/networks/'
r = requests.get(url,headers=headers)
networks = r.json()
return networks
Inside my app i have created a templates folder with an index.html. Inside this index.html i have the following code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Meraki Networks</title>
<link crossorigin="anonymous"
href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css"
integrity="sha256-8B1OaG0zT7uYA572S2xOxWACq9NXYPQ+U5kHPV1bJN4="
rel="stylesheet"/>
<link rel="shortcut icon" type="image/png"/>
</head>
<body>
<nav aria-label="main navigation" class="navbar is-light" role="navigation">
<div class="navbar-brand">
<div class="navbar-item">
<img alt="Meraki" src="https://upload.wikimedia.org/wikipedia/commons/thumb/3/3a/Meraki_Logo_2016.svg/1920px-Meraki_Logo_2016.svg.png"
style="margin-right: 0.5em;" width="142" height="142">Networks
</div>
</div>
</nav>
<table class="table is-bordered is-striped is-narrow is-hoverable is-fullwidth">
<thead>
<tr>
<th>Network Name</th>
<th>Network ID</th>
<th>Time zone</th>
<th>Tags</th>
</tr>
</thead>
<tbody>
{% for network in networks %}
<tr>
<td>{{ network.name }}</td>
<td>{{ network.id }}</td>
<td>{{ network.timeZone }}</td>
<td>{{ network.tags }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</body>
</html>
This works good and i have the data i want to display.
What i want to do is add an extra column to my table with the header "Get device info" and with an button titled 'Get devices' as the table data.
What this button has to do is send the variable 'network.id' to an different function in my services.py.
I have created a new function inside my services.py with the following code:
def get_devices(net_id):
url = 'https://api.meraki.com/api/v0/networks/'+net_id+'/devices/'
r = requests.get(url,headers=headers)
devices = r.json()
return devices
The variable "net_id" has to come from the button click and the button has to call this function and display the output the same as i have done for the networks.
Does anybody have an idea how i can achieve this?
Thanks in advance!
As the question asks how to pass a variable to a view. The answer is:
Pass it inside the url.
Pass it as a GET or POST parameter in the request (can be done using forms etc.).
Pass it inside the request body.
To solve your problem we shall use the 1st option for it's simplicity. First in your urlpatterns we shall make a pattern that will capture some arguments and these shall be passed to the view:
urlpatterns = [
# Other patterns
path('device/<str:network_id>/', views.GetDevices.as_view(), name='get_devices'),
# Other patterns
]
The <str:network_id> here means that network_id would be passed as a keyword argument to the view. Check more details about the URL dispatcher.
Your view GetDevices would handle getting the devices:
from .services import get_devices
class GetDevices(TemplateView):
template_name = 'devices.html'
#context == dict
def get_context_data(self, *args, **kwargs):
context = {
'devices' : get_devices(kwargs['network_id']),
}
return context
Now in your template with the table for networks you would write the following to add an anchor tag with a link to this new page:
<td>Get Devices</td>
You can style this anchor to look like a button using css / actually put a button tag inside it.
I am sure you know how to make templates so I would leave the task of making 'devices.html' to you.

Django models to HTML. Then, HTML to PDF

I am trying to export django models data (admin side data) into a PDF file.
For that first I created a HTML file to render the data from models.
The HTML file I created
It worked successfully and showed the data from the models correctly.
Successfully worked (I create a url for it to check whether it is working or not)
Then I tried to render the same html file to PDF. I ran the server and I generated a pdf file.
PDF file I expected it will show the data also. But It only showed the table border.
You can see my folders and names in the 1st photo.
I thing it is enough to add this code. If you need full code please tell me.
This is my views.py from app.
def render_to_pdf(template_src, context_dict={}):
template = get_template(template_src)
html = template.render(context_dict)
result = BytesIO()
pdf = pisa.pisaDocument(BytesIO(html.encode("ISO-8859-1")), result)
if not pdf.err:
return HttpResponse(result.getvalue(), content_type='application/pdf')
return None
class ViewPDF(View):
def get(self, request, *args, **kwargs):
pdf = render_to_pdf('app/pdf_template.html')
return HttpResponse(pdf, content_type='application/pdf')
Can't I use the same html file to get the data as pdf?
Can anyone tell me what wrong I did?
pdf_template.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>This is my first pdf</title>
</head>
<body>
<center>
<h2>User Table</h2>
<table border="1">
<tr>
<th>Username</th>
<th>E-mail</th>
<th>Country</th>
<th>City</th>
</tr>
{% for result in user %}
<tr>
<td>
{{result.username}}
</td>
<td>
{{result.email}}
</td>
<td>
{{result.country}}
</td>
<td>
{{result.city}}
</td>
</tr>
{% endfor %}
</table>
</center>
</body>
</html>
I got the correct out put. I am posting this as an answer so that it will use for someone else too.
class ViewPDF(View):
def get(self, request, *args, **kwargs):
context={}
context['user'] =user.objects.all()
pdf = render_to_pdf('app/pdf_template.html',context_dict=context)
return HttpResponse(pdf, content_type='application/pdf')
In the views.py I modified the code like above.
i see you used 'user' as a list for your 'for' condition but you never add it to your context. i think it's working fine but there is no data to show
update:
in the 'render_to_pdf' you get 'context_dict' argument to render your template by that. but you never pass this argument when you call your function. that's why you can' see anything except borders. because there is no data
update 2: in this line :
pdf = render_to_pdf('app/pdf_template.html')
just add context dict. something like this:
pdf = render_to_pdf('app/pdf_template.html',context)

How to use links to local server as href in Django?

I want to have links that are clickable . That link is a path in a server.
Example:
file:///I:/IT/Install/Winrar/
SO far I have my view code:
def installables_available(request):
install_path = r'I:/IT/Install/'
list_setup = os.listdir(install_path)
full_path = [os.path.join(install_path, item) for item in list_setup]
return render(request, 'generic/installables.html', {'full_path': full_path})
And the html looks like:
<html lang="en">
<head>
<title>All Installables</title>
</head>
<body>
<h1>Below are all setups available</h1>
{% for name in full_path %}
<ul>
<li><a href={{name}}> {{name}}</a></li>
</ul>
{% endfor %}
<hr>
<p>Thanks for visiting my site.</p>
</body>
</html>
I do get the page showing links but , If I click them, they don't do anything. But hovering on them shows the correct path i.e e.g file:///I:/IT/Install/Winrar/.

Django render_to_response displaying raw text

I am new to Django and I'm trying to create a simple html skeleton to verify everything is working properly. Everything is working (server is running and it loads the file) yet when I put in HTML code it is displayed as raw text instead of rendering it correctly.
My views.py is as follows
def home(request):
return render_to_response('index.html')
My 'index.html' is as follows
<!DOCTYPE html >
<html>
  <head>
   <meta charset="UTF-8">
   <title> awesome </title>
  </head>
  <body>
  
  </body>
</html>
What should I do to have it render correctly? (Display only "awesome")
EDIT
As far as this problem goes, the error came in that I saved the raw code as html. When I chose this option, it added the code to make html render it look like a raw input.
Moral of the story: Make sure you do your edits in a text editor and change extension by hand
A few problems..
1: what's with the spaces inside your tags?
< title > is invalid. It needs to be <title>Foo</title> That's why you're seeing "html".
2: Even if the title tag was written correctly, a title tag does not render, so you will get a blank page. If you want to display "awesome" -- you need to write it inside the body tag.
<body>awesome</body>
1) Remove spaces in < title > tag
2) And add bellow code in your urls.py file no need to map with view you can render html page from url also
(r'^home/$', 'django.views.generic.simple.direct_to_template',
{'template': 'index.html'}),
The first thing you need to do is create a "base" template so the other templates can extend from. You will normally call it base.html but you can use the name you want. You also need to create blocks that extended templates can use:
base.html
<!DOCTYPE html >
<html>
<head>
<meta charset="UTF-8">
< title > awesome < /title >
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
Then, you have to extend base.html from your index.html and use the content block we have created:
index.html
{% extends "base.html" %}
{% block content %}
{% endblock %}
At this point, index.html will be exactly as base.html because you are not showing anything inside the content block. Update your view with some data like this:
views.py
def home(request):
data = {'name': 'YourName', 'age': 25}
return render_to_response('index.html', data)
Now, again, update your index.html:
index.html
{% extends "base.html"%}
{% block content %}
<p>My name is {{ name }}</p>
<p>I'm {{ age }} years old</p>
{% endblock %}
Don't forget to read the fine tutorial.