About paging query #452
-
Now I need to use paging query in the joint table, and Use multiple response, What shall I do? For example: class Group(models.Model)
name = models.CharField(max_length=64, verbose_name="group name")
class User(models.Model)
name = models.CharField(max_length=64, verbose_name="user name")
group = models.ForeignKey(Group, on_delete=models.CASCADE, verbose_name="by group",
related_name='user', related_query_name='user')
class GroupUsers(Schema)
id: int
name: str
group_id: int
@router.get('/groups/{pk}/users', response={404: str, 200: List[GroupUsers]})
@paginate
def get_group_users(request, pk: int)
group = Group.objects.filter(id=pk).first()
if not group:
return 404, "Group does not exist"
users = Group.objects.filter(user__group=pk).all()
return users But this is a failure by 422 |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 5 replies
-
@router.get('/groups/{pk}/users', response={200: List[GroupUsers], 404: str}) # put 200 in the front
@paginate
def get_group_users(request, pk: int)
group = Group.objects.filter(id=pk).first()
if not group:
return 404, "Group does not exist"
users = group.user.all() # query
return users it can work. but, it can only return paginate result, If it's 404, it will trigger schema error by GroupUsers If remove the paging decorator, it can return to all normally, but I need paging What shall I do? @vitalik @ |
Beta Was this translation helpful? Give feedback.
-
This has nothing to do with pagination at all! You're just doing the user query wrong. You want: users = group.user_set.all() Removing the pagination decorator definitely does not make things "return to normal". The key here was to note that your error was 422, with the following error message:
Which should get you thinking about why doesn't the item have a group_id. Then you look back at your query and see that you're returning a queryset of groups rather than users, and it all becomes clear. |
Beta Was this translation helpful? Give feedback.
-
Hi @SmileyChris. I made a complete example to overturn your statement and support my statement first: because use ForeignKey, therefore, Second, 422 is the initial problem, which is in the changes I propose below new, will not happen 422 third, your query is right, but use next: This is the complete example and the returned result # Model
from django.db import models
class Group(models.Model):
name = models.CharField(max_length=64, verbose_name="group name")
class User(models.Model):
name = models.CharField(max_length=64, verbose_name="user name")
group = models.ForeignKey(Group, on_delete=models.CASCADE, verbose_name="by group",
related_name='user', related_query_name='user') # code
from typing import List, Any
from ninja import NinjaAPI, Schema
from ninja.pagination import paginate, PageNumberPagination
from ttt.models import Group, User
router = NinjaAPI(docs_url='/v1/docs')
class Response404(Schema):
code: int = 404
msg: str = 'Not Found'
data: Any = None
class CreateGroup(Schema):
name: str
class CreateUser(Schema):
name: str
group: int
class GroupUsers(Schema):
id: int
name: str
group_id: int
@router.post('/groups')
def create_group(request, group: CreateGroup):
Group.objects.create(**group.dict())
return group
@router.post('/users')
def create_user(request, user: CreateUser):
user.group = Group.objects.filter(id=user.group).first()
User.objects.create(**user.dict())
return {'name': user.name}
@router.get('/groups/{pk}/users', response={200: List[GroupUsers], 404: Response404}) # put 200 in the front
@paginate(PageNumberPagination)
def get_group_users(request, pk: int):
group = Group.objects.filter(id=pk).first()
if not group:
return 404, {"msg": "Group does not exist"}
users = group.user.all() # query
return users
1: group=1
# request
curl -X 'GET' \
'http://127.0.0.1:8000/groups/1/users?page=1' \
-H 'accept: application/json'
# response
{
"items": [
{
"id": 1,
"name": "string",
"group_id": 1
},
{
"id": 2,
"name": "string",
"group_id": 1
}
],
"count": 2
}
2: group=2
# request
curl -X 'GET' \
'http://127.0.0.1:8000/groups/2/users?page=1' \
-H 'accept: application/json'
# response
{
"items": [],
"count": 0
}
3: group=3
# request
curl -X 'GET' \
'http://127.0.0.1:8000/groups/3/users?page=1' \
-H 'accept: application/json'
# response
Traceback (most recent call last):
File "C:\ProgramData\Anaconda3\envs\NinjaXia\lib\site-packages\ninja\operation.py", line 100, in run
return self._result_to_response(request, result)
File "C:\ProgramData\Anaconda3\envs\NinjaXia\lib\site-packages\ninja\operation.py", line 193, in _result_to_response
result = response_model.from_orm(resp_object).dict(
File "C:\ProgramData\Anaconda3\envs\NinjaXia\lib\site-packages\ninja\schema.py", line 161, in from_orm
return super().from_orm(obj)
File "pydantic\main.py", line 631, in pydantic.main.BaseModel.from_orm
pydantic.error_wrappers.ValidationError: 6 validation errors for NinjaResponseSchema
response -> items -> 0 -> id
field required (type=value_error.missing)
response -> items -> 0 -> name
field required (type=value_error.missing)
response -> items -> 0 -> group_id
field required (type=value_error.missing)
response -> items -> 1 -> id
field required (type=value_error.missing)
response -> items -> 1 -> name
field required (type=value_error.missing)
response -> items -> 1 -> group_id
field required (type=value_error.missing) If remove the paging 1: group=1
# request
curl -X 'GET' \
'http://127.0.0.1:8000/groups/1/users?page=1' \
-H 'accept: application/json'
# response
[
{
"id": 1,
"name": "string",
"group_id": 1
},
{
"id": 2,
"name": "string",
"group_id": 1
}
]
2: group=2
# request
curl -X 'GET' \
'http://127.0.0.1:8000/groups/2/users?page=1' \
-H 'accept: application/json'
# response
[]
3: group=3
# request
curl -X 'GET' \
'http://127.0.0.1:8000/groups/3/users?page=1' \
-H 'accept: application/json'
# response
{
"code": 404,
"msg": "Group does not exist",
"data": null
} As you can see, the request is normal without the paging |
Beta Was this translation helpful? Give feedback.
-
Ah, I see what you're saying now -- it's specifically when you're trying to return a different response type, which you can't do with the What you can do though is raise an exception that ninja will handle. And by default, it handles Django's Http404 error like you want. So all you want is: from django.shortcuts import get_object_or_404
...
@paginate
def get_group_users(request, pk: int):
return get_object_or_404(Group, id=pk).user.all() |
Beta Was this translation helpful? Give feedback.
Ah, I see what you're saying now -- it's specifically when you're trying to return a different response type, which you can't do with the
paginate
decorator. That could definitely do with some better documentation.What you can do though is raise an exception that ninja will handle. And by default, it handles Django's Http404 error like you want. So all you want is: