2

I am trying to load a pdf file in django which is already present in the database. I can access the pdf file using the url, "localhost:8000/documents/file.pdf" but when I perform the query and return the response containing this file, url it redirects to "localhost:8000/ans/documents/file.pdf" which doesn't exist. The html code is:

<form id="signup-form" method="POST" action="ans/">
        {% csrf_token %}
            <input type="text" name="id" id="id" placeholder="Report id" />
            <input type="submit" value="Check" />
        </form>

The path in urls.py is

path('ans/',views.func),

The view is:

def func(request):
if request.method=="POST":
    id=request.POST.get("id")
    ans = query.objects.get(id=id)
    response=ans.repo
    if ans is None:
        return render(request,"index.html",{})
    else:
        return redirect(response)

The bottomline is, I wan't to get rid of the "/ans/" in the url.

Tahseen Rahman
  • 97
  • 3
  • 13
  • Try removing the `action` attribute from the form and provide feedback. – MiniGunnR Nov 24 '18 at 19:28
  • @MiniGunnR If I do that, then how will I pass the request to the view? – Tahseen Rahman Nov 24 '18 at 19:37
  • Create a different view that would uniquely render this pdf, define it in urls.py with it's own `path` and then use `HttpResponseRedirect('that_new_path')` – dmitryro Nov 24 '18 at 19:42
  • I didn't understand what you are trying to do in your view. Do you want to display the file somewhere or let someone to download it? – Rarblack Nov 24 '18 at 20:23
  • @TahseenRahman There is a certain way to write the view that is showing your form, using if else, in Django. It is not like you used to do in PHP. I've seen that `action` attribute can be skipped in Django forms. Please read up on `Forms` in django docs. – MiniGunnR Nov 24 '18 at 20:33
  • @Rarblack I am trying to view the file and as it happens in chrome, it automatically renders the pdf file. – Tahseen Rahman Nov 25 '18 at 05:57
  • @MiniGunnR If I don't use the action attribute, it again reloads the index page because in urls.py file, my code is path('',views.index), – Tahseen Rahman Nov 25 '18 at 06:00
  • @TahseenRahman If you don't provide the if else clause in your view then action is required. I don't use it and the forms work fine. – MiniGunnR Nov 25 '18 at 06:16
  • @MiniGunnR I am not using a forms.py file. My code is on www.github.com/tahseen09/delhipatho Can you please go through it and come up with a solution. Please consider the fact that I am a beginner. Thanks. – Tahseen Rahman Nov 25 '18 at 06:29
  • @TahseenRahman You need a lot of pointers on Django. Helping you with text is going to be tedious. If you are willing to join me on Skype, I can share my screen and show you how I would write code to solve this problem. You can share me your Skype ID. – MiniGunnR Nov 25 '18 at 08:35

2 Answers2

1

When you put ans/ it adds this to the url and file location is added right after it. To solve the issue remove ans/ and give name.

path('',views.func, name='func'),

Moreover, you have logical mistakes in view and form. You should have used either normal form or ModelForm to get id to form the form.

def func(request):
    if request.method=="POST":
        id=request.POST.get("id") # do not get id from url in post method
        ans = query.objects.get(id=id)
        response=ans.repo
        if ans is None:
            return render(request,"index.html",{})# do not render index.html just use HttpResponseRedirect. rendering is used for forms.
        else:
            return redirect(response) # redirecting to the file directly is a bad pattern.

Instead of these bad design, you should have used FileField in your models.py class and after that you would be eligible to get the url with file.url call in any place without redirecting it and you could easily assign it to any button.

Note: To skip the action attribute you should use I have mentioned above form and render it in the view method.

Edit : Lets say you want to view the file from a specific object(You just need to pass the pk of the object which can be done with url template tag)

<a href="{% url 'specific_request' pk=query.pk %}">Specific request</a>

urls.py

path('response/request/<int:pk>/', views.specific_request, name='specific_request')

view.py

def specific_request(request, pk):

    query = get_object_or_404(Request,
                              pk=pk)

    context = {
        'query': query
    }

    return render(request,
                  'view-request-specific.html',
                  context=context)

