Downloading a FileField with a View - python

I have a table which presents order information - attached to each order is a file. This file's file path displays as a link in the table already, but I am unable to download by clicking it. I would like to be able to click this link and have the proper .docx download.
I am referencing: how to download a filefield file in django view
but I really don't understand how this solution is working. Is no URL needed? How does the view know which file to pick? I opened a previous question and got marked as a duplicate and pointed to this link, but I really don't understand the solution that was given here. Do I need to somehow pass the pk of the order or something? Any help would be greatly appreciated. Below is my code.
models.py
class Orders(models.Model):
...
order_file = models.FileField(upload_to='web_unit', null=True, blank=True)
...
def __str__(self):
return self.reference
index.html
<div class="table-responsive">
<table id="main_table" class="table table-striped table-bordered" cellspacing="0" style="width="100%">
<thead>
<tr>
....
</thead>
<tbody>
{% for order in orders %}
<tr>
<td>
<!-- Update book buttons -->
<button type="button" class="update-book btn btn-sm btn-primary" style="color: #FFCF8B; border-color: #FFCF8B; background-color: #FFF;" data-id="{% url 'order_update' order.pk %}">
<span class="fa fa-pencil"></span>
</button>
</td>
....
<td>Download</td> #this is the link
</tr>
{% endfor %}
</tbody>
</table>
When the link in the table is clicked - I'd like for the file to be downloaded - I need help on how to define the URL and the View to make this happen.
Right now when I click the link I get an error showing all the urls that were tried.

This is a bit complex stuff at first, but let me break it down for you.
First of all, the files you upload thorough Django are stored somewhere in the Filesystem (in case of default settings). This usually means your uploaded files go to your /media folder which is in the same directory as your other Django files are.
The path to the media folder can be defined in your Django settings file using the MEDIA_ROOT parameter. By default its probably next to your manage.py file.
To be able to download your uploaded files, you need to serve the files using a webserver (Apache, nginx, etc...). Here's a config snippet from a classic nginx setup:
# Media files
location /media {
alias /home/riverman/my-django-project/media;
}
This means, your uploaded file could be accessed (and downloaded) thorough a browser using the following imaginary link:
http://my-django-project.test/media/images/cat.png
Now here's the tricky part: Django does not store the full url (http://my-django-project.test/media/images/cat.png) to your file in the database, but instead, only the static part of it (/images/cat.png). Both the media folder's name (media in this example) and the website's URL (my-django-project.test) are subject to later change so it would not be clever to store it all in the database, but instead, you generate the full URL on-the-fly.
When you access the path to your desired file ({{ order.order_file.url }}) you only receive a partial information, something like this: /media/images/cat.png.
You need to combine this partial information with your site's url. Here's an example how i'd do it. Add this in your views.py:
from django.contrib.sites.models import Site
current_site = Site.objects.get_current()
current_site.domain
and update your index.html to this:
<td>Download</td>
To setup a local webserver on your development machine is out of scope for this question, but you can refer to this question: Best lightweight web server (only static content) for Windows
Good luck!

Related

Upload jpg with flask and html

I'm a beginner and i'm making a blog with flask and html right now but it only can post title and content, but i want to post some picture init, so if anyone know whats the essayist way to post it (print the pic on flask app) and can storage in db file, can u please help me out? Because i'm stuck in this for so long.
If you are using a flask form to upload a file, then from flask_wtf.file import FileField can be used as the form field to upload files.
class UploadImageForm(Form):
file = FileField(label='File Upload')
submit = SubmitField('Submit')
On the HTML side you will want:
<form action="{{ url_for(your.route, **kwargs) }}" method="POST" enctype = "multipart/form-data">
{{ form.name_of_file_field }}
{{ form.submit }} <!-- Or an input tag -->
</form>
Then your route that will be called when the form is submitted must require a POST method. In development, you can store your files locally within the static folder, but I would advise to store them in remote storage before putting the app on a server.
Once the file is stored and uploaded, then in your html you can render the image with:
<img class="image" src="{{ url_for('static', filename=image_file_path) }}"> where image_file_path is the path to the image. This path should be stored as an environment variable. The image file name can be stored on your db within one of your models data columns as a string. I suggest creating UUID's as the image file name so you are not dependent on the user's upload (i.e. if the filename is in a different language).
Miguel Grinberg has a great tutorial on this that will cover all of this and more including working with image objects, image validation, and security: https://blog.miguelgrinberg.com/post/handling-file-uploads-with-flask

