Skip to content

Upgrade back-end code from Django 4.2 to 5.2 LTS - #8052

Open
acwhite211 wants to merge 36 commits into
mainfrom
issue-8046
Open

Upgrade back-end code from Django 4.2 to 5.2 LTS#8052
acwhite211 wants to merge 36 commits into
mainfrom
issue-8046

Conversation

@acwhite211

@acwhite211 acwhite211 commented May 1, 2026

Copy link
Copy Markdown
Collaborator

Fixes #8046

Upgrade Django from 4.2 to LTS version 5.2.

https://docs.djangoproject.com/en/6.0/releases/5.2/

Changes:

  • removed USE_L10N (A localization setting, that is now defaulted to true)
  • added new migration to fix many-to-many fields (django-generated)
  • Migrated GET request to logout to a POST request to be in HTTP (and django) spec
    • changed the logOut user tool (in Header/userToolDefinitions) to point to a new front-end endpoint: /specify/command/logout to match the cache clearing endpoint
    • this new endpoint (defined in Router/Routes.tsx) renders the Logout component
    • the Logout component makes the POST request to the backend and returns a loading screen

Checklist

  • Self-review the PR after opening it to make sure the changes look good and
    self-explanatory (or properly documented)
  • Add relevant issue to release milestone
  • Add pr to documentation list
  • Add automated tests

Testing instructions

Note for dev testers
If you are testing on your local instance, change

command: npx webpack -w --mode development --color

from --mode development to --mode production. This is because in development mode, webpack will duplicate web requests, which when sending the POST request, the first one is aborted by the second, which causes ajax to flash an error on-screen before refreshing to the login page. This does not happen in production mode, as far as I have seen.

  • Ensure strings are localized correctly
    • verify that labels are not raw schema labels, i.e. ensure schema config labels are respected.
    • Ensure that switching languages behaves correctly.
  • Log out from several locations
    • Ensure that no error dialogs flash on the screen
    • Logging back in takes you to the splash screen
  • General UI/UX testing
    • especially the workbench and attachments/attachment bulk upload

Summary by CodeRabbit

  • New Features

    • Added a dedicated logout flow with loading feedback and redirect handling.
    • Improved logout navigation from collection, agent, and user menus.
  • Bug Fixes

    • Updated relationship mappings and database migrations for more reliable data handling.
    • Improved compatibility with current Django and authentication tooling.
  • Refactor

    • Simplified URL routing across backend endpoints without changing their primary destinations.
    • Updated date/time and boolean field configuration for Django compatibility.

@coderabbitai

coderabbitai Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 8f66b69c-8a2c-4957-9c3f-e6226775d137

📥 Commits

Reviewing files that changed from the base of the PR and between 75026ea and a6f6020.

📒 Files selected for processing (4)
  • requirements-testing.txt
  • specifyweb/settings/__init__.py
  • specifyweb/specify/migrations/0046_add_indexes.py
  • specifyweb/specify/migrations/0047_alter_specifyuser_spprincipals.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • specifyweb/settings/init.py

📝 Walkthrough

Walkthrough

Changes

Django platform upgrade

Layer / File(s) Summary
Runtime and test foundation
requirements.txt, requirements-testing.txt, specifyweb/settings/__init__.py
Django, authentication, JWT, and testing dependencies are upgraded. USE_TZ is disabled and USE_L10N is removed.
URL routing modernization
specifyweb/backend/*/urls.py, specifyweb/specify/urls.py, specifyweb/backend/context/testurls.py, specifyweb/urls.py
Regex routes are replaced with path() routes. Typed converters are used for task IDs, viewset levels, and property names.
Model field compatibility migration
specifyweb/specify/utils/case_insensitive_bool.py, specifyweb/specify/migrations/*
NullBooleanField now extends the local BooleanField. A migration updates many-to-many field metadata and subsequent migration dependencies.

Frontend logout flow

Layer / File(s) Summary
Logout route and component
specifyweb/frontend/js_src/lib/components/Router/Routes.tsx, specifyweb/frontend/js_src/lib/components/Logout/index.tsx
A lazy command/logout route loads Logout. The component posts to /accounts/logout/, displays loading state, handles errors, and redirects to login.
Logout entry points
specifyweb/frontend/js_src/lib/components/ChooseCollection/index.tsx, specifyweb/frontend/js_src/lib/components/Core/Main.tsx, specifyweb/frontend/js_src/lib/components/Header/userToolDefinitions.ts
Logout links now target /specify/command/logout/. The collection action sends an explicit POST request.

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant Router
  participant Logout
  participant AccountsLogout
  participant LoginPage
  User->>Router: Open command/logout
  Router->>Logout: Lazy-load Logout
  Logout->>AccountsLogout: POST /accounts/logout/
  AccountsLogout-->>Logout: Return response
  Logout->>LoginPage: Redirect with nextUrl
Loading

Possibly related PRs

Suggested reviewers: carolinedenis, emenslin

🚥 Pre-merge checks | ✅ 4 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Automatic Tests ⚠️ Warning The PR changes 20 paths, adds a logout component and migrations, but changes no test files; focused searches found no related tests, and the checklist leaves automated tests unchecked. Add automatic tests for the POST logout flow and redirect, route registration, and migration/settings behavior, or document why each changed behavior does not require coverage.
Testing Instructions ⚠️ Warning Instructions cover logout symptoms but omit explicit checks for the new migration, USE_TZ behavior, and numerous path() API routes; “several locations” and “General UI/UX testing” are vague. Add exact logout locations and expected POST, redirect, nextUrl, cache, and localization results. Add migration/relationship, timezone/date, and representative backend URL checks with steps.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: upgrading the back-end from Django 4.2 to Django 5.2 LTS.
Linked Issues check ✅ Passed The dependency, settings, migration, URL, field, and logout changes support the Django 5.2 upgrade objective in [#8046].
Out of Scope Changes check ✅ Passed The changes are related to Django 5.2 compatibility and the linked logout-flow requirements; no unrelated code changes are evident.
✨ Finishing Touches 💡 1
⚔️ Resolve merge conflicts 💡
  • Resolve merge conflict in branch issue-8046
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue-8046

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@g1rly-c0d3r g1rly-c0d3r self-assigned this Jul 14, 2026
@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Warning

One or more dependencies are approaching or past End-of-Life.
Please plan upgrades accordingly.

STATUS=WARNING
NODE_VERSION=20
NODE_CYCLE=20
EOL_DATE=2026-04-30
DAYS_REMAINING=-89

--- Node.js ---
Version: 20
EOL: 2026-04-30
Status: WARNING

STATUS=OK
PYTHON_VERSION=3.12
PYTHON_CYCLE=3.12
EOL_DATE=2028-10-31
DAYS_REMAINING=826

--- Python ---
Version: 3.12
EOL: 2028-10-31
Status: OK

STATUS=OK
DJANGO_VERSION=5.2
DJANGO_CYCLE=5.2
EOL_DATE=2028-04-30
DAYS_REMAINING=642

--- Django ---
Version: 5.2
EOL: 2028-04-30
Status: OK


Triggered by ffecf67 on branch refs/heads/issue-8046
Comment thread specifyweb/backend/inheritance/urls.py Fixed
@g1rly-c0d3r
g1rly-c0d3r requested review from a team and removed request for a team July 22, 2026 19:27

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (1)
specifyweb/frontend/js_src/lib/components/ChooseCollection/index.tsx (1)

175-177: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Avoid posting logout twice in this flow.

The ping call performs a POST, then the redirect mounts Logout, which POSTs to /accounts/logout/ again. Let one layer own the logout request; verify whether the pre-redirect POST is still required.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@specifyweb/frontend/js_src/lib/components/ChooseCollection/index.tsx` around
lines 175 - 177, Update the logout flow around the ping call and redirect to
ensure /accounts/logout/ is POSTed only once. Determine whether Logout owns the
required logout request, then remove the redundant pre-redirect ping POST if so,
while preserving the redirect to formatUrl('/specify/command/logout/', { next:
nextUrl }).
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@requirements-testing.txt`:
- Around line 2-3: Update the mypy dependency pin in requirements-testing.txt to
a version supported by django-stubs==5.2.9, such as mypy==1.13.0; retain the
django-stubs pin and do not keep the incompatible mypy==1.5.1 combination.

In `@requirements.txt`:
- Line 14: Update the PyJWT dependency version in requirements.txt from 2.12.1
to 2.13.0 or later, ensuring the pinned version includes the PyJWKClient
scheme-validation fix.

In `@specifyweb/backend/context/testurls.py`:
- Line 12: Update the URL pattern for views.viewsets to use a string-compatible
path converter instead of <int:level>, so the level argument remains a string
when passed to testsviews.viewsets().

In `@specifyweb/frontend/js_src/lib/components/Logout/index.tsx`:
- Line 17: Update the logout redirect callback in the Logout component to read
and validate the route’s next value, preserving it when valid and falling back
to “/specify/” otherwise. Use that resolved value in the formatUrl call instead
of always passing the fixed “/specify/” target.
- Around line 16-22: Update the logout failure handler in the promise chain
around softError so a failed POST transitions away from the indefinitely
displayed LoadingScreen. Render an error/retry state or navigate to a terminal
fallback on rejection, while preserving the existing successful redirect
behavior.
- Around line 11-20: Move the logout request and its loading/redirect error
handling from the component render path into a mount-only effect, using the
component’s existing effect and loading utilities. Ensure the POST to
/accounts/logout/ starts once after mount, while preserving the current success
redirect and softError behavior.

---

Nitpick comments:
In `@specifyweb/frontend/js_src/lib/components/ChooseCollection/index.tsx`:
- Around line 175-177: Update the logout flow around the ping call and redirect
to ensure /accounts/logout/ is POSTed only once. Determine whether Logout owns
the required logout request, then remove the redundant pre-redirect ping POST if
so, while preserving the redirect to formatUrl('/specify/command/logout/', {
next: nextUrl }).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 3501db84-1148-48c2-861a-22071020f1f5

📥 Commits

Reviewing files that changed from the base of the PR and between 7c0e603 and 6a6d62d.

📒 Files selected for processing (20)
  • pytest.ini
  • requirements-testing.txt
  • requirements.txt
  • specifyweb/backend/batch_identify/urls.py
  • specifyweb/backend/context/testurls.py
  • specifyweb/backend/context/urls.py
  • specifyweb/backend/inheritance/urls.py
  • specifyweb/backend/setup_tool/urls.py
  • specifyweb/backend/trees/urls.py
  • specifyweb/frontend/js_src/lib/components/Atoms/Icons.tsx
  • specifyweb/frontend/js_src/lib/components/ChooseCollection/index.tsx
  • specifyweb/frontend/js_src/lib/components/Core/Main.tsx
  • specifyweb/frontend/js_src/lib/components/Header/userToolDefinitions.ts
  • specifyweb/frontend/js_src/lib/components/Logout/index.tsx
  • specifyweb/frontend/js_src/lib/components/Router/Routes.tsx
  • specifyweb/settings/__init__.py
  • specifyweb/specify/migrations/0045_alter_many_to_many_through_fields.py
  • specifyweb/specify/urls.py
  • specifyweb/specify/utils/case_insensitive_bool.py
  • specifyweb/urls.py
💤 Files with no reviewable changes (1)
  • specifyweb/settings/init.py

Comment thread requirements-testing.txt Outdated
Comment thread requirements.txt Outdated
Comment thread specifyweb/backend/context/testurls.py Outdated
Comment thread specifyweb/frontend/js_src/lib/components/Logout/index.tsx Outdated
Comment thread specifyweb/frontend/js_src/lib/components/Logout/index.tsx Outdated
Comment thread specifyweb/frontend/js_src/lib/components/Logout/index.tsx Outdated
@github-project-automation github-project-automation Bot moved this from 📋Back Log to Dev Attention Needed in General Tester Board Jul 22, 2026
@g1rly-c0d3r g1rly-c0d3r added this to the 7.12.1 milestone Jul 28, 2026
@g1rly-c0d3r
g1rly-c0d3r requested review from combs-a, emenslin and rijulpoudel and removed request for a team July 28, 2026 20:15

@rijulpoudel rijulpoudel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I completed the manual testing:

  • Labels are localized correctly and schema-config labels are respected
  • Switching languages works correctly
  • Logging out from several locations works without a flashing error
  • Logging back in takes me to the splash screen
  • General UI/UX testing
  • WorkBench
  • Attachments and attachment bulk upload

Everything worked as expected except that opening the Attachments panel displays two error dialogs. Both report:

'datetime.date' object has no attribute 'utcoffset'
Not sure if it's related to the upgrade. The Attachments features still worked after dismissing the dialogs.

Image Image Image

@g1rly-c0d3r

Copy link
Copy Markdown
Collaborator

@rijulpoudel I think that is outside of the scope of this PR, I think it is happening here:

'timestamp': datetime.datetime.now(datetime.UTC).isoformat()

as that is the only place we use datetime.UTC, which is not a part of django. Might be a different issue to write up.

@g1rly-c0d3r
g1rly-c0d3r requested a review from rijulpoudel July 29, 2026 15:38

@combs-a combs-a left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

  • Ensure strings are localized correctly
    • verify that labels are not raw schema labels, i.e. ensure schema config labels are respected.
    • Ensure that switching languages behaves correctly.
  • Log out from several locations
    • Ensure that no error dialogs flash on the screen
    • Logging back in takes you to the splash screen
  • General UI/UX testing
    • especially the workbench and attachments/attachment bulk upload

It's a bit difficult to tell if switching languages is behaving correctly, as several are incomplete, but from what I could see all of the expected areas were still localized.

Edited since I hadn't spotted Rijul's testing before I submitted my review--apologies! There's a lot of screenshots that can be moved over to the issue

Rijul's issue didn't exist in main from my testing. It appears that date fields having no utcoffset is causing issues saving or accessing any newly created records, since I created a record set from Workbench, and found that the timestamps were off, and that I could not open the recordset(s). This affects other new records, such as Collection Objects.

We should wait until this issue is fixed regardless of whether it's within the scope of this PR or not to check general UI/UX, as it's affecting the basic functionality.

Below are all of the screenshots of the UTC offset issues I got.

From this branch:
Image

When opening the record set(s):
Image

Specify 7 Crash Report - 2026-07-29T16_47_28.993Z.txt

From main:
Image

There are some oddities in timestamps because of this. Newly created record sets/queries appear to have a different timestamp from main. Above is an example--the two recordset created '5 hours ago' were actually created in main, recently, while the one recordset created an hour ago (ID 498) was created in the branch and appears to be accurate. On main, recordset 498 has a timestamp of 'now.'

Further evidence: from the branch, you can see that it the most recent query was created 15 minutes ago. This is accurate. On main, however, the timestamp created says 'now.'

Image Image

Database is sdnhmherps_2026_07_17 with a login of sdnhmherp for verification/testing, as well. If this gets split into another issue, I'll move all of this over.

Thank you for the work on this Eos! 🫡

@CarolineDenis CarolineDenis modified the milestones: 7.12.1, 7.12.2 Jul 30, 2026
@g1rly-c0d3r

Copy link
Copy Markdown
Collaborator

I don't think this should be a different issue actually. I combed through the Django release notes again, as well as our Django settings, saw something I missed. In 5.0, they set the default value for USE_TZ from False to True. We never specified that setting, so our code dealt with timezone info. The change to True meant that now the datetime.date object was stored in UTC, not local time. I believe changing this to False will fix the regressions that @combs-a and @rijulpoudel noticed. I will do some testing myself first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Dev Attention Needed

Development

Successfully merging this pull request may close these issues.

Upgrade Django to LTS version 5.2

7 participants