So I am creating follower system but there is a problem. Everything is working properly. but in follower serializer I want the username's and other details of users.
models.py
class Follow(models.Model):
user = models.OneToOneField(User,related_name="user" ,on_delete=models.CASCADE)
''' to obtain user ' eeee = User.objects.first() , eeee.user' '''
following = models.ManyToManyField(User,related_name='following_user',blank=True)
''' to obtain followers ' eeee.following_user.all()' '''
''' to obtain following ' eeee.user.following.all()' '''
def __str__(self):
return self.user.username
In field following , user.following.all() is used to get the user in manytomany field of request.user and
following_user.all() is used get all the users who has added request.user in their following field.
serializers.py
class FollowerSerializer(ModelSerializer):
user = UserSerializer(many=False)
follower = SerializerMethodField()
class Meta:
model = Follow
fields = ('user','follower')
def get_follower(self, obj):
context = self.context
request = context.get("request")
return request.user.following_user.all().values()
Here I am serializing all the user who has added request.user in their following field
views.py
class FollowerView(RetrieveAPIView):
queryset = Follow.objects.all()
serializer_class = FollowerSerializer
permission_classes = [IsAuthenticated]
lookup_field = 'id'
api
{
"user": {
"name": "eeee"
},
"is_follower": [
{
"id": 2,
"user_id": 9
},
{
"id": 5,
"user_id": 16
},
{
"id": 3,
"user_id": 10
}
]
}
These is the api I am getting of all the user who has added request.user in their following list.
the problem here is I am getting the pk of the user from the key user_id. But I want there username and other information like email, full name of the user who has that primary key. So how can I achieve that?
Modify the get_follower method in serializers.py as follows:
def get_follower(self, obj):
context = self.context
request = context.get("request")
qs = request.user.following_user.all()
data = [{'id': obj.pk, 'user_id': obj.user_id, 'name': obj.req_field} for obj in qs]
return data
Related
I have this URL and I send the currently logged in user's id (viewer (33)) and the id of the user being looked at (user (1)) in the URL:
path("users/<int:viewer>/<int:user>/profile/", OtherProfile.as_view()),
Here is the view handling that URL:
class OtherProfile(generics.RetrieveAPIView):
permission_classes = [permissions.IsAuthenticated]
serializer_class = ProfileSerializer
name = "other-profile"
lookup_field = "user"
def get_queryset(self):
breakpoint()
viewer = self.kwargs["viewer"]
user = self.kwargs["user"]
return Profile.objects.all().filter(user_id=user)
There is a breakpoint here and the result of
print(self.kwargs["viewer"]) gives 33 which is correct
print(self.kwargs["user"]) gives 1 which is also correct
Here is the profile serializer as specified in the serializer_class:
class ProfileSerializer(serializers.ModelSerializer):
location = serializers.SerializerMethodField()
user = UserSerializer()
followers = serializers.SerializerMethodField()
class Meta:
model = Profile
fields = [
"id",
"background",
"photo",
"first_name",
"middle_name",
"last_name",
"birthdate",
"gender",
"bio",
"occupation",
"is_verified",
"verification",
"website",
"location",
"user",
"followers",
"created_at",
"updated_at",
]
def get_location(self, obj):
location_obj = Location.objects.filter(profile=obj.id)
if location_obj:
location_obj = Location.objects.get(profile=obj.id)
location = LocationSerializer(location_obj)
return location.data
def get_followers(self, obj):
breakpoint()
followers = Follow.objects.filter(followee=obj.user.id)
return followers.count()
I put a breakpoint on the get_followers method so I can look at the data.
print(self.context["view"].kwargs) - prints ["viewer", "user"]
My question:
Why does print(self.context["view"].kwargs["user"]) print 33 when on the view the kwargs user should be 1?
Why does it give me a key error when I try and print(self.context["view"].kwargs["viewer"])?
Whenever i called my booking function with a post method in that it throws me an error of 'Invalid Data Type it expected dict but its an int'. So when i debug that i found a problem in my serializers so Please help me to resolve the error
model.py
class Booking(models.Model):
details = models.ForeignKey(PersonalDetails, on_delete=models.CASCADE)
quantity = models.IntegerField(null=False)
total_amount = models.IntegerField()
show = models.ForeignKey(ShowTime, on_delete=models.CASCADE)
def __str__(self) -> str:
return self.total_amount
views.py
class BookingTicketsQuery(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
booking_id = request.query_params.get('booking_no', None)
if booking_id is not None:
queryset = Booking.objects.get(id=booking_id)
else:
return Response("invalid", status=status.HTTP_409_CONFLICT)
seriliazer = BookingSerializer(queryset)
return Response(seriliazer.data)
def post(self, request, format=None):
recieve_data = JSONParser().parse(request)
showtime = ShowTime.objects.get(id=recieve_data['show'])
print(showtime)
if recieve_data['quantity'] > (showtime.total_seats - showtime.booked_seats):
return Response("Error: No seats available", status=status.HTTP_409_CONFLICT)
recieve_data['total_amount'] = showtime.total_price * \
recieve_data['quantity']
showtime.booked_seats += recieve_data['quantity']
showtime.save()
serializer = BookingSerializer(data=recieve_data)
if serializer.is_valid():
booking_obj = serializer.save()
return Response(booking_obj.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
serializers.py
class ShowMovieSerializer(serializers.ModelSerializer):
cinema = CinemaSerializer()
movie = MovieSerializer()
class Meta:
model = ShowTime
fields = ('id', 'show_start_time', 'show_end_time',
'total_seats', 'booked_seats', 'cinema', 'movie')
class BookingSerializer(serializers.ModelSerializer):
show = ShowMovieSerializer()
details = PersonalDetailsSerializer()
class Meta:
model = Booking
fields = ('id', 'total_amount', 'quantity', 'details', 'show')
traceback
Bad Request: /api/v1/bookings/
[19/Jul/2021 12:07:20] "POST /api/v1/bookings/ HTTP/1.1" 400 168
{
"details": {
"non_field_errors": [
"Invalid data. Expected a dictionary, but got int."
]
},
"show": {
"non_field_errors": [
"Invalid data. Expected a dictionary, but got int."
]
}
}
my post data:
{
"details": 1,
"quantity":1,
"show":1
}
You added a ShowMovieSerializer() and PersonalDetailsSerializer(). Therefore drf expects data that represents both models (nested data). What you have to do instead of posting { "details": 1, "quantity":1, "show":1 }-data you have to adjusted your data that represents your model. You are posting data with a pk of your Movie and Show.
For instance:
{
"id":....,
"total_amount": ....,
....
"movie": {
"title": ...., # fields are only for explanation
"length": ....
},
"show": {
"title": ....,
"actor": ....
}
}
If you only want to establish a relationship between you ShowTime and Booking you have to remove your serializers.
dealing with nested data
I am trying to create a simple model with foreign keys using Django rest framework.
This are the models:
class Route(models.Model):
place_origin = models.ForeignKey(
Place, null=False, on_delete=models.DO_NOTHING)
class Place(models.Model):
name = models.CharField(max_length=50, null=False)
This are the serializers for each model:
class PlaceSerializer(serializers.ModelSerializer):
class Meta:
model = Place
fields = ["id", "name"]
class RouteSerializer(serializers.ModelSerializer):
place_origin = PlaceSerializer(many=False, read_only=True)
class Meta:
model = Route
fields = ["id", "place_origin"]
This RouteSerializer has the place_origin property in order to show the place details(all the fields from it) when I am looking at the route detail. What I mean is for routes I want to display:
[
{
"id": 1,
"place_origin": {
"id": 1,
"name": "New york"
}
},
{
"id": 2,
"place_origin": {
"id": 2,
"name": "Boston"
}
}
]
And not just:
[
{
"id": 1,
"place_origin": 1
},
{
"id": 2,
"place_origin": 2
}
]
This is the view:
#api_view(['POST'])
def routes_new_route_view(request):
"""
Create a new route
"""
if request.method == "POST":
data = JSONParser().parse(request)
place_origin = Place.objects.get(id=data["place_origin"])
data["place_origin"] = PlaceSerializer(place_origin)
data["place_origin"] = data["place_origin"].data
serializer = RouteSerializer(data=data)
if serializer.is_valid():
serializer.save()
return JsonResponse(serializer.data, status=201)
else:
return JsonResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
I want to send the request from postman this way:
{
"place_origin": 3
}
But I am getting the error from the title.
Thanks for all the help!
The error is that you're trying to send data via a PlaceSerializer but this field is read_only. On the other hand, your DB expects place_origin since you precised null=False in your model. Both combined gives the error "Not NULL constraint failed".
The easiest way is to slightly modify your serializer in order to have one field for write and another for read.
class RouteSerializer(serializers.ModelSerializer):
place_origin = PlaceSerializer(many=False, read_only=True)
place = serializers.PrimaryKeyRelatedField(source="place_origin",queryset=Place.objects.all(),write_only=True)
class Meta:
model = Route
fields = ["id", "place_origin", "place"]
Here, you will use place field as a way to create the relationship with your Route instance.
I'm currently trying to make a post request with only data field in models.py:
class Filter(models.Model):
class Meta:
verbose_name_plural = "Filter"
verbose_name = "Filter"
db_table= "listing_filter"
data = JSONField(default={})
user = models.ForeignKey('backend.user', on_delete=models.CASCADE)
I have the following Serializer , i use JSONField following the drf document docs:
class FilterSerializer(serializers.ModelSerializer):
data = serializers.JSONField(required=True)
user = serializers.CharField(required=False)
class Meta:
model = Filter
fields = ('__all__')
and use it in the APIView:
class FilterView(APIView):
def post(self, request):
login_user = request.user
received_json_data=json.loads(request.body)
valid_ser = FilterSerializer(data=received_json_data)
if valid_ser.is_valid():
post_data = received_json_data["data"]
filter = Filter.objects.create(data=post_data, user=login_user)
filter.save()
return JsonResponse({'code':'200','data': filter.id}, status=200)
else:
return JsonResponse({'code':'400','errors':valid_ser.errors}, status=400)
When i send the following data in body it worked and saved the object:
{
"data": {
"http://example.org/about": {
"http://purl.org/dc/terms/title": [
{
"type": "literal",
"value": "Anna's Homepage"
}
]
}
}
}
But when i send data as a string(which is not a json object) it still save, how do i prevent this ?
{
"data" : "abc"
}
The problem: when I pass someModelSerializer.data as a nested data for anotherModelSerializer, and after that I pass anotherModelSerializer.data to Response, in the response I see only two fields of SomeModel instead of 5. But when I pass someModelSerializer.data directly to Response, I can see that all model fields are present.
Details below.
I have TranslationHistory model
class TranslationHistory(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
string = models.CharField(max_length=255)
count = models.IntegerField(default=1)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='translation_history')
and it's TranslationHistorySerializer
class TranslationHistorySerializer(serializers.ModelSerializer):
class Meta:
model = TranslationHistory
user = serializers.PrimaryKeyRelatedField(read_only=True, default=None)
count = serializers.IntegerField(read_only=True)
def validate_user(self, value):
return self.context['request'].user
def update(self, instance, validated_data):
instance.count += 1
instance.save()
return instance
I also have a virtual entity Translation, which is not a model. It has it's own serializer.
class TranslationSerializer(serializers.Serializer):
translation_history = TranslationHistorySerializer() # nested serializer
translation = serializers.CharField()
In my view, if I do like this,
history = TranslationHistory().findByUserAndString(request.user, string)
historySerializer = TranslationHistorySerializer(history)
return Response(historySerializer.data, status=status.HTTP_200_OK)
I have the response like this.
{
"id": 18,
"user": 1,
"count": 72,
"created": "2015-07-15T15:35:50.751219Z",
"updated": "2015-07-24T15:37:04.247469Z",
"string": "hello"
}
But if in my view I do like this,
history = TranslationHistory().findByUserAndString(request.user, string)
historySerializer = TranslationHistorySerializer(history)
serializer = TranslationSerializer(
data={
'translation_history': historySerializer.data,
'translation': 'hello'
},
context={'request': request}
)
serializer.is_valid(raise_exception=True)
return Response(serializer.data, status=status.HTTP_200_OK)
I have the response like this.
{
"translation_history": {
"user": 1,
"string": "hello"
},
"translation": "hello"
}
Why am I getting only user and string fields in this case?