How can I get a Django view.py to request a selected posts information such as primary key?

I have a Django project with an HTML file that lists all of the CSV files that have been uploaded to my Postgresql database and when you click on the CSV of interest a new page is rendered with the CSV model's basic information (name/time submitted).
This is the First Page:
{% for csv in Data_List %}
<button class="btn btn-primary" style = "font-size:1.2em;" >{{csv.name}}</button>
<br><br>
{% endfor %}
This is the second page:
<p>{{request.user.username}}'s Note
<h6>{{worklog.name}}
<br>
{{worklog.date}}
<br>
{{worklog.notes|safe}}
<br>
{{worklog.mycsv|safe}}
</h6>
</p>
However, my goal is that when you click the button a python VIEW will be passed (or just retrieve) the chosen posts primary key (or other information). I want to do this so the view can ask the database for the actual CSV and do some work.
How can I get a view.py to request a selected posts information such as primary key?
Thanks and Happy Coding
#The url
url(r'^anote/(?P<pk>\d+)$', views.A_Note, name = 'anote'),
#The view
def A_Note(request, pk):
#the rest of code here
return render(request, "some.html", {"thing":thing, "pk":pk, "etc":etc})
I learned that sharp brackets <> in a url passes the value through to the view where it can then be accessed as an argument when defining the view. From there it can easily be used in the code.
Thanks!

Accessing model data in Django template

