Skip to content

Commit 4e378db

Browse files
authored
Merge pull request #8934 from readthedocs/humitos/django3-json-fields
2 parents 9bdffa3 + 9842783 commit 4e378db

File tree

8 files changed

+92
-43
lines changed

8 files changed

+92
-43
lines changed

readthedocs/api/v2/views/integrations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ def handle_webhook(self):
431431
(created or deleted),
432432
]):
433433
integration = self.get_integration()
434-
events = integration.provider_data.get('events', [])
434+
events = integration.provider_data.get('events', []) if integration.provider_data else [] # noqa
435435
if any([
436436
GITHUB_CREATE in events,
437437
GITHUB_DELETE in events,
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Generated by Django 3.2.11 on 2022-01-31 12:12
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('builds', '0039_migrate_config_data'),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name='build',
15+
name='_config',
16+
),
17+
migrations.RenameField(
18+
model_name='build',
19+
old_name='_config_json',
20+
new_name='_config',
21+
),
22+
]

readthedocs/builds/models.py

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
ModificationDateTimeField,
2020
)
2121
from django_extensions.db.models import TimeStampedModel
22-
from jsonfield import JSONField
2322
from polymorphic.models import PolymorphicModel
2423

2524
import readthedocs.builds.automation_actions as actions
@@ -662,8 +661,7 @@ class Build(models.Model):
662661
null=True,
663662
blank=True,
664663
)
665-
_config = JSONField(_('Configuration used in the build'), default=dict)
666-
_config_json = models.JSONField(
664+
_config = models.JSONField(
667665
_('Configuration used in the build'),
668666
null=True,
669667
blank=True,
@@ -740,7 +738,7 @@ def config(self):
740738
# probably change this field to be a ForeignKey to avoid repeating the
741739
# config file over and over again and re-use them to save db data as
742740
# well
743-
if self.CONFIG_KEY in self._config:
741+
if self._config and self.CONFIG_KEY in self._config:
744742
return (
745743
Build.objects
746744
.only('_config')
@@ -784,10 +782,6 @@ def save(self, *args, **kwargs): # noqa
784782
self.version_slug = self.version.slug
785783
self.version_type = self.version.type
786784

787-
# TODO: delete copying config after deploy
788-
# Copy `_config` into the new `_config_json` JSONField
789-
self._config_json = self._config
790-
791785
super().save(*args, **kwargs)
792786
self._config_changed = False
793787

@@ -957,7 +951,9 @@ def external_version_name(self):
957951
return None
958952

959953
def using_latest_config(self):
960-
return int(self.config.get('version', '1')) == LATEST_CONFIGURATION_VERSION
954+
if self.config:
955+
return int(self.config.get('version', '1')) == LATEST_CONFIGURATION_VERSION
956+
return False
961957

962958
def reset(self):
963959
"""

readthedocs/builds/tasks.py

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -115,14 +115,17 @@ def route_for_task(self, task, args, kwargs, **__):
115115
last_builds = version.builds.order_by('-date')[:self.N_LAST_BUILDS]
116116
# Version has used conda in previous builds
117117
for build in last_builds.iterator():
118-
build_tools_python = (
119-
build.config
120-
.get('build', {})
121-
.get('tools', {})
122-
.get('python', {})
123-
.get('version', '')
124-
)
125-
conda = build.config.get('conda', None)
118+
build_tools_python = ''
119+
conda = None
120+
if build.config:
121+
build_tools_python = (
122+
build.config
123+
.get('build', {})
124+
.get('tools', {})
125+
.get('python', {})
126+
.get('version', '')
127+
)
128+
conda = build.config.get('conda', None)
126129

127130
uses_conda = any([
128131
conda,
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Generated by Django 3.2.11 on 2022-01-31 12:12
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('integrations', '0009_migrate_headers_data'),
10+
]
11+
12+
operations = [
13+
migrations.RemoveField(
14+
model_name='httpexchange',
15+
name='request_headers',
16+
),
17+
migrations.RemoveField(
18+
model_name='httpexchange',
19+
name='response_headers',
20+
),
21+
migrations.RemoveField(
22+
model_name='integration',
23+
name='provider_data',
24+
),
25+
migrations.RenameField(
26+
model_name='httpexchange',
27+
old_name='request_headers_json',
28+
new_name='request_headers',
29+
),
30+
migrations.RenameField(
31+
model_name='httpexchange',
32+
old_name='response_headers_json',
33+
new_name='response_headers',
34+
),
35+
migrations.RenameField(
36+
model_name='integration',
37+
old_name='provider_data_json',
38+
new_name='provider_data',
39+
),
40+
]

readthedocs/integrations/models.py

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
from django.db import models, transaction
1313
from django.utils.safestring import mark_safe
1414
from django.utils.translation import gettext_lazy as _
15-
from jsonfield import JSONField
1615
from pygments import highlight
1716
from pygments.formatters import HtmlFormatter
1817
from pygments.lexers import JsonLexer
@@ -102,12 +101,15 @@ def from_requests_exchange(self, response, related_object):
102101
:param related_object: Object to use for generic relationship.
103102
"""
104103
request = response.request
104+
# NOTE: we need to cast ``request.headers`` and ``response.headers``
105+
# because it's a ``requests.structures.CaseInsensitiveDict`` which is
106+
# not JSON serializable.
105107
obj = self.create(
106108
related_object=related_object,
107-
request_headers=request.headers or {},
109+
request_headers=dict(request.headers) or {},
108110
request_body=request.body or '',
109111
status_code=response.status_code,
110-
response_headers=response.headers,
112+
response_headers=dict(response.headers),
111113
response_body=response.text,
112114
)
113115
self.delete_limit(related_object)
@@ -144,17 +146,15 @@ class HttpExchange(models.Model):
144146

145147
date = models.DateTimeField(_('Date'), auto_now_add=True)
146148

147-
request_headers = JSONField(_('Request headers'))
148-
request_headers_json = models.JSONField(
149+
request_headers = models.JSONField(
149150
_('Request headers'),
150151
# Delete after deploy
151152
null=True,
152153
blank=True,
153154
)
154155
request_body = models.TextField(_('Request body'))
155156

156-
response_headers = JSONField(_('Request headers'))
157-
response_headers_json = models.JSONField(
157+
response_headers = models.JSONField(
158158
_('Request headers'),
159159
# Delete after deploy
160160
null=True,
@@ -175,15 +175,6 @@ class Meta:
175175
def __str__(self):
176176
return _('Exchange {0}').format(self.pk)
177177

178-
# TODO: delete .save method after deploy
179-
# Copy headers into new JSONField
180-
def save(self, *args, **kwargs):
181-
# NOTE: cast headers into a regular dict because Django does not know
182-
# how to serialize ``requests.structures.CaseInsensitiveDict``
183-
self.request_headers_json = dict(self.request_headers)
184-
self.response_headers_json = dict(self.response_headers)
185-
super().save(*args, **kwargs)
186-
187178
@property
188179
def failed(self):
189180
# Assume anything that isn't 2xx level status code is an error
@@ -298,8 +289,7 @@ class Integration(models.Model):
298289
max_length=32,
299290
choices=INTEGRATIONS,
300291
)
301-
provider_data = JSONField(_('Provider data'), default=dict)
302-
provider_data_json = models.JSONField(
292+
provider_data = models.JSONField(
303293
_('Provider data'),
304294
null=True,
305295
blank=True,
@@ -329,12 +319,6 @@ def remove_secret(self):
329319
self.secret = None
330320
self.save(update_fields=['secret'])
331321

332-
# TODO: delete .save method after deploy
333-
# Copy `provider_data` into new JSONField
334-
def save(self, *args, **kwargs):
335-
self.provider_data_json = self.provider_data
336-
super().save(*args, **kwargs)
337-
338322
def __str__(self):
339323
return (
340324
_('{0} for {1}')

readthedocs/rtd_tests/tests/test_api.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ def test_make_build(self):
8989
self.assertEqual(resp.status_code, status.HTTP_201_CREATED)
9090
build = resp.data
9191
self.assertEqual(build['state_display'], 'Cloning')
92-
self.assertEqual(build['config'], {})
92+
self.assertIsNone(build['config'])
9393

9494
resp = client.get('/api/v2/build/%s/' % build['id'])
9595
self.assertEqual(resp.status_code, 200)

requirements/pip.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ drf-flex-fields==0.9.7
2121
drf-extensions==0.7.1
2222

2323
django-vanilla-views==3.0.0
24+
25+
# This module is only used on migrations. We are now using Django's official
26+
# JSONField. We should probably squash these migrations and remove this
27+
# dependency as well.
2428
jsonfield==3.1.0
2529

2630
requests==2.27.1

0 commit comments

Comments
 (0)