api: handle multiple objects returned in get-or-create mixin (#44301)
This commit is contained in:
parent
d305ddd6f6
commit
bf5df42709
|
@ -15,12 +15,21 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from django.db import transaction
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from rest_framework import status
|
||||
from rest_framework.settings import api_settings
|
||||
from rest_framework.exceptions import APIException
|
||||
from rest_framework.exceptions import ValidationError
|
||||
from rest_framework.utils import model_meta
|
||||
|
||||
|
||||
class Conflict(APIException):
|
||||
status_code = status.HTTP_409_CONFLICT
|
||||
default_detail = _('Cannot process request because of conflicting resources.')
|
||||
default_code = 'conflict'
|
||||
|
||||
|
||||
class GetOrCreateMixinView(object):
|
||||
_lookup_object = None
|
||||
|
||||
|
@ -49,6 +58,9 @@ class GetOrCreateMixinView(object):
|
|||
return ModelClass.objects.get(**kwargs)
|
||||
except ModelClass.DoesNotExist:
|
||||
return None
|
||||
except ModelClass.MultipleObjectsReturned:
|
||||
raise Conflict('retrieved several instances of model %s for key attributes %s' % (
|
||||
ModelClass.__name__, kwargs))
|
||||
|
||||
def _validate_get_keys(self, keys):
|
||||
ModelClass = self._get_model_class()
|
||||
|
|
|
@ -1507,6 +1507,41 @@ def test_api_users_get_or_create_email_is_unique(settings, app, admin):
|
|||
assert User.objects.get(id=id).last_name == 'Doe'
|
||||
|
||||
|
||||
def test_api_users_get_or_create_email_not_unique(settings, app, admin):
|
||||
settings.A2_EMAIL_IS_UNIQUE = False
|
||||
User = get_user_model()
|
||||
OU = get_ou_model()
|
||||
ou1 = OU.objects.create(name='OU1', slug='ou1', email_is_unique=True)
|
||||
ou2 = OU.objects.create(name='OU2', slug='ou2', email_is_unique=False)
|
||||
|
||||
app.authorization = ('Basic', (admin.username, admin.username))
|
||||
payload = {
|
||||
'email': 'john.doe@example.net',
|
||||
'first_name': 'John',
|
||||
'last_name': 'Doe',
|
||||
'ou': 'ou1'
|
||||
}
|
||||
# 1. create
|
||||
resp = app.post_json('/api/users/?get_or_create=email', params=payload, status=201)
|
||||
id_user = resp.json['id']
|
||||
assert User.objects.get(id=id_user).first_name == 'John'
|
||||
assert User.objects.get(id=id_user).last_name == 'Doe'
|
||||
assert User.objects.get(id=id_user).ou == ou1
|
||||
# 2. get
|
||||
resp = app.post_json('/api/users/?get_or_create=email', params=payload, status=200)
|
||||
# 3. explicitly create in a different OU
|
||||
payload['ou'] = 'ou2'
|
||||
resp = app.post_json('/api/users/', params=payload, status=201)
|
||||
id_user2 = resp.json['id']
|
||||
assert id_user2 != id_user
|
||||
assert User.objects.get(id=id_user2).first_name == 'John'
|
||||
assert User.objects.get(id=id_user2).last_name == 'Doe'
|
||||
assert User.objects.get(id=id_user2).ou == ou2
|
||||
# 4. fail to retrieve a single instance for an ambiguous get-or-create key
|
||||
resp = app.post_json('/api/users/?get_or_create=email', params=payload, status=409)
|
||||
assert resp.json['errors'] == "retrieved several instances of model User for key attributes {'email': 'john.doe@example.net'}"
|
||||
|
||||
|
||||
def test_api_users_get_or_create_multi_key(settings, app, admin):
|
||||
app.authorization = ('Basic', (admin.username, admin.username))
|
||||
# test missing first_name
|
||||
|
|
Loading…
Reference in New Issue