Piero Marini Piero Marini - 2 months ago 11
Python Question

How to apply read/write permissions to user-uploaded files in Django

I have a "document" model, an upload system using dropzone.js and the register/login. Im now lost on how to apply permissions to each individual uploaded File so only the specified users can access them.

Basically:
File1->accessible_by = user1,user2

File2->accesible_by=user3,user5...

And so on.

Thanks to anyone for advice/help on my problem.

Edit with relevant code:



Create Document View:



class DocumentCreate(CreateView):
model = Document
fields = ['file', 'is_public']

def form_valid(self, form):
self.object = form.save()
data = {'status': 'success'}
response = JSONResponse(data, mimetype =
response_mimetype(self.request))
return response


I did the above to the view to handle dropzone.js file uploading.

This is my "document" model



class Document(models.Model):

file = models.FileField(upload_to = 'files/')
#validators=[validate_file_type])
uploaded_at = models.DateTimeField(auto_now_add = True)
extension = models.CharField(max_length = 30, blank = True)
thumbnail = models.ImageField(blank = True, null = True)
is_public = models.BooleanField(default = False)

uploaded_by = models.ForeignKey(User,
related_name='uploadedByAsUser', null=True)

allowed_users = models.ManyToManyField(User,
related_name='allowedUsersAsUser')

def clean(self):
self.file.seek(0)
self.extension = self.file.name.split('/')[-1].split('.')[-1]
if self.extension == 'xlsx' or self.extension == 'xls':
self.thumbnail = 'xlsx.png'
elif self.extension == 'pptx' or self.extension == 'ppt':
self.thumbnail = 'pptx.png'
elif self.extension == 'docx' or self.extension == 'doc':
self.thumbnail = 'docx.png'


def delete(self, *args, **kwargs):
#delete file from /media/files
self.file.delete(save = False)
#call parent delete method.
super().delete(*args, **kwargs)

#Redirect to file list page.
def get_absolute_url(self):
return reverse('dashby-files:files')

def __str__(self):
return self.file.name.split('/')[-1]

class Meta():
ordering = ['-uploaded_at']

Answer

You can add an allowed_user field into the document model, so that only those users specified can access the files. for example:

class Document(models.Model):
    file = FileField()
    uploaded_by = models.ForeignKey(User, related_name='uploadedByAsUser')
    allowed_users = models.ManyToManyField(User, related_name='allowedUsersAsUser')

This way, if you want a user to be added to the "allowed" list, you can just add them using something like this:

class DocumentCreate(CreateView):
    model = Document
    fields = ['file', 'is_public']

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.allowed_users.add(request.user)
        self.object.save()
        data = {'status': 'success'}
        response = JSONResponse(data, mimetype =
        response_mimetype(self.request))
        return response

Then to make the Admin look nice (admin.py):

class DocumentAdmin(admin.ModelAdmin):
    list_display = ('uploaded_by', 'file')

    fields = ('id', 'file', 'uploaded_at', 'extension', 'thumbnail', 'is_public', 'uploaded_by', 'allowed_users')
    filter_horizontal = ('allowed_users',)

    readonly_fields = ('id',)

admin.site.register(Document, DocumentAdmin)

Then if you want to check if they're allowed, you can do:

if allowed_user in doc.allowed_users:
    print('We have liftoff')