Django Form not showing the attachment link

User retrieves data via an api call. When he inputs the data in the django form.Forms the attachment is showing as blank.

forms.py:

class PaymentListForm(forms.Form):

  Title = forms.CharField(max_length=50)
  Receipt_Amount = forms.DecimalField(max_digits=8, decimal_places=2)
  Request_Amount = forms.DecimalField(max_digits=8, decimal_places=2)
  Receipt_Attachment = forms.FileField()

  def __init__(self, *args, **kwargs):
       super(PaymentListForm, self).__init__(*args, **kwargs)

views.py:

def edit_payments(request, trn_pk):
    trns = get_transaction_by_id(trn_pk)
    data = trns['data']
    if request.method == 'GET':
        form = PaymentListForm(initial=data)
        return render(request, 'paymentlist/createeditpayments.html', {'form': form})

the problem has raised on Udemy and StackOverflow.

There is no possibility to set initial value for FileField like in CharField or DecimalField but there is a way to solve this problem. What we need is to hide forms.FileField and handle loading files by a label and show initial data as just text. so first hide forms.FileField:

forms.py:

class PaymentListForm(forms.Form):
  Title = forms.CharField(max_length=50)
  Receipt_Amount = forms.DecimalField(max_digits=8, decimal_places=2)
  Request_Amount = forms.DecimalField(max_digits=8, decimal_places=2)
  Receipt_Attachment = forms.FileField(label="", widget=forms.FileInput(
      attrs={'style': "display: none",},
  ), )

  def __init__(self, *args, **kwargs):
    super(PaymentListForm, self).__init__(*args, **kwargs)

now we need to add tag to handle uploading files instead forms.FileField and tag where we’ll display info about attachment url. I’m not sure how html template looks exactly so i’ve made some generic one - important tag we need to place inside tag.

createeditpayments.html:

<form method="POST" action="" enctype="multipart/form-data">
   {% csrf_token %}

   {{ form.as_p }}

   <span>Receipt attachment: </span>  
   <label for="id_Receipt_Attachment" class="mt-2 btn btn-primary " style="cursor: pointer;">Choose file...</label>
   <span id="receipt_url"> {{ url_of_receipt }}</span>
   <br><br>
   <button class="btn btn-primary" role="button" type="submit">
     Save
   </button>

so we should get such output:
1
of course u can style label, span as u want to. now we need to change a bit the view - specially to add to context dictionary url_of_receipt.

views.py:

def edit_payments(request, trn_pk):
    trns = get_transaction_by_id(trn_pk)
    data = trns['data']
    if request.method == 'GET':
        form = PaymentListForm(initial=data)
        return render(request, 'paymentlist/createeditpayments.html', {'form': form, 'url_of_receipt': data['Receipt_Attachment']})

i’ve assumed that data is a dictionary with such structure:

        data = {
            'Title': 'Example title',
            'Receipt_Amount': 21.99,
            'Request_Amount': 34,
            'Receipt_Attachment': 'media/example.receipt.pdf' 
        }

so now we’ve got such output:
2
and very last thing is to switch on uploading files after clicking the label. think the best way is to use jQuery and short script. so i the bottom of createeditpayments.html place such code:
createeditpayments.html

{% block javascript %}
    <script>
        // fetch url from hidden FieldField and insert it next to upload button
        $("#id_Receipt_Attachment").change(function () {
            {#readURL(this);#}
            $('#receipt_url').text(' ' + this.files[0].name);
        });
    </script>
{% endblock %}

and in base.html (or any html which createeditpayments.html extends) place just above closing tag:

base.html:

    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"
        integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
        crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.0/dist/umd/popper.min.js"
        integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo"
        crossorigin="anonymous"></script>


    {% block javascript %}{% endblock %}

</body>

now the label should upload files and change url next to it.