Skip to content

[change] Reduce sortedm2m queries for templates #204 #1010

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

DragnEmperor
Copy link
Member

@DragnEmperor DragnEmperor commented Apr 23, 2025

Checklist

  • I have read the OpenWISP Contributing Guidelines.
  • I have manually tested the changes proposed in this pull request.
  • I have written new test cases for new code and/or updated existing tests for changes to existing code.
  • I have updated the documentation.

Reference to Existing Issue

Closes #204
Closes #1050

Description of Changes

To remove queries generated by sortedm2m, 'formfield_for_manytomany' is overridden such that on page load, we can get templates using 'get_relevant_templates'.
Added device/group id in 'get_relevant_templates' to identify selected templates. Changes are made in 'relevantTemplates.js' to ensure templates are viewed and changes are saved as per initial behavior.

As now we are fetching templates via js only, I have done some modifications for the failing test cases.

  • for test case test_device_templates_m2m_queryset there is a similar selenium test case test_multiple_organization_templates
  • for test cases test_configuration_templates_removed , test_vpn_clients_deleted, have added new selenium test cases test_add_remove_templates, test_vpn_clients_deleted.

@DragnEmperor
Copy link
Member Author

DragnEmperor commented Apr 23, 2025

Known Issues:

  • Ordering is not maintained (done)

@devkapilbansal
Copy link
Member

Hi @DragnEmperor
I see that the tests are failing. You can keep a PR in draft state unless it is completed

@DragnEmperor DragnEmperor marked this pull request as draft May 6, 2025 02:31
@codesankalp codesankalp self-requested a review May 10, 2025 04:54
@DragnEmperor DragnEmperor force-pushed the issues/204-sortedm2m-queries branch from d29a35b to 9088448 Compare May 10, 2025 13:07
@coveralls
Copy link

coveralls commented May 11, 2025

Coverage Status

coverage: 98.777% (-0.04%) from 98.816%
when pulling ccdf7ea on DragnEmperor:issues/204-sortedm2m-queries
into 85eee35 on openwisp:master.

@DragnEmperor DragnEmperor marked this pull request as ready for review May 11, 2025 12:37
@DragnEmperor
Copy link
Member Author

As now we are fetching templates via js only, I have done some modifications for the failing test cases.

  • for test case test_device_templates_m2m_queryset there is a similar selenium test case test_multiple_organization_templates
  • for test cases test_configuration_templates_removed , test_vpn_clients_deleted, have added new selenium test cases test_add_remove_templates, test_vpn_clients_deleted.

@devkapilbansal devkapilbansal self-requested a review May 16, 2025 17:22
@@ -479,15 +479,6 @@ def test_device_organization_fk_autocomplete_view(self):
hidden=[data['org2'].name, data['inactive'].name],
)

def test_device_templates_m2m_queryset(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please mention in description why these tests are removed from here

Copy link
Member Author

@DragnEmperor DragnEmperor May 16, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi Kapil,
I have added in the commit description and in the comment above the reason for removing these test cases.

@devkapilbansal devkapilbansal self-requested a review May 16, 2025 17:26
Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you asserting the number of queries to verify the optimizations? Or what are you doing to ensure that the optimization is effective within automated tests?

@@ -1626,89 +1567,6 @@ def test_add_vpn(self):
response, 'value="openwisp_controller.vpn_backends.OpenVpn" selected'
)

def test_vpn_clients_deleted(self):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are these tests being moved?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we are adding the templates via js so i migrated these tests to selenium tests. I have added this in conversation above. I will update the description of PR itself for more clarity.

@DragnEmperor
Copy link
Member Author

DragnEmperor commented May 17, 2025

Are you asserting the number of queries to verify the optimizations? Or what are you doing to ensure that the optimization is effective within automated tests?

Yes I have checked the queries and while there is an improvement its not much i think ( around 4-5 queries less now, some queries' results are cached so i am not exactly sure of the count)
I have not added the tests for asserting number of queries. That would be something I need to work on, Thanks!

@DragnEmperor DragnEmperor force-pushed the issues/204-sortedm2m-queries branch from c98b148 to 4f85589 Compare May 20, 2025 18:49
@DragnEmperor
Copy link
Member Author

DragnEmperor commented May 20, 2025

@nemesifier @pandafy
Upon inspection of the queries executed, the following query was being duplicated twice leading to total count of 26.

SELECT "config_template"."id", "config_template"."created", "config_template"."modified", "config_template"."name", "config_template"."backend", "config_template"."config", "config_template"."organization_id", "config_template"."vpn_id", "config_template"."type", "config_template"."default", "config_template"."required", "config_template"."auto_cert", "config_template"."default_values" FROM "config_template" ORDER BY "config_template"."name" ASC

With the changes, templates are being added via js using get_relevant_templates so this query is not executed, bringing the count to 24.

Comment on lines 2123 to 2135
# ensuring queries are consistent for different number of templates
def test_templates_fetch_queries_1(self):
config = self._create_config(organization=self._get_org())
self._verify_template_queries(config, 1)

def test_templates_fetch_queries_5(self):
config = self._create_config(organization=self._get_org())
self._verify_template_queries(config, 1)

def test_templates_fetch_queries_10(self):
config = self._create_config(organization=self._get_org())
self._verify_template_queries(config, 1)

Copy link
Member

@pandafy pandafy May 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DragnEmperor can you help me understand why do we need three tests?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have added these checks to ensure that queries are not changed and remain the same irrespective of number of templates

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The count argument is 1 in all the tests. Is that correct?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes that was my mistake, these should be correct in new commit.

Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please merge with the latest master and run openwisp-qa-format again.
I see some changes from other PRs that have already been merged which are showing up again here, I hope that updating on master and running openwisp-qa-format fixes that, if not please look into resolving it as it makes reviewing tougher with no added benefits.

Copy link
Member

@nemesifier nemesifier left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's one failing test: test_multiple_organization_templates.

@DragnEmperor thank you for your effort! You can leave this to us now and focus on the other work you have.

nemesifier
nemesifier previously approved these changes May 29, 2025
.only("templates")
.get(pk=config_id)
.templates.filter(org_filters)
.filter(**filter_options)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I spotted something that is worrying me: we aren't enforcing/asserting that this config is really assigned to a device which is related to organization_id. In theory it would be possible to call an organization_id which is valid and a config_id which shouldn't be allowed.

So I think filter options should include device__organization_id=organization_id, what do you think?

Watch out from query count increase due to this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider the following scenario:

There are two organizations: OrgA and OrgB. OrgA has a device that is linked to a configuration object.

A user attempts to change the organization of this device from OrgA to OrgB. At this point, the organization_id URL keyword argument contains the UUID of OrgB. However, since the change hasn't been saved yet, the device object in the database is still associated with OrgA.

If we filter the Config queryset using OrgB (based on your suggestion), it will raise a Config.DoesNotExist error, because the configuration is still linked to OrgA. As a result, we won’t be able to retrieve information about the current state of shared configuration templates.

.only("templates")
.get(pk=group_id)
.templates.filter(org_filters)
.filter(**filter_options)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What's the value of filter_options here? Can we add organization_id=organization_id here?

@github-project-automation github-project-automation bot moved this from To do (general) to In progress in OpenWISP Contributor's Board May 29, 2025
if (isDeviceGroup() && !$(".add-form").length) {
// Get the group id from the URL
// TODO: This is fragile, consider using a more robust way to get the group id.
var pathParts = window.location.pathname.split("/");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are overriding /templates/admin/device_group/change_form.html, so why don't we add the group ID there as an HTML element which is easy to retrieve here?

window._deviceGroup = true;
window._deviceGroupId = "{{ original.pk }}";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We were already setting the _devieGroup property here to determine whether the relevant_template,js script was loading from device page or device group page. I have updated the logic to pass the device group ID to the JS.

@nemesifier if you prefer an HTML element, I would update the code accordingly.

DragnEmperor and others added 12 commits June 9, 2025 15:37
To remove queries generated by sortedm2m, 'formfield_for_manytomany'
is overriden such that on page loads, we can get templates using
'get_relevant_templates'. Added device/group id to identify selected
templates. Changes are made in JS to ensure templates are viewed and
changes are saved as per initial behaviour.
Ordering is not maintained.

Closes openwisp#204

Signed-off-by: DragnEmperor <[email protected]>
Using the 'sort_value' of the 'through_model', created a subquery
which annotates a sort_value and selected field to each template.
The sort_value is used for ordering the templates and also for
checking if template is selected or not using a large default value
which  happens if template is not selected for a device config or
group.

Signed-off-by: DragnEmperor <[email protected]>
As now templates are being loaded via js, normal tests
were failing. For these failing tests, added relevant
selenium tests.
Modified `get-relevant_templates` to
allow fetching templates during device creation by
superuser and org users.

Signed-off-by: DragnEmperor <[email protected]>
Added a test to assert the queries executed during templates
fetch on device change page. Previous count of this fetch
combined with `get_relevant_templates` was 26 due to
template fetch query being duplicated. With new changes
the count is down to 24.

Signed-off-by: DragnEmperor <[email protected]>
The queries for fetching the templates with sorted
in `get_relevant_templates` via Subquery, while
were working, were a bit complex to understand
for future.
Fetching templates using config/devicegroup
maintains sorting, making the fetching query
much readable.

Signed-off-by: DragnEmperor <[email protected]>
Formatted the changes as per the new QA checks
and rules in `openwisp-qa-format`. For the tests
inside  `test_views` to work properly, made minor
modifications in `get_relevant_templates`.
Also fixed the type in template count in
`test_templates_fetch_queries`.

Signed-off-by: DragnEmperor <[email protected]>
@pandafy pandafy force-pushed the issues/204-sortedm2m-queries branch 2 times, most recently from c082f0e to b00bcc8 Compare June 9, 2025 12:58
@pandafy pandafy force-pushed the issues/204-sortedm2m-queries branch from b00bcc8 to b4d0b93 Compare June 9, 2025 13:06
@pandafy pandafy force-pushed the issues/204-sortedm2m-queries branch from 43899e1 to ccdf7ea Compare June 12, 2025 08:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: In progress
Development

Successfully merging this pull request may close these issues.

[change] Change relevant templates logic to facilitate changing organization [change] Optimize queries of sortedm2m
5 participants