allow slug or pk (bug 847659)
This commit is contained in:
Родитель
ae7701691b
Коммит
a61aa9eff4
|
@ -50,7 +50,7 @@ A list of the featured apps on the Marketplace.
|
|||
GET /api/v1/home/featured/
|
||||
|
||||
:param dev: the device requesting the homepage, results will be tailored to the device which will be one of: `firefoxos` (Firefox OS), `desktop`, `android` (mobile).
|
||||
:param category: the id of the category to filter on.
|
||||
:param category: the id or slug of the category to filter on.
|
||||
:param limit: the number of responses.
|
||||
|
||||
**Response**
|
||||
|
|
|
@ -83,6 +83,28 @@ class JSONField(forms.Field):
|
|||
return value
|
||||
|
||||
|
||||
class SluggableModelChoiceField(forms.ModelChoiceField):
|
||||
"""
|
||||
A model choice field that can accept either a slug or a pk and adapts
|
||||
itself based on that. Requries: `sluggable_to_field_name` to be set as
|
||||
the field that we will base the slug on.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kw):
|
||||
if 'sluggable_to_field_name' not in kw:
|
||||
raise ValueError('sluggable_to_field_name is required.')
|
||||
self.sluggable_to_field_name = kw.pop('sluggable_to_field_name')
|
||||
return super(SluggableModelChoiceField, self).__init__(*args, **kw)
|
||||
|
||||
def to_python(self, value):
|
||||
try:
|
||||
if not value.isdigit():
|
||||
self.to_field_name = self.sluggable_to_field_name
|
||||
except AttributeError:
|
||||
pass
|
||||
return super(SluggableModelChoiceField, self).to_python(value)
|
||||
|
||||
|
||||
def parse(file_, require_name=False, require_type=None):
|
||||
try:
|
||||
if not set(['data', 'type']).issubset(set(file_.keys())):
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import base64
|
||||
|
||||
from nose.tools import eq_
|
||||
import mock
|
||||
from nose.tools import eq_, ok_
|
||||
|
||||
from addons.models import Addon
|
||||
import amo
|
||||
import amo.tests
|
||||
from mkt.api.forms import PreviewJSONForm, StatusForm
|
||||
from mkt.api.forms import (PreviewJSONForm, SluggableModelChoiceField,
|
||||
StatusForm)
|
||||
|
||||
|
||||
class TestPreviewForm(amo.tests.TestCase, amo.tests.AMOPaths):
|
||||
|
@ -73,3 +75,26 @@ class TestSubmitForm(amo.tests.TestCase):
|
|||
self.addon.status = s
|
||||
status = StatusForm(instance=self.addon).fields['status']
|
||||
eq_([k for k, v in status.choices], [k])
|
||||
|
||||
|
||||
class TestSluggableChoiceField(amo.tests.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.fld = SluggableModelChoiceField(mock.Mock(),
|
||||
sluggable_to_field_name='foo')
|
||||
|
||||
def test_nope(self):
|
||||
with self.assertRaises(ValueError):
|
||||
SluggableModelChoiceField()
|
||||
|
||||
def test_slug(self):
|
||||
self.fld.to_python(value='asd')
|
||||
ok_(self.fld.to_field_name, 'foo')
|
||||
|
||||
def test_pk(self):
|
||||
self.fld.to_python(value='1')
|
||||
ok_(self.fld.to_field_name is None)
|
||||
|
||||
def test_else(self):
|
||||
self.fld.to_python(value=None)
|
||||
ok_(self.fld.to_field_name is None)
|
||||
|
|
|
@ -2,16 +2,17 @@ from django import forms
|
|||
|
||||
from addons.models import Category
|
||||
from mkt import regions
|
||||
from mkt.api.forms import SluggableModelChoiceField
|
||||
|
||||
|
||||
class Featured(forms.Form):
|
||||
CHOICES = ('android', 'desktop', 'firefoxos')
|
||||
|
||||
dev = forms.ChoiceField(choices=[(c, c) for c in CHOICES],
|
||||
required=False)
|
||||
dev = forms.ChoiceField(choices=[(c, c) for c in CHOICES], required=False)
|
||||
limit = forms.IntegerField(max_value=20, min_value=1, required=False)
|
||||
category = forms.ModelChoiceField(queryset=Category.objects.all(),
|
||||
required=False)
|
||||
category = SluggableModelChoiceField(queryset=Category.objects.all(),
|
||||
sluggable_to_field_name='slug',
|
||||
required=False)
|
||||
region = forms.ChoiceField(choices=list(regions.REGIONS_DICT.items()),
|
||||
required=False)
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ from mkt.zadmin.models import FeaturedApp, FeaturedAppRegion
|
|||
class TestForm(amo.tests.TestCase):
|
||||
|
||||
def lookup(self, region, device):
|
||||
form = Featured({'device': device}, region=region)
|
||||
form = Featured({'dev': device}, region=region)
|
||||
ok_(form.is_valid(), form.errors)
|
||||
return form.as_featured()
|
||||
|
||||
|
@ -71,7 +71,8 @@ class TestFeaturedHomeHandler(BaseOAuth):
|
|||
super(TestFeaturedHomeHandler, self).setUp(api_name='home')
|
||||
self.list_url = list_url('featured')
|
||||
self.cat = Category.objects.create(name='awesome',
|
||||
type=amo.ADDON_WEBAPP)
|
||||
type=amo.ADDON_WEBAPP,
|
||||
slug='awesome')
|
||||
|
||||
# App, no category, worldwide region.
|
||||
self.app1 = Webapp.objects.create(status=amo.STATUS_PUBLIC,
|
||||
|
@ -124,10 +125,16 @@ class TestFeaturedHomeHandler(BaseOAuth):
|
|||
self.assertSetEqual([o['slug'] for o in data['objects']],
|
||||
['app-1', 'app-3'])
|
||||
|
||||
def test_get_category(self):
|
||||
res = self.anon.get(self.list_url, data={'category': self.cat.pk})
|
||||
def _get_category(self, data):
|
||||
res = self.anon.get(self.list_url, data=data)
|
||||
data = json.loads(res.content)
|
||||
eq_(res.status_code, 200)
|
||||
eq_(data['meta']['total_count'], 1)
|
||||
# App2 is in the category.
|
||||
eq_(data['objects'][0]['slug'], self.app2.app_slug)
|
||||
|
||||
def test_get_category(self):
|
||||
self._get_category({'category': self.cat.pk})
|
||||
|
||||
def test_get_slug(self):
|
||||
self._get_category({'category': self.cat.slug})
|
||||
|
|
Загрузка…
Ссылка в новой задаче