Search code examples
djangofilefield

Display uploaded files in Django


I have a dashboard that displays files you uploaded. But I can't seem to figure out how to iterate through the files.

Here are my models:

@python_2_unicode_compatible
class Client(models.Model):
    user = models.OneToOneField(User)
    company = models.CharField(max_length=100)

    def __str__(self):
        return self.company

    class Meta:
        verbose_name_plural = _("Clients")
        verbose_name = _("Client")
        permissions = (
            ("can_upload", _("Can upload files.")),
            ("can_access_uploads", _("Can access upload dashboard.")),
            ("is_client", _("Is a client.")),
        )

@python_2_unicode_compatible
class ClientUploads(models.Model):

    client = models.OneToOneField(Client)
    #created_at = models.DateTimeField(auto_now_add=True)

    def generate_filename(self, filename):
        name = "uploads/%s/%s" % (self.client.company, filename)
        return name

    file_upload = models.FileField(upload_to=generate_filename)

    def __str__(self):
        return self.client.company

    class Meta:
        verbose_name_plural = _("Client Uploads")
        verbose_name = _("Client Upload")

Here is my view:

@login_required(login_url='/dashboard-login/')
def dashboard(request):
    current_user = request.user
    current_client = request.user.client

    files = ClientUploads.objects.filter(client=current_client).values('file_upload')

    if request.method == 'POST':
        form = UploadFileForm(request.POST, request.FILES)
        if form.is_valid():
            new_file = ClientUploads(client=current_client, file_upload = request.FILES['file_upload'])
            new_file.save()

        return HttpResponsePermanentRedirect('/dashboard/')
    else:
        form = UploadFileForm()

    data = {'form': form, 'client': current_client, 'files': files}
    return render_to_response('dashboard.html', data, context_instance=RequestContext(request))

And here is the template:

{% load i18n %}

<table class="table">
    <div>
        <p>{{ files }}</p>
    </div>
<tr>
    <th>{% blocktrans %}Filename{% endblocktrans %}</th>
    <th>{% blocktrans %}Size{% endblocktrans %}</th>
    <th>{% blocktrans %}Uploaded At{% endblocktrans %}</th>
</tr>
{% for file in files %}
<tr>
    <th>{{ file.name }}</th>
    <th>{{ file.size }}</th>
    <th>{{ file.url }}</th>
</tr>
{% endfor %}

</table>

The test div in the template displays [{'file_upload': u'uploads/Company/archive_addin_log_408hdCy.txt'}] Which is what I uploaded. So it's working, but I can't figure out how to iterate through all of the uploaded files. All I see are a bunch of blank lines under the table headings.

I use files = ClientUploads.objects.filter(client=current_client).values('file_upload') to get the files, I've tried a few other ways but can't seem to get it to work. I tried files = ClientUploads.objects.filter(client=current_client) but then I just get a QuerySet object and am not sure how to extract the file names and iterate through. I really don't understand it.

Any help would be much appreciated as I am very confused. I just can't seem to get the file object out of the model. How can I return a list of the objects and then in the template display the file object from the filefield and also display the created_at field. I need help understanding how to access the different fields within the model. If I had a list of file objects within that model I could just iterate through that and the created_at field, but I don't see how to do that.

Any suggestions and examples would help a ton.

Thanks

EDIT:

I also want users to be able to download the files, right now if they click the name it displays the file in the browser as I am serving media. I most likely will disable this. But I do need to let the user download the files that are displayed. How can I accomplish this? I can't find any information regarding how to let a user download a file.

Thanks


Solution

  • values() returns a special class named ValuesQuerySet which acts like a list of dictionaries containing the properties you pass into that as key/value pairs.

    Given the above information, the following query will give you a list of dictionaries where each of them contains a FileField instance for each ClientUploads object:

    files = ClientUploads.objects.filter(client=current_client).values('file_upload')
    

    It may not be easy to iterate over a list of dicts in the template so I would change the above query as follows:

    files = ClientUploads.objects.filter(client=current_client)
    

    and update for loop in the template like this:

    {% for file in files %}
     {% with uploaded_file=file.file_upload %}    
      <tr>
        <th>{{ uploaded_file.name }}</th>
        <th>{{ uploaded_file.size }}</th>
        <th>{{ uploaded_file.url }}</th>
      </tr>
     {% endwith %}
    {% endfor %}
    

    Hope this helps.