I am using the below lines to pass data to my template index.html, model1 being the class in my models.py.
data = model1.objects.all()
return TemplateResponse(request, 'index.html', {'data': data})
I am able to access data on the front end by using a for loop as shown below
{% for x in data %}
<h3>{{x.name}}</h3>
<h4>{{x.department}}</h4>
{% endfor %}
Since there are mutliple objects in this data, my question is if I want to access only the department of particular object with certain name, how can I do that?
For example here I am using a for loop, consider there are two objects in the data. Then the output would be
name1
department1
name2
department2
So now if I need to access only name2 without any loop, how can i do that?
Updating the question: I am updating this question with html, so that the question looks clear.
table id="example" class="table table-striped" cellspacing="1" width="100%">
<thead>
<tr>
<th>ID</th>
<th>Name</th>
<th>Department</th>
<th>View/Edit</th>
</tr>
</thead>
<tbody>
{% for x in data %}
<tr>
<td>{{x.id}}</td>
<td>{{x.name}}</td>
<td>{{x.department}}</td>
<td>View</td>
<button type="button" class="btn-sm btn-primary btn-lg" data-toggle="modal" data-target="#myModal">
view</button></td>
</tr>
{% endfor %}
</tbody>
This is how my html looks, I am using data-table here. So all the data is captured in a table automatically. As you can see every row has a view button that I would implement. Once the user clicks the view button, I should pop up a modal dialog to show all the other details like {{x.dateJoined}} etc which I don't show in the table. But if I use a separate view to pop this dialog, I should send a request to the view from my template saying which row(with some ID) the user has clicked. How can i achieve that? How can I bind the view button with respective rows here?
You need to write custom template tag which will take the queryset and filtering parameters and returns you appropriate object, you can use simple_tag:
myapp/templatetags/myapp_tags.py
from django import template
register = template.Library()
#register.simple_tag
def get_model1_object(queryset, **filters):
if not filters:
raise template.TemplateSyntaxError('`get_model1_object` tag requires filters.')
retrun queryset.filter(**filters).first()
Then in template:
{% load get_model1_object from myapp_tags %}
{% get_model1_object data name='blah' as obj %}
Note: Your filtering criteria might yield multiple results but in get_model1_object i am only returning the first object assuming your criteria will be strict, change it according to your needs.
The first thing to understand is that template rendering happens on the server, before the user sees anything in their browser. The template is not sent to the user, only the HTML that the template generated. When the user is interacting with the page, the original template is not involved. So, you have two choices here:
You can render the data for all the objects in hidden div's on your page, then use javascript with something like a jquery dialog to display them on demand. This is only realistic if you have very few records.
You can create a second view with its own template, which renders just the HTML for the modal dialog contents. You could then, again using javascript/jquery, make an AJAX request to load the contents of the dialog that you need when you need it. In your first view template, the list of departments, include the url of the object you want to fetch, eg:
{% for x in data %}
<tr>
<td>{{x.name}}</td>
<td><a class="deptlink" href="{% url 'dept_detail' x.pk %}">
{{ x.department }}</a></td>
</tr>
{% endfor %}
Where dept_detail is the name of the urls.py entry for your view that supplies the contents of the dialog.
Then in your javascript, hook the a tag so it opens your dialog instead of leaving the page:
$('.deptlink').click(function (event) {
event.preventDefault();
# then the code after this is up to you, but something that'll
# load the url into your dialog and open it.
$('yourdialog').load($(event.target).attr('href'));
Since you say you are an intermediate in javascript I won't get into the details of implementation, but basically, the moral of the story is that the output of django is going to be an HTML page. Anything that you need to have on the client side either has to be in that page, or you will have to make another request to the server to get it... Either way, you'll need some javascript to do this, since you want a modal dialog with client side interaction.

Sending messages using Django Postman

I am trying to use Django-Postman and have gotten as far as being able to see the templates on the webpage after I press the link but I don't know how send messages works. According to the write view there should be a form loaded but all I get is the links to the other pages in the template. If someone could explain how to get this to work it would be fantastic.
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav ">
<li>MyCourse</li>
<li>Timetable</li>
<li>logout</li>
<li>Inbox</li>
</ul>
</div>
Recently had to set up postman myself, and based just off your snippet, I'm going to assume you wrote the ul element yourself.
So, if that's the case, postman actually expects to handle all of that for you. According to the docs, you need to create a base.html template inside your own template directory. A few blocks are expected to be present inside this template, namely {% title %} (text it will add to the page's title), {% extrahead %} (some extra js and css), {% content %} (would contain the missing forms you're looking for) and {% postman_menu %} (the menu links automatically generated by postman).
You could always create the menu links yourself, but I'd suggest you create a /postman folder in your app's template folder, then copy the base.html from the installed postman app (this contains the code for how to layout the ul). Just a little more django-esque, and usefull if you need to fiddle with the names of the template tags, etc, but that's up to you.
Hope this helps, happy coding.

linking outside of Django site in dev mode

I'm testing a django site on the local server: http://127.0.0.1:8000/
The sites internal links all work great, even the static links. However, when I try to link to an outside link with say google as text inside a text field of my blog model it doesnt render the link correctly. That blog model is then passed through as |safe (so that the html is rendered) to the template, and the link is instead trying to append everything to the static root:
http://127.0.0.1:8000/blog/view/http://google.com
Anyone know how to keep my static links working, but still have links that go outside of the site?
EDIT:
For example, here is a blog post that is stored in a TextField() from the admin, inside my blog app. The blog post has some links. The link to the /static/mytextfile works fine as it appends that to the http://127.0.0.1:8000/. However, the github link isnt working as it attempts to append the github link to http://127.0.0.1:8000/ and thus the outputted html creates "http://127.0.0.1:8000/http://github.com/":
<p><b>The Code</b><br>
<a href=”http://github.com/”>GitHub</a>
<p><b>Example Outputs</b>
<br>a text file
Here's the 404 error that I get:
Page not found (404)
Request Method: GET
Request URL: http://127.0.0.1:8000/blog/view/%E2%80%9Dhttp://github.com/%E2%80%9D
EDIT 2:
This is how I have been 'escaping' the html filter. Up until now it has worked fine at leaving my <p> etc alone. It is not however leaving my href links alone!
{% autoescape off %}
{% block content %}
<p>{{ post.body|safe }}</p>
{% endblock %}
{% endautoescape %}
Something seems to be wrong with your double quote characters for the GitHub link.
Instead of:
<p><b>The Code</b><br>
<a href=”http://github.com/”>GitHub</a>
Try:
<p><b>The Code</b><br>
GitHub
I think you should try google.

Categories

Resources