Search code examples
djangourl-routingfilefield

Determine model instance from file URL


Given the URL in the request is for a known static file, how can I determine which model instance references that file?

If I have several different Django model each with an ImageField, those fields each know how to store a relative path on the filesystem:

# models.py

from django.db import models

class Lorem(models.Model):
    name = models.CharField(max_length=200)
    secret_icon = models.ImageField(upload_to='secrets')
    secret_banner = models.ImageField(upload_to='secrets')

class UserProfile(models.Model):
    user = models.ForeignKey(User)
    secret_image = models.ImageField(upload_to='secrets')

Templates can then render those images, using (for example) the instance.secret_banner.url attribute.

When a request comes in for that same URL, I want to handle the request in a view:

# urls.py

from django.urls import path

from .views import StaticImageView

urlpatterns = [
    ...,
    path(settings.MEDIA_URL + 'secrets/<path:relpath>', StaticImageView.as_view(), name='static-image'),
]

So the StaticImageView.get method will be passed the relpath parameter parsed from the URL.

At that point I need to do more handling based on which instance made the URL for this static image.

# views.py

from django.views.generic import View

class StaticImageView(View):

    def get(self, request, relpath):
        instance = figure_out_the_model_instance_from_url_relpath(relpath)
        do_more_with(instance)

What I don't know is how to write that figure_out_the_model_instance_from_url_relpath code.

How can I use that path to find which model and which instance, generated that URL?


Solution

  • You can query and get the instance from image file or rather the file name of the image. First get the just filename of from the relpath and then query for the instance.

    A sample code example:

    class StaticImageView(View):
    
        def get(self, request, relpath):
            fname = get_filename_from_relpath(relpath)
            instance = Lorem.objects.get(secret_icon=fname)
            
            do_more_with_instance(instance)
    

    I assumed you want to get based on secret_icon image. You can change it as required.