This reduces a lot of the tech debt we had built up around this. This
field is populated from a slugified representation of State.name and has
a uniqueness constraint. As a result, we also need to a uniqueness
constraint to the State.name field. This shouldn't be an issue and
probably should have been used from day one.
Note that there is no REST API impact for this since we've been using
state slugs all along.
Signed-off-by: Stephen Finucane
---
patchwork/api/event.py | 6 +--
patchwork/api/patch.py | 18 ++-
patchwork/fixtures/default_states.xml | 10
patchwork/migrations/0038_state_slug.py | 68 +
patchwork/models.py | 8 ++-
patchwork/tests/api/test_patch.py | 4 +-
patchwork/tests/utils.py| 1 +
7 files changed, 92 insertions(+), 23 deletions(-)
create mode 100644 patchwork/migrations/0038_state_slug.py
diff --git a/patchwork/api/event.py b/patchwork/api/event.py
index e00ce051..a066faae 100644
--- a/patchwork/api/event.py
+++ b/patchwork/api/event.py
@@ -8,6 +8,7 @@ from collections import OrderedDict
from rest_framework.generics import ListAPIView
from rest_framework.serializers import ModelSerializer
from rest_framework.serializers import SerializerMethodField
+from rest_framework.serializers import SlugRelatedField
from patchwork.api.embedded import CheckSerializer
from patchwork.api.embedded import CoverLetterSerializer
@@ -16,7 +17,6 @@ from patchwork.api.embedded import ProjectSerializer
from patchwork.api.embedded import SeriesSerializer
from patchwork.api.embedded import UserSerializer
from patchwork.api.filters import EventFilterSet
-from patchwork.api.patch import StateField
from patchwork.models import Event
@@ -27,8 +27,8 @@ class EventSerializer(ModelSerializer):
patch = PatchSerializer(read_only=True)
series = SeriesSerializer(read_only=True)
cover = CoverLetterSerializer(read_only=True)
-previous_state = StateField()
-current_state = StateField()
+previous_state = SlugRelatedField(slug_field='slug', read_only=True)
+current_state = SlugRelatedField(slug_field='slug', read_only=True)
previous_delegate = UserSerializer()
current_delegate = UserSerializer()
created_check = SerializerMethodField()
diff --git a/patchwork/api/patch.py b/patchwork/api/patch.py
index d1c9904d..a29a1ab0 100644
--- a/patchwork/api/patch.py
+++ b/patchwork/api/patch.py
@@ -5,6 +5,7 @@
import email.parser
+from django.utils.text import slugify
from django.utils.translation import ugettext_lazy as _
from rest_framework.generics import ListAPIView
from rest_framework.generics import RetrieveUpdateAPIView
@@ -28,10 +29,7 @@ from patchwork.parser import clean_subject
class StateField(RelatedField):
"""Avoid the need for a state endpoint.
-NOTE(stephenfin): This field will only function for State names consisting
-of alphanumeric characters, underscores and single spaces. In Patchwork
-2.0+, we should consider adding a slug field to the State object and make
-use of the SlugRelatedField in DRF.
+TODO(stephenfin): Consider switching to SlugRelatedField for the v2.0 API.
"""
default_error_messages = {
'required': _('This field is required.'),
@@ -41,19 +39,13 @@ class StateField(RelatedField):
'{data_type}.'),
}
-@staticmethod
-def format_state_name(state):
-return ' '.join(state.split('-'))
-
def to_internal_value(self, data):
+data = slugify(data.lower())
try:
-data = self.format_state_name(data)
-return self.get_queryset().get(name__iexact=data)
+return self.get_queryset().get(slug=data)
except State.DoesNotExist:
self.fail('invalid_choice', name=data, choices=', '.join([
-self.format_state_name(x.name) for x in self.get_queryset()]))
-except (TypeError, ValueError):
-self.fail('incorrect_type', data_type=type(data).__name__)
+x.slug for x in self.get_queryset()]))
def to_representation(self, obj):
return obj.slug
diff --git a/patchwork/fixtures/default_states.xml
b/patchwork/fixtures/default_states.xml
index 86e1105f..1bbd919d 100644
--- a/patchwork/fixtures/default_states.xml
+++ b/patchwork/fixtures/default_states.xml
@@ -4,51 +4,61 @@
New
+new
0
True
Under Review
+under-review
1
True
Accepted
+accepted
2
False
Rejected
+rejected
3
False
RFC
+rfc
4
False
Not Applicable
+not-applicable
5
False
Changes Requested
+changes-requested
6
False
Awaiting Upstream
+awaiting-upstream
7
False
Superseded
+superseded
8
False
Deferred
+deferred