Reputation: 163
I have this tables store in a Postgres DB
users
| id | email | password | gender |
| 01 | [email protected] | pass1 | male |
| 02 | [email protected] | pass3 | female |
| 03 | [email protected] | pass2 | male |
marks
| id | school_mark | subject | user_id | status |
| 01 | 9 | history | 01 | True |
| 02 | 8 | english | 02 | True |
| 03 | 7 | math | 01 | True |
| 02 | 7 | english | 01 | False |
| 03 | 6 | math | 03 | False |
...
# api/models.py
from django.db import models
class User(models.Model):
email = models.EmailField()
password = models.CharField(max_length=100)
gender = models.CharField(max_length=100)
class Mark(models.Model):
school_mark = models.IntegerField()
subject = models.CharField(max_length=100)
user_id = models.ForeignKey(User, on_delete=models.CASCADE)
status = models.BooleanField(default=False)
I want my final result to be like this /api/marks/male
[
{"id" : 01,
"marks": [
{"id": 01,
"subject": "history",
"school_mark": 9},
{"id": 03,
"subject": "history",
"school_mark": 7}]}
{"id" : 03,
"marks": []}
]
First select only 'male' form user, then search marks for selected users but return in the response only the marks that have status=TRUE
I start to think the serializers.py like this:
# api/serializers.py
from rest_framework import serializers
from .models import User, Mark
class MarkSerializer(serializers.ModelSerializer):
class Meta:
model = Mark
exclude = ('status', 'user_id')
class UserSerializer(serializers.ModelSerializer):
marks = MarkSerializer(many=True, read_only=True)
class Meta:
model = User
fields = ('id', 'marks')
But then I'm stuck on views.py
# api/views.py
from rest_framework import generics
from .models import User, Mark
from .serializers import UserSerializer
class MarkList(generics.ListAPIView):
serializer_class = UserSerializer
def get_queryset(self):
# "/api/marks/<str:gender>/"
gender = kwargs['gender']
???
Any idea how to go on ?
Upvotes: 2
Views: 440
Reputation: 2830
Are you set on the url/response structure? I realize this is not exactly what you asked for, but in order to give the best answer I can, there are some structural things I would probably change about your setup:
Normally for a RESTful API, /api/marks/ would return a list of serialized Mark
objects as opposed to what you have shown, which is a list of Users
where each has a list of serialized Marks
. Since you only need the user id, DRF provides a simple non-nested mechanism for serializing this the other way around (using PrimaryKeyRelatedField
).
Next, instead of /api/marks/male I would probably use a query parameter (/api/marks?gender=male). This is a little bit of personal preference but has some basis in REST best practices (see this SO answer for a nice description)
Finally, the ForeignKey
field on Mark
should be named user
, not user_id
. Django automatically appends _id
to the database column name when storing a foreign key field, so the model as you have written it will result in a DB column named user_id_id
.
With these modifications, the following code would get you the filtering you requested (although the serialized response is a little different than your initial request as described above):
# api/serializers.py
from rest_framework import serializers
from .models import Mark
class MarkSerializer(serializers.ModelSerializer):
user = serializers.PrimaryKeyRelatedField(read_only=True)
class Meta:
model = Mark
exclude = ('status')
# api/views.py
from rest_framework import generics
from .models import Mark
from .serializers import MarkSerializer
class MarkList(generics.ListAPIView):
serializer_class = MarkSerializer
def get_queryset(self):
queryset = Mark.objects.filter(status=True)
gender = self.request.query_params.get('gender')
if gender is not None:
queryset = queryset.filter(user__gender=gender)
return queryset
I have not tested this out, but barring any typos, requesting /api/marks?gender=male from your example above should return something like this:
[
{
"id" : 01,
"subject": "history",
"school_mark": 9,
"user": 01
},
{
"id" : 03,
"subject": "math",
"school_mark": 7,
"user": 01
}
]
Upvotes: 2