Skip to content

Using a component inside a loop will duplicate the database query (or rendering the entire page) for each element #643

@medycynka

Description

@medycynka

Hi!

While trying to use this wonderful library in our project, we encountered a performance issue. A table that contains only 80 rows renders about 12 seconds through this piece of code:

{% for obj in filtered_object_list %}
    {% unicorn 'available_projects_row' counter=forloop.counter columns_choice=columns_choice key=forloop.counter obj=obj %}
 {% endfor %}

According to django-debug-toolbar:
image
image

If instead of using the component {% unicorn ... %} we generate the table in the "classic" way using pure html, the page load time is less than a second (with around 90 database queries). What we have already tried:

  • Changing djang models to simple objects or dictionaries before page rendering
  • Disabling caching of components by overriding the methods of the UnicornView class.

Therefore, we guess that the problem may be the way individual components are rendered, but we have not been able to find the cause or solution to the problem so far.

Due to the fact that this is a project with no access to the source code, I am not able to share the full data of the data but only an illustrative one:

class AvailableProjectsRowView(UnicornView):
    template_name = 'unicorn/available_projects_row.html'
    project_versions: list = []
    project_process_statuses: dict = None
    obj: AvailableProjectPresenter = None
    counter: int = 0
    columns_choice: dict = None
    loaded_status_table: bool = False
    selected_columns: int = 0
    response_class = UnicornTemplateResponse

    def mount(self):
        self.project_versions = []
        self.project_process_statuses = {}
        self.counter = self.component_kwargs.get('counter', 1)
        self.loaded_status_table = False
        self.obj = self.component_kwargs.get('obj')
        self.columns_choice = self.component_kwargs.get('columns_choice')
        self.selected_columns = sum(column.checked or column.disabled for column in self.columns_choice.values())


...


class Project(models.Model):
    institution = models.ForeignKey(...)
    name = models.TextField(...)
    short_name = models.CharField(...)
    description = models.TextField(...)
    undertaking_type = models.CharField(...)
    sor_name = models.CharField(...)
    sor_type = models.CharField(...)
    sor_period = models.CharField(...)
    scope = models.CharField(...)
    project_type = models.CharField(...)
    category = models.CharField(...)
    signature = models.CharField(...)
    contract_no = models.CharField(...)
    current_phase = models.CharField(...)
    # more model fields, but their number did not affect performance because we also tested converting model instances to 
    # simple objects or dictionaries

...


class AvailableProjectPresenter:
    def __init__(self, project, request_user, selectable):
        self.project = project
        self.enterprise_name = project._meta.model_name
        self.request_user = request_user
        self.show_full_data = selectable
        self.is_selectable = selectable

    @property
    def name(self):
        return self.project.short_name if self.project.name else ''

    @property
    def short_name(self):
        return self.project.short_name

    @property
    def institution(self):
        return self.project.institution.abbreviation
        
    # more properties

Currently we are stuck and do not know what we can do next, and we want to integrate our project with this library because it will improve our work and provide better code clarity.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions