Skip to content
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

bug-1809726: update to django 4.2 #6538

Merged
merged 2 commits into from Mar 1, 2024
Merged

bug-1809726: update to django 4.2 #6538

merged 2 commits into from Mar 1, 2024

Conversation

willkg
Copy link
Collaborator

@willkg willkg commented Feb 29, 2024

This updates Socorro from Django 3.2 LTS to 4.2 LTS. This is a more involved update than Tecken was because Socorro uses more of Django's stuff for the web ui whereas Tecken is predominantly a react app.

This starts with updating Django which then required me to update django-pipeline. That unearthed some problems one of which was fixed by adjusting the bundle specification. The other required us to switch from one jsonview js lib which isn't maintained to another one which sort of is.

On top of that, Django deprecated a bunch of stuff that were were doing with the plan of removing those things in Django 5.0. So I ran django-upgrade and I also fixed some things by hand.

To test:

  1. run make build which builds everything and also builds the static assets
  2. run the tests
  3. run the webapp, process some crash reports, click around
    1. check report view "Raw data and minidumps" and "Telemetry Environment" tabs which use the jsonview library
    2. check the admin

@willkg willkg requested a review from a team as a code owner February 29, 2024 02:32
@willkg willkg requested a review from relud February 29, 2024 02:32
@@ -31,7 +31,7 @@ COPY --chown=app:app ./webapp/package*.json /webapp-frontend-deps/
RUN cd /webapp-frontend-deps/ && npm install

COPY --chown=app:app requirements.txt /app/
RUN pip install -U 'pip==23.3.1' && \
RUN pip install -U 'pip==24.0' && \
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I got tired of the pip warning, so I updated pip, too.

@@ -110,7 +110,7 @@ def test_base_classes_raise_not_found(self):
def test_option_CORS(self):
"""OPTIONS request for model_wrapper returns CORS headers"""
url = reverse("api:model_wrapper", args=("NoOp",))
response = self.client.options(url, HTTP_ORIGIN="http://example.com")
response = self.client.options(url, headers={"origin": "http://example.com"})
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The Django test client takes a headers argument instead of headers as kwargs. I don't know which Django version changed this--it's possible it's been this way for a while and we never updated.

@@ -38,12 +38,12 @@ class UserAdminBetter(UserAdmin):
"get_policyexception",
]

@admin.display(description="Hacker (PII)")
Copy link
Collaborator Author

@willkg willkg Feb 29, 2024

Choose a reason for hiding this comment

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

Instead of setting properties on the methods, there's a decorator that you can use to set things. We switched to that.

https://docs.djangoproject.com/en/5.0/ref/contrib/admin/#django.contrib.admin.display

"object_link",
"action",
"get_change_message",
]
list_display_links = ["action_time", "get_change_message"]

def admin(self, obj):
def admin_email(self, obj):
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

We needed to change this method name because it overrides admin in the class namespace preventing us from using admin.display() decorator.

@@ -24,9 +24,9 @@ div#message {
}
.message.warning {
background-color: @pink;
border: 1px solid @jsonview-bool;
border: 1px solid @orange;
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I got rid of jsonview-bool when I updated the CSS for the jsonview. It's weird that the messages system was using that color. It was kind of a lighter tangerine color, so I replaced it with orange.

@@ -201,7 +202,7 @@ def test_html(self):
handler500 = getattr(views, end)

# to make a mock call to the django view functions you need a request
fake_request = RequestFactory().request(**{"wsgi.input": None})
fake_request = RequestFactory().request(**{"wsgi.input": StringIO("")})
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Turns out when you pass None in as a value, something in Django internals calls .read() on it and then everything gets mad. wsgi.input should be a stream, so I replaced it with a StringIO and that seemed to work.

# No need to load it because we don't do i18n in this project
USE_I18N = False

USE_L10N = False
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

These are deprecated. I think that means Django always has localization enabled. We don't use that in Crash Stats, so I think this is probably fine and if not, someone will tell us and we can figure out what to do then.

@@ -470,6 +465,12 @@ def filter(self, record):
DATABASES = {"default": dj_database_url.parse(DATABASE_URL)}


STORAGES = {
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This used to be STATICFILES_STORAGE and is now just STORAGES with a different structure.

https://docs.djangoproject.com/en/5.0/releases/4.2/#custom-file-storages

@@ -34,12 +34,15 @@
"@fortawesome/fontawesome-free": ["css/all.min.css", "webfonts/*"],
"tablesorter": ["dist/css/theme.default.min.css", "dist/js/jquery.tablesorter.js"],
"d3": ["dist/*"],
"jssha": ["dist/*.js"],
"jssha": ["dist/*.js", "dist/*.map"],
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The .js file has an indicator to the .map file and something uses that now (I have no idea what), so we need to copy over the .map file now.

"jquery.json-viewer": [
"json-viewer/jquery.json-viewer.css",
"json-viewer/jquery.json-viewer.js",
],
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

jquery-jsonview has a file that indicates there's a .map file just like jssha did, but there is no .map file in the package. The library hasn't been touched in 8 years. So I switched us to jquery.json-viewer which has some minor differences, but it's been updated more recently and doesn't have the .map problem.

@@ -206,7 +206,7 @@ class IsoDateTimeField(forms.DateTimeField):
def to_python(self, value):
if value:
try:
return parse_isodate(value).replace(tzinfo=utc)
return parse_isodate(value).replace(tzinfo=datetime.timezone.utc)
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

django.utils.timezone.utc is deprecated in Django 4.1 in favor of datetime.timezone.utc which it was an alias for since Django 4.0.

http://docs.djangoproject.com/en/5.0/releases/4.1/

@@ -115,7 +115,7 @@ <h2>Generate a New Token</h2>
<form method="post">
{% csrf_token %}
<table class="data-table">
{{ form }}
{{ form.as_table() }}
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Django project created a new div form renderer that's accessibility friendly which the table form renderer is not. Calling {{ form }} will change what it's doing from the table form renderer it does now to the div form renderer. So we call form.as_table() here because I didn't want to spend time on redoing the API token form using the div form renderer and hunt for other forms that need to be similarly updated.

I'll write up a bug to cover that work.

http://docs.djangoproject.com/en/5.0/releases/4.1/

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This updates Django to 4.2. In order to do that, we also had to update
django-pipeline to 3.0.0 so it worked correctly. But then that caused
problems when building static files. I managed to fix the jssha error,
but couldn't fix the jquery.jsonview one.

jquery.jsonview is unmaintained and hasn't had a version release in 8
years and the example urls redirect to terrible places. I switched Crash
Stats to use jquery.json-viewer which required some minor js and css
changes, but generally works the same.
This fixes a bunch of DeprecationWarnings introduced with Django 4.1 and
4.2 for things that are going away in Django 5.0.

* change in how forms are rendered -- I picked `as_table()` for now
  since that's what it used to do; we want to switch to the new
  accessible-friendly form rendering--I'll write up a bug to do that
* deprecating django.utils.timezone.utc -- these are all switched to
  datetime.timezone.utc
* pass in headers as headers dict to test client
* switch setting admin method properties to use a decorator

This also fixes a new bug where RequestFactory `wsgi.input` value needs
a `read()` method.
@willkg willkg force-pushed the willkg-bug-1809726-django42 branch from e9cecf8 to 7869d5d Compare March 1, 2024 14:02
@willkg willkg merged commit c99dc11 into main Mar 1, 2024
1 check passed
@willkg
Copy link
Collaborator Author

willkg commented Mar 1, 2024

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants