Reputation: 1543
I have following APIView:
class SubmitFormAPIView(APIView):
def put(self, request, pk):
# some other codes
form = Form.objects.get(id=pk)
tu_filter, target_user = self._validate_target_user(request, form)
user_status, created = UserFormStatus.objects.get_or_create(
tu_filter,
form_id=pk,
user_id=request.user.pk
)
# Some other codes.
def _validate_target_user(request, form):
if some_conditions:
return Q(), None
else:
try:
target_user_id = int(request.GET.get('target_user_id))
except ValueError:
raise ValidationError()
target_user = get_user_model().objects.get(id=target_user_id)
return Q(target_user_id=target_user_id), target_user
but when django wants to execude get_or_create
method, raises following error:
TypeError: 'Q' object is not iterable
Note: If _validate_target_user()
returns Q(), None
, no errors raised and view works fine. The error will be raised when return Q(target_user_id=target_user_id), target_user
is returned.
I know, question information is not completed, just I want to know, what may cause this error?
Upvotes: 0
Views: 1437
Reputation: 5443
Instead of returning a Q
object, you can also just pass a dictionary of filters instead, like
{ 'target_user_id': target_user_id }
The you can run the get_or_create
with **tu_filter
as arguments, bypassing the need for Q
.
class SubmitFormAPIView(APIView):
def put(self, request, pk):
# some other codes
form = Form.objects.get(id=pk)
tu_filter, target_user = self._validate_target_user(request, form)
user_status, created = UserFormStatus.objects.get_or_create(
**tu_filter,
form_id=pk,
user_id=request.user.pk
)
# Some other codes.
def _validate_target_user(request, form):
if some_conditions:
return {}, None
else:
try:
target_user_id = int(request.GET.get('target_user_id))
except ValueError:
raise ValidationError()
target_user = get_user_model().objects.get(id=target_user_id)
return { 'target_user_id': target_user_id }, target_user
Edit: As to what causes the error, my guess would be that using Q
as part of your get_or_create statement is unclear to Django, because it doesn't know what to do with it in case the object needs to be created. A better approach would therefor be:
UserFormStats.objects.filter(tu_filter).get_or_create(form_id=pk, user_id=request.user.pk)
Upvotes: 1
Reputation: 88609
From the source of get_or_create(...)
,
which indicating that thedef get_or_create(self, defaults=None, **kwargs):
get_or_create(...)
doesn't not accept any args unlike the get()
or filter(...)
methods.
Since your are executing the function as below, Python thinks that the tu_filter
is the value for default
parameter, which is expected to be an iterable.
get_or_create(
tu_filter,
form_id=pk,
user_id=request.user.pk
)
Upvotes: 2