How to make and use custom template-loader in Django

Viewed 423

I am trying to write a custom template loader in django which serves html templates which are present in a folder in my s3 bucket. Following is my custom_loader file

from django.conf import settings
from django.template import Origin, Engine
from django.template.loader import TemplateDoesNotExist
from django.template.loaders.base import Loader
from boto3.session import Session
from django.template import engines

ACCESS_KEY_NAME = getattr(settings, 'AWS_ACCESS_KEY_ID', getattr(settings, 'AWS_ACCESS_KEY_ID', None))
SECRET_KEY_NAME = getattr(settings, 'AWS_SECRET_ACCESS_KEY', getattr(settings, 'AWS_SECRET_ACCESS_KEY', None))
TEMPLATE_BUCKET = getattr(settings, 'AWS_STORAGE_BUCKET_NAME')

django_engine = engines['django']
template = django_engine.from_string("Hello {{ name }}!")


class S3Engine(Engine):

    def __unicode__(self):
        return "s3_engine"

    def __str__(self):
        return "s3_engine"


class Loader(Loader):
    is_usable = True

    def __unicode__(self):
        return "loader"

    def __init__(self, *args, **kwargs):
        django_engine = engines['django']
        print(engines.all())
        template = django_engine.from_string("Hello {{ name }}!")
        print(template)
        params = args[0]
        print(args)
        print('params', params)
        session = Session(aws_access_key_id=ACCESS_KEY_NAME,
                          aws_secret_access_key=SECRET_KEY_NAME)
        s3 = session.resource('s3')
        self.bucket = s3.Bucket(TEMPLATE_BUCKET)
        super(Loader, self).__init__(*args, **kwargs)
        # self.engine = S3Engine(dirs=params['DIRS'], context_processors=options, loaders=Loader)


    def getKeys(self):
        keys_objects = []
        for obj in self.bucket.objects.filter(Prefix="media/festive_html/"):
            key = obj.key
            keys_objects.append({
                'key': key,
                'object': obj
            })
        return keys_objects

    def get_contents(self, origin):
        print(111111)
        print('origin', origin)
        try:
            keys_objects = self.getKeys()
            for key_object in keys_objects:
                print('origin', origin)
                print('key_object', key_object)
                if key_object['key'] == origin:
                    return key_object['object'].get()['Body'].read()
        except FileNotFoundError:
            raise TemplateDoesNotExist(origin)


    def get_template_sources(self, template_name, template_dirs=None):
        tried = []
        # print('template_name', template_name)
        # template_name = "media/" + template_name
        print(11111)
        yield Origin(
            name=template_name,
            template_name=template_name,
            loader=self,
        )
        print(333333)
        tried.append('/index.html')
        print(444444)
        if tried:
            print(555555555)
            error_msg = "Tried Keys %s" % tried
        else:
            print(6666666)
            error_msg = "Your TEMPLATE_DIRS setting is empty. Change it to point to at least one template directory."
        raise TemplateDoesNotExist(error_msg)

    get_template_sources.is_usable = True

and in my settings i have set the template settings in following way.

TEMPLATES = [
    {
        'NAME': 'django',
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates'), os.path.join(BASE_DIR, 'media')],
        'APP_DIRS': False,
        'OPTIONS': {
            'loaders': [
                'django.template.loaders.filesystem.Loader',
                'django.template.loaders.app_directories.Loader',
                's3template_loader.Loader',
            ],
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

and following is my view

def generate_html(request, template_id)
    template_instance = TemplateData.objects.get(id=template_id) 
    html = template_instance.html
    rendered = render_to_string(html, response)
    return rendered

but when i am trying to access my end point i am getting the below error:

TypeError: 'Engine' object has no attribute '__getitem__'

PS: This question is similar to the below question with the difference that I don't want to use a different template Engine but just a different template loader that renders templates from s3.

custom template loader Django

0 Answers
Related