'Unable to access filefield file via URL with Django

tldr: Problems with accessing filefield's URL attribute led me to realize that I also have to check how to serve media files in debug mode with django's runserver. I have no clue how to continue.

Long version:

I am a Django newbie and totally lost how to access a filefield object with the browser.

Here is my settings.py in the project root:

import os 
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) 
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) 
MEDIA_ROOT = os.path.join(BASE_DIR, 'rgeingabe/documents/') 
MEDIA_URL = '' 
#STATIC_URL = 'static/' 
#STATIC_ROOT = os.path.join(BASE_DIR, 'rgeingabe/static')

I also set the DEBUG mode to true.

Here is the project's urls.py:

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

urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^rgeingabe/', include('rgeingabe.urls')),
]

if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

I hope that it is right to include that static information in the project's urls.py. First I tried to do that in the app's urls.py, but I guess that was wrong.

Next, to the models.py:

class Document(models.Model):
    beschreibung = models.CharField(max_length=255, blank=True)
    datei = models.FileField(upload_to='')
    hochgeladen_am = models.DateTimeField(auto_now_add=True)
    gehoert_zu_rg = models.ForeignKey('Pkvjanosch', on_delete=models.CASCADE)

def save(self, rgauswahl, *args, **kwargs):
    d = Pkvjanosch.objects.get(rg_id = rgauswahl)
    neuer_dateiname = d.rgsteller + " " + d.rgdatum.strftime("%d.%m.%Y")
    self.datei.name = neuer_dateiname
    super(Document, self).save(*args, **kwargs)
    d.scanablageort = neuer_dateiname
    d.save()

I try to access the download with a view. Here comes the app's views.py:

def uebersichteingaben_alle(request):
eingaben_alle_liste = get_list_or_404(Pkvjanosch)
alle_uploaddateien = get_list_or_404(Document)
context = {
        'eingaben_alle_liste': eingaben_alle_liste,
        'alle_uploaddateien': alle_uploaddateien
}
return render(request, 'rgeingabe/eingaben_alle.html', context)

And finally I tried a dozen approaches how to access the object with a template. So, I startet with something like upload.url, but this did not work. Neither did approaches like "{% url upload %}", "{% url upload.datei %}", "{{upload.datei.url}}, and many more. It is as if upload.url is just empty. Here is the template:

<html>
<body>
    <h1>Übersicht aller Eingaben</h1>
    {% if eingaben_alle_liste %}
       <table style="border-style:solid;border-width:3px;" rules="all">
          <tr>
             <th>ID</th>
             <th>Rechnungssteller</th>
             <th>Rechnungsdatum</th>
             <th>Rechnungsbetrag</th>
             <th>TK Übernahme</th>
             <th>Continentale Übernahme</th>
             <th>Abrechnungszeitraum</th>
             <th>Anmerkungen</th>
             <th>Scan</th>
        </tr>
        {% for eintrag in eingaben_alle_liste %}
        <tr>
             <td><a href="{%url 'rg_janosch:rgupdate' eintrag.rg_id %}">{{ eintrag.rg_id }}</a></td>
             <td>{{ eintrag.rgsteller }}</td>
             <td>{{ eintrag.rgdatum }}</td>
             <td style="text-align:right;">{{ eintrag.rgbetrag }}</td>
             <td style="text-align:right;">{{ eintrag.tkbetrag}}</td>
             <td style="text-align:right;">{{ eintrag.contibetrag }}</td>
             <td style="text-align:center;">{{ eintrag.rg_zeitraum }}</td>
             <td>{{ eintrag.anmerkung }}</td>
        {% if eintrag.scanablageort %}
            {% for upload in alle_uploaddateien %}
                {% if upload.gehoert_zu_rg_id == eintrag.rg_id %}
             <td><a href="documents/{{ upload.datei }}">Scan</a></td>
             <td>upload.datei: {{upload.datei}}</td>
                {% endif %}
            {% endfor %}
        {% else %}
             <td>&nbsp;</td>
        {% endif %}
    </tr>
    {% endfor %}
</table>
{% else %}
<p>Keine Einträge vorhanden.</p>
{% endif %}
</body>
</html>


Solution 1:[1]

Solved (at least partially).

To everyone who might have a similar problem: I changed the lines in settings.py to

MEDIA_ROOT = os.path.join(BASE_DIR, 'rgeingabe/documents/')
MEDIA_URL = '/documents/'
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, 'rgeingabe/static')

The end of my project's urls.py read now like this:

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

Finally in the template I could use this:

<td><a href="{{ upload.datei.url }}">{{ upload.datei.url }}</a></td>

I am so happy that it works now.

Now I have to think about if I find it good that instead of overwriting files, new files are written to disk with some kind of appendix in the name. And I have to figure out how to preserve the file extension while renaming the files in the upload process. Have a nice day everyone!

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 MDoe