Now it is time to view the uploaded file on click template.py

<label for="id_file">Uploaded file:   </label>
<a id="id_file" href="{{ query.file.url}}">  {{ query.file.url}}</a>

file.url is the magic to retrieve the exact url of the file. so when it is clicked the file will be opened.

Rarblack
  • 4,559
  • 4
  • 22
  • 33
  • class query(models.Model): id=models.IntegerField(primary_key=True) repo=models.FileField(upload_to='documents/') This is my models.py file. I am directly uploading the file through admin panel and I want it that way. – Tahseen Rahman Nov 25 '18 at 05:50
  • And I am using a custom HTML 5 template to do this. The complete code can be found in www.github.com/tahseen09/delhipatho I am a beginner and if you could help me, I will be thankful to you. – Tahseen Rahman Nov 25 '18 at 06:07
  • I am getting the url I wanted but it is showing me an error of Suspicious File Operation – Tahseen Rahman Nov 25 '18 at 06:13
  • My other question is Can I use get method in the form? – Tahseen Rahman Nov 25 '18 at 06:24
  • Yes you can definitely use get method in the form but you will get parameters from url then they will be shown in the url – Rarblack Nov 25 '18 at 08:07
  • You should open another question for how properly upload and load a file to database and tag me in the comment I will contribute to it. For now, I guess I have answered your current question. But as I have mentioned in my answer what you are trying to do is not a Django style and a bad structure, therefore, it is not passing through internal security. Please, accept the answer to close the question and create a new one so I can help further @TahseenRahman . – Rarblack Nov 25 '18 at 08:12
  • I have no problem uploading the file, the thing is I am having a problem retrieving it from the database. I know what I am doing is bad structure. And I am seeking help for that. I have already searched a lot and haven't got any definite answer. MY problem is quite simple, I have two fields, one of id and other is FileField. ID being unique relates to file. By passing the id I want to retrieve the file from the database. This is what I have tried to do as a beginner. By the way, thanks a lot and if I open another question I will tag you. @Rarblack – Tahseen Rahman Nov 25 '18 at 11:58
  • Have you used FileFIeld in your model? Do you store the file in the media folder? – Rarblack Nov 25 '18 at 12:58
  • Yes. I have and I am uploading the file in the documents folder which I have mentioned in the settings.py as MEDIA_ROOT = os.path.join(BASE_DIR, '') MEDIA_URL = '/documents/' my models.py code is: class query(models.Model): id=models.IntegerField(primary_key=True) repo=models.FileField(upload_to='documents/') @Rarblack – Tahseen Rahman Nov 25 '18 at 13:08
  • I am a beginner and I am trying to figure things out in Django. I might be making silly mistakes but please understand I am learning and that's why I am seeking your help. The thing is I have solved the URL problem, Django app is navigating to my desired URL but it is showing me an error of Suspicious File Operation which means Django isn't allowing me to access the file via URL directly. There has to some other easy way or something which I don't know yet. I want help with that. Thanks a lot for taking out time for me but it would be great if you could help me a little more. – Tahseen Rahman Nov 25 '18 at 13:35
  • My advice open a new question, post your model, view, url and template code and I will try to correct them. But first close this question by accepting an answer. It is all mixed up here. – Rarblack Nov 25 '18 at 13:40
  • I have mentioned you in the comment of the new question. But in the edit, the html code goes where? and template.py file needs to be created? with just that code? – Tahseen Rahman Nov 25 '18 at 14:25
0

Remove the action attribute from your form tag in your template file and change your index function to something close to the following.

def index(request):
    if request.method == "POST":
        form = Form(request.POST)
        if form.is_valid():
            id=request.POST.get("id")
            ans = query.objects.get(id=id)
            response=ans.repo
            if ans is None:
                return redirect("index.html")
            else:
                #return render (request,"ans.html",{'ans':response})
                return redirect(response)
    else:
        form = Form()
    return render(request,"index.html",{'form':form})

I have not tested the above code, so please provide feedback of any errors that you are seeing.

MiniGunnR
  • 5,590
  • 8
  • 42
  • 66