openwisp / openwisp/openwisp-users

[feature] Emit a signal when an object changes organization

Open
#559 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
Python
Stars
179
Forks
96
Avg merge
13h 40m
Merged PRs (30d)
16

Description

⚠️ not suited to first time contributors (PRs will be closed without explanation!).

Is your feature request related to a problem? Please describe.

Organization-owned models currently have no shared, public lifecycle hook for reacting to a change to their organization field. Integrations must implement their own change detection and cannot consistently receive both the previous and new organization in the same transaction.

This is needed by related Controller work: #1050, #1334, and #1459. Reviewing #1378 also showed that different objects need different organization-change rules. Some objects must reject organization changes. Others need to update their related records when the organization changes. A shared signal is needed for the second case.

Describe the solution you would like

Add an organization_changed signal to openwisp_users.signals, emitted by OrgMixin and inherited by ShareableOrgMixin.

When an object is loaded from the database, OrgMixin.from_db() should store its original organization ID in _initial_organization_id. OrgMixin.refresh_from_db() should update the snapshot when the organization field is refreshed. This lets clean() and save() detect organization changes without extra database queries.

The signal should emit only for existing objects whose persisted organization_id actually changed. It should use the concrete model as sender and provide instance, old_organization_id, and organization_id. It must respect update_fields, including relation names and attnames, and support deferred fields and swappable models.

After a successful save(), when the values differ, emit the signal synchronously inside the current transaction, then update _initial_organization_id. Do not use transaction.on_commit(): receivers must be able to update related records in the same transaction.

Describe alternatives you have considered

Application-specific pre-save and post-save receivers duplicate organization-change detection and cannot provide a consistent public integration point. Querying the database from clean() adds unnecessary queries. Deferring the signal to transaction.on_commit() is unsuitable for receivers which must reconcile related state atomically.

Additional context

A related follow-up will define a reusable way for models which must not change organization to reject that change during clean(). The same _initial_organization_id snapshot should support both behaviors.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in openwisp_users.signals and inspect OrgMixin.from_db(), refresh_from_db(), clean(), and save(), including how ShareableOrgMixin inherits the behavior. Review the linked Controller issues and pull request for differing organization-change rules; done means the signal handles snapshots, deferred and swappable models, update_fields, and synchronous emission only after a persisted change.

Written by the indexing model from the issue text.

Assessment

Tech stack
django, python
Domain
backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.