django-tenants / django-tenants

Django tenants using PostgreSQL Schemas
MIT License
1.53k stars 344 forks source link

Tenant-aware file system is not working as expected when files stored in public tenant is trying to be accessed in any private tenant #1022

Open JayDarjiAubergine opened 10 months ago

JayDarjiAubergine commented 10 months ago

We have this kind of use case where Default public tenant Django database models are accessible for other tenant schemas.

By using Configuring Tenant Aware media file storage in Django Tenant

DEFAULT_FILE_STORAGE = "django_tenants.files.storage.TenantFileSystemStorage"

Let's take an example, when we upload a media file in a public tenant database model with tenant-aware file handling, it can be accessible in the public schema with a very nice path just like:

localhost/media/public/user/user_1.jpg

Where public is tenant aware file system handling folder name for the public schema. This URL works well to access the image from the public tenant only.

In this approach, the DB field will save the image path like this: user/user_1.jpg -> Mark that tenant name public is NOT being stored in the DB field.

But now, when we want to access the same image from some ABC tenant schema, then it is changing the image URL to

ABC.localhost/media/ABC/user/user_1.jpg

where public is replaced by ABC, which makes sense as we changed the tenant, but the image is not accessible now as the path is wrong.

Is there any good way to perform this kind of scenario properly?


For now, we are doing a workaround of explicitly using the django_tenants.utils.parse_tenant_config_path function in Django models ImageField's upload_to field like this

image = models.ImageField(upload_to=f"{parse_tenant_config_path('%s')}/user/{filename}")

what this will do is, it'll save the tenant name in the database table field itself, In this approach, the DB field will save the image path like this: `

public/user/user_1.jpg` -> Mark that tenant name is being stored in DB field here unlike above situation

so whenever we try to access this file from any tenant, it'll return the correct path as now it'll not use django_tenants.files.storage.TenantFileSystemStorage as File Storage, rather it'll use Django's default file system class django.core.files.storage.FileSystemStorage.

Is this the efficient way for django-tenant?


Also, for production implementation, we are following same but replaced django.core.files.storage.FileSystemStorage with storages.backends.s3.S3Storage which also uses same solution for tenant specific media file handling.

However I couldn't find any documentation that support S3 implementation with django-tenant! Can anyone also helps with that!

Related issues:

miyou995 commented 10 months ago

I had the same problem today and didn't find the time to go deep in the problem but used this small hack to make things work till finding a better solution. custom template tag

from django import template

register = template.Library()

@register.simple_tag(name='format_public_image', takes_context=True)
def format_public_image(context, image_url):
    request = context['request']
    public_url = image_url.replace(str(request.tenant), 'public')
    return public_url 

if someone knows where the problem is or has a better solution, he is welcome to help