karlosss karlosss - 3 months ago 8
Python Question

Django - get file from db by its url

I am trying to implement a secure access to files. This is my view serving static files:

class ServeStatic(LoginRequiredMixin, View):
login_url = reverse_lazy("login")

def dispatch(self, request, *args, **kwargs):
if request.user == Document.objects.get(url=self.kwargs["path"]).owner:
return serve(request, kwargs["path"], kwargs["file_root"])
else:
return HttpResponseNotFound()


The point is that I cannot get the condition to work. Is it even possible to get a file by its URL, or I need to choose a very different approach of serving files?

My Document model:

class Document(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL,
verbose_name=_("Owner"), related_name="owner")
document = models.FileField(upload_to=file_upload_handler, verbose_name=_("Document"))


Thanks for your ideas!

Answer

First of all I will pass to dispatch cleaned data (after validation). I'm not saying you're not doing that. Next thing, I wouldn't use the same part of file path which locates files on your machine as it is in url. If you're using Document model, so you can change url to something which doesn't tell anything about document. Let's say even uuid:

import uuid
print uuid.uuid4().get_hex() # python 2.7
print (uuid.uuid4().hex)     # python 3.x

according to uuid sent in url I will search proper document in my database:

 class Document(models.Model):
     owner = models.ForeignKey(settings.AUTH_USER_MODEL,
                               verbose_name=_("Owner"), related_name="owner")
     uid = models.CharField(max_length=32, null=False)
     document = models.FileField(upload_to=file_upload_handler, verbose_name=_("Document"))

You can then query using:

class ServeStatic(LoginRequiredMixin, View):
    login_url = reverse_lazy("login")

    def dispatch(self, request, *args, **kwargs):
        doc = Document.objects.get(uid=self.kwargs["uid"],
                                   owner=request.user):
            return serve(request, doc.document, kwargs["file_root"])
        else:
            return HttpResponseNotFound()

Hope that helps.

Comments