About Display uploaded files in Django Templates.

Where is the code where you are putting data into the FileUpload model?

(What’s your view that accepts the files to be uploaded and stored? Or, if you’re not uploading files through a form, what commands or processes are you using?)

Here my apologies, I forgot to add some logics in files function.

views.py:

from FileHub.models import FileUpload
from django.shortcuts import render

class UploadView:
    def files(request):
        if request.method == 'POST':
            pdf_file = request.FILES['document'] if 'document' in request.FILES else None
            newvar = FileUpload(pdf_file=pdf_file)
            newvar.save()
            print(newvar)  # FileUpload object (6)
        return render(request, "file_upload.html")
    
    
    def show_data(request):
        context = {
            "fileupload_list": FileUpload.objects.all(),
                   }
        return render(request, "display_files.html", context)

uploadview = UploadView()

display_files.html:

<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Uploaded Files</title>
    <style>
      * {
        margin: 0;
        padding: 0;
      }

    </style>
  </head>

  <body>
    {% load static %}
    {% for fileupload in fileupload_list %}
      <div class="doc">
        <div class="file_desc">
          <iframe src="{{ fileupload }}" width="50%" height="50%"></iframe>
          {% comment %} <a href="{{ fileupload.url }}"> My files </a> {% endcomment %}
        </div>
      </div>
    {% endfor %}
  </body>
</html>

But can’t understand why it returns,

Not Found
The requested resource was not found on this server.

That error occurs in every object’s declaration.

Why have you put your two function-based views inside a class?

And in your template you have this:

<iframe src="{{ fileupload }}" width="50%" height="50%"></iframe>

It should use fileupload.url

When does this happen?

Please show your urls.py and the “file_upload.html” template.

When I implement {{ fileupload.url }}. It shows empty space in the area of each file object width=“50%” height=“50%”.

files_upload.html:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>File Uploads</title>
</head> 

<body>
  <form method="post" enctype="multipart/form-data">
    <pre> 
            {% csrf_token %}
            {{new_form.as_p}}
    <label for="File">Upload PDF Files</label><br>
    <input type="file" name="document">

    <button class="btn" type="submit"> Submit </button>
  </form>

  <form action="/user_data/" method="post" enctype="multipart/form-data"> {% csrf_token %} {{new_form.as_p}}
    <button class="btn2" type="submit"> Data </button>
    
  </form>
</pre>
</body>

</html>

urls.py (Django app):

from django.urls import path
from . import views

urlpatterns = [
    path('', views.UploadView.files),
    path('user_data/', views.UploadView.show_data, name="show_data"),
]

Not Found
The requested resource was not found on this server.

The error inside the each object is happen when I click on the Data button and it shows display_files.html.

Here is my Django Project’ s urls.py:

from django.conf.urls.static import static
from django.urls import path, include
from StorageStation import settings
from django.contrib import admin


urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include("FileHub.urls"))
    
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 

I think you should move your two view methods out of the UploadView class. The class structure isn’t doing anything and it’s only confusing matters. For one thing, methods in a class should have self as their first argument, then any other arguments.

So, change them to functions, outside of a class, and adjust your app’s urls.py accordingly.

In display_files.html, using {{ fileupload }} is rendering a FileUpload object, which will output the results of its __str__() method. At the moment that returns the name property of the FileUpload.file_url field.

This might be what you need at the moment but if you ever change the __str__() method, so that it looks different in Django Admin, for example then your template will break.

I’d be explicit and put {{ fileupload.file_url.name }} in the template, if that’s what you want. But you probably actually want {{ fileupload.file_url.url }} – the URL of the file, not the relative filesystem path.


I assume your files_upload.html template is actually file_upload.html, because that’s what you call it in the UploadView.files() method. Both of them try to render {{ new_form.as_p }} but neither of your views sends a new_form to the template, so that’s going to do nothing.

The first form, with a “Submit” button, submits to the current URL, which will send the POST request to the UploadView.files() view. What happens when you submit that form?

The second form, with a “Data” button, has no fields (apart from {{ new_form.as_p }}, which as I said, does nothing). It submits to /user_data/, which will send POST request to the UploadView.show_data() view. That view does not expect to process a POST request so it will do nothing with the data.

It’s hard to work out exactly what you want to happen. If you want pressing the “Data” button to take you to the page listing the FileUpload objects, then why use a form? You just need a link:

<a href="{% url 'show_data' %}">Data</a>

There I’ve used the url template tag to link to the URL named “show_data”.

As you said there is no need of class then I removed it. And I have made changes accordingly.

I understood what you said about __str__() method. I had executed both of them (FileUpload.pdf_file.name and FileUpload.pdf_file.url).

But you said that if I ever change the __str__() method, what looks different in Django Admin?
For what the use of __str__() method in Django Admin?
And if the object representation logic resides with the Django admin then what about the user-side representation of file objects?

According to your perspective, The concept of Form confused me so I removed it from the file_upload.html . (No error occurred after made changes).

In first form, The files() Function just take the file from user using FileField() and after click on the submit button, send the object of FileField() to the model. (We have to show this File object to display_file.html. so when I click on object the File should open.)

<a href="{% url 'show_data' %}">Data</a>

For insatnce,
If there are only 5 objects then it shows 5 clickable Data but nothing is happen after clicking on it.

I just want to take a File Object from models and simply render to the html page. It is not but why seems very complicated.?

As the docs say the __str__() method is used wherever you output an object as a string. Django Admin uses this by default in the lists of objects, and as the title of the page when editing one.

It’s also used in the console if you view an object (e.g. doing print(FileUpload.objects.first())).

Maybe I’m over-complicating things for you. I expect lots of people rely on using __str__() to display things in templates to the users.

But, to me, what you – the developer, and Django Admin user – finds useful as the “string version” of an object, is not always the same as what is useful to the end user in templates.


To be clear, it was the second <form></form> in the template that wasn’t doing anything useful. A Form, in Django terms is a class that’s quite different.


This isn’t quite correct, as a description.

When the first HTML form is submitted it sends a POST request which is received by the files() view.

This request contains a "document" field. The view uses this data to create and save a FileUpload object.

At the moment, the view will then render the “file_upload.html” template again.


Why are you showing five objects there?

Originally you had this in files_upload.html:

  <form action="/user_data/" method="post" enctype="multipart/form-data"> {% csrf_token %} {{new_form.as_p}}
    <button class="btn2" type="submit"> Data </button> 
  </form>

Which we replaced with this:

<a href="{% url 'show_data' %}">Data</a>

That is a link to the show_data page, which renders the display_files.html template, which lists the files.


In the end it isn’t very complicated, but you’ve got things into quite a tangle and we’re trying to untangle them. A piece of string is very simple, but once it’s in a tangle it seems complicated until you untangle it :slight_smile:

Only a sample has been taken so that you understand

Your are right. It shows the list of files but not openable.

Yes, because this:

<a href="{% url 'show_data' %}">Data</a>

was to be used in the file_upload.html template to link to the show_data page.

If you just move it to the display_files.html template, it’s the same HTML. Which links to the show_data page. Which is the page you’re on. So it doesn’t do anything.

If you look further back up the comments above, what were we using to link to a file, instead of {% url 'show_data' %}?

We used {{ fileupload.url }} ??

So what happens if you use that?

After using both one by one, nothing shows like before.

What does the template look like now?


  <body>
    {% load static %}
    {% for fileupload in fileupload_list %}
      <div class="doc">
        <div class="file_desc">
          {% comment %} <iframe src="{% url 'show_data' %}" width="50%" height="50%"></iframe> {% endcomment %}
          <a href="{{ fileupload.url }}">Data</a>
        </div>
      </div>
    {% endfor %}
  </body>

The web page looks same as I posted a screenshot above.

Now I see this I realise it’s wrong. fileupload.url is trying to output the url field on a FileUpload object. Is there one?

class FileUpload(models.Model):
    pdf_file = models.FileField()

No! There’s a pdf_file field. We actually want to output the URL of the pdf_file field.

How would we do that? What can you try?

As far as I understand. PDFs will go to models of FileUpload via pdf_file. so we have make changes in fileupload_list function.

def show_data(request):
    context = {
        "fileupload_list": FileUpload.objects.all(),
               }
    return render(request, "display_files.html", context)

Am I right…?

Not quite.

What I think might not be clear here is that files being uploaded are not stored in the model.

Files being uploaded are stored in the directory identified by the MEDIA_ROOT setting.

What is stored in the model is a reference to that file, in the pdf_file FileField within the model.

A reference to FileUpload is a reference to a class. You need to use the pdf_file field name to get the reference to the uploaded file.

See the docs for FileField for more detailed information.

def files(request):
    if request.method == 'POST':
        pdf_file = request.FILES['document'] if 'document' in request.FILES else None
        newvar = FileUpload(pdf_file=pdf_file)
        newvar.save()
        # print(newvar)
    return render(request, "file_upload.html")

The files has been store in models and in MEDIA_ROOT directory correctly.

But what does the meaning of the references of files?

And I changed the __str__() function from return FileUpload.file_url.name to FileUpload_pdf_file.url.

This is not an accurate statement.

The file is not stored in the model.

The file name is stored in the pdf_file field within the model. It is a reference to the file, not the file itself.

The file is only stored in the location identified by MEDIA_ROOT.

So it means, it is not about models. if I want to display files, I should take it from MEDIA_ROOT and display it on Django template… Am I not correct…?