Inserting foreign key in django rest framework - django

Here is the code that i am using for serializer
class CitySerializer(serializers.ModelSerializer):
addedBy = serializers.ReadOnlyField(source='addedBy.username')
country = CountrySerializer()
class Meta:
model = City
fields = ('id','name','slug','country','addedBy','createdAt')
class ActivitySerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
tag = ActivityTagSerializer()
location = CitySerializer()
class Meta:
model = Activity
fields = ('id','title','slug','description','location','tag','owner','createdAt')
i am able to insert data if i remove tag and location serializer by adding there pk in form but not with them being serialized. Here is the views that are being used
class ActivityList(generics.ListCreateAPIView):
queryset = Activity.objects.all()
serializer_class = ActivitySerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
class ActivityDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Activity.objects.all()
serializer_class = ActivitySerializer
permission_classes = (permissions.IsAuthenticatedOrReadOnly,)
The owner field is read-only so thats why had to create a separate insert for the same. Now here are the outputs from the two case , with and without reference to other serializer (tag and location) in ActivitySerializer
{
"id": 3,
"title": "sdfsdf",
"slug": "sdfsdf",
"description": "sdfsdfsdf",
"location": {
"id": 2,
"name": "goa",
"slug": "goa",
"country": {
"id": 1,
"name": "india",
"slug": "india",
"addedBy": "georoot",
"createdAt": "2016-06-17T05:56:30.099121Z"
},
"addedBy": "georoot",
"createdAt": "2016-06-17T06:01:12.771079Z"
},
"tag": {
"id": 3,
"title": "temp",
"slug": "temp",
"addedBy": "georoot",
"createdAt": "2016-06-17T06:03:44.647455Z"
},
"owner": "georoot",
"createdAt": "2016-06-17T06:24:50.006344Z"
}
This is with reference to serializer which is the output view that i want, but insert not working in this case
and this is without reference to the serializer
{
"id": 3,
"title": "sdfsdf",
"slug": "sdfsdf",
"description": "sdfsdfsdf",
"location": 2,
"tag": 3,
"owner": "georoot",
"createdAt": "2016-06-17T06:24:50.006344Z"
}
Here i can change the values of tag and location by passing in the pk.
How can i do the same while referencing to other serializer as in the previous output
EDIT
structure for models
class City(models.Model):
name = models.CharField(max_length=200)
slug = AutoSlugField(populate_from='name')
country = models.ForeignKey(Country)
addedBy = models.ForeignKey('auth.user')
createdAt = models.DateTimeField(auto_now_add=True, blank=True)
class Activity(models.Model):
owner = models.ForeignKey('auth.user')
title = models.CharField(max_length=200)
slug = AutoSlugField(populate_from='title')
description = models.TextField()
location = models.ForeignKey(City)
tag = models.ForeignKey(ActivityTag)
createdAt = models.DateTimeField(auto_now_add=True, blank=True)

Related

Fields of Nested serializers

In my nested serializer i want to show only movie name and exclude the other fields
[
{
"id": 2,
"watchlist": [
{
"id": 3,
"platform": "Netflix",
"title": "Martian",
"storyline": "A lost astronaut of Mars survived",
"average_rating": 4.1,
"total_rating": 2,
"active": true,
"created": "2022-04-05T05:37:35.902464Z"
},
{
"id": 4,
"platform": "Netflix",
"title": "Intersteller",
"storyline": "Finding new home",
"average_rating": 0.0,
"total_rating": 0,
"active": true,
"created": "2022-04-06T04:52:04.665202Z"
},
{
"id": 5,
"platform": "Netflix",
"title": "Shutter Island",
"storyline": "Psycopath",
"average_rating": 0.0,
"total_rating": 0,
"active": true,
"created": "2022-04-06T04:52:51.626397Z"
}
],
"platform": "Netflix",
"about": "streaming, series and many more",
"website": "https://www.netflix.com"
},
]
In the above data,
"watchlist" is the nested serializer data
i want to show only "title"
and exclude all other data
I have included WatchListSerializer class as "nested" serializer in the StreamPlatformSerializer class.
I want that on "title should be shown, rest other fields should be excluded from nested serializer part"
below is the code...
class WatchListSerializer(serializers.ModelSerializer):
# reviews = ReviewSerializer(many=True, read_only=True)
platform = serializers.CharField(source='platform.platform')
class Meta:
model = WatchList
fields = '__all__'
# def to_representation(self, value):
# return value.title
class StreamPlatformSerializer(serializers.ModelSerializer):
watchlist = WatchListSerializer(many=True, read_only=True)
# watchlist = serializers.CharField(source='watchlist.title')
class Meta:
model = StreamPlatform
fields = '__all__'
after removing other fields it should look like this as below..
[
{
"id": 2,
"watchlist": [
{
"title": "Martian"
},
{
"title": "Intersteller",
},
{
"title": "Shutter Island",
],
"platform": "Netflix",
"about": "streaming, series and many more",
"website": "https://www.netflix.com"
},
]
There may be two approaches for this thing
First Approach:
class WatchListSerializer(serializers.ModelSerializer):
# reviews = ReviewSerializer(many=True, read_only=True)
class Meta:
model = WatchList
fields = ("title",)
# def to_representation(self, value):
# return value.title
class StreamPlatformSerializer(serializers.ModelSerializer):
watchlist = WatchListSerializer(many=True, read_only=True)
# watchlist = serializers.CharField(source='watchlist.title')
class Meta:
model = StreamPlatform
fields = '__all__'
With this approach the downside will be that WatchListSerializer can only be used in this serializer not as a standalone serializer.
For second approach I need to see your models. It would be like
class StreamPlatformSerializer(serializers.ModelSerializer):
watchlist = serializers.SerializerMethodField("get_watchlist")
class Meta:
model = StreamPlatform
fields = '__all__' # include watchlist as well
def get_watchlist(self, obj):
return obj.watchlist.all().values('title')
I like this approach personally.

Django serializers filter foreignkey

view:
class MPNView(viewsets.ModelViewSet):
queryset = MPN.objects.all()
serializer_class = MPNSerializer
serializers:
class ProductsSerializer(serializers.ModelSerializer):
class Meta:
model = Products
fields = "__all__"
class MPNSerializer(serializers.ModelSerializer):
products = ProductsSerializer(many=True)
class Meta:
model = MPN
fields = "__all__"
model:
class MPN(Model):
number = models.CharField(max_length=50)
created_at = models.DateTimeField(auto_now_add=True)
class Product(Model):
mpn = models.ForeignKey(to=MPN, on_delete=models.CASCADE, related_name="products", null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
Results i am getting:
[
{
"id": 1221,
"products": [],
"number": "B07BMTYSMR",
"created_at": "2020-09-29T03:05:01.560801Z"
},
{
"id": 1222,
"products": [
{
"id": 2352,
"created_at": "2020-09-30T12:49:09.347655Z",
},
{
"id": 2352,
"created_at": "2020-09-30T12:49:09.347655Z",
}
]
}
]
Results i am expecting:
[
{
"id": 1222,
"products": [
{
"id": 2352,
"created_at": "2020-09-30T12:49:09.347655Z",
},
{
"id": 2352,
"created_at": "2020-09-30T12:49:09.347655Z",
}
]
}
]
Here is my code . I have shared view, model and serializers.
Here I am trying to get result with ForeignKey related fields.
But, I want to add one filter so that it ignores data where products is [ ] (empty array)
Please have a look how can I achieve that.
Try filtering the queryset:
queryset = MPN.objects.all().exclude(products__isnull=True)
Here you would use the "products" and check if it is empty. Empty results would be excluded.

Django Search in many to many field

I am trying to create a search in my Django Rest Framework application I have a table of follower and following via one model called: UserFollowing and the code is:
class UserFollowing(TimeStampedModel):
user_id = models.ForeignKey(
User, related_name="following", on_delete=models.CASCADE, blank=True)
following_user_id = models.ForeignKey(
User, related_name="followers", on_delete=models.CASCADE, blank=True)
#property
def username(self):
profile_instance = Profile.objects.get(user=self.user_id)
username = profile_instance.profile_username
return username
#property
def name(self):
profile_instance = Profile.objects.get(user=self.user_id)
name = profile_instance.name
return name
class Meta:
unique_together = ("user_id", "following_user_id")
ordering = ["-user_id"]
def __str__(self):
return str(self.id)
Here everything works fine but in my following list API, I am appending username and name of the user. When I am getting a list of follower using:
paginator = PageNumberPagination()
query_set = UserFollowing.objects.filter(user_id=request.user.id)
context = paginator.paginate_queryset(query_set, request)
serializer = UserFollowingSerializer(context, many=True)
Now I want to search via the result my serializer.data look like:
{
"count": 2,
"next": null,
"previous": null,
"results": [
{
"id": 233,
"username": "Username1",
"user_profile_image": "url",
"name": "CDE",
"is_active": true,
"created_at": "2020-07-25T06:00:31.786154Z",
"updated_at": "2020-07-25T06:00:31.786185Z",
"user_id": 88,
"following_user_id": 53,
"is_following": true
},
{
"id": 49,
"username": "username",
"user_profile_image": "URL",
"name": "ABC",
"is_active": true,
"created_at": "2020-07-15T08:32:35.352484Z",
"updated_at": "2020-07-15T08:32:35.352517Z",
"user_id": 88,
"following_user_id": 144,
"is_following": true
}
]
}
So based on my output how can I search a result where username = What can be the best way to search in this case.

Django: Make a GET Request to a URL that is advanced

So I have Chat Rooms and I have Messages. Then I have two urls: /messages and /rooms. And these display all your rooms and messages. Also a message can be assigned to a room. So in the Room API I have the messages assigned to that room.
Let's say that the room is called 'Room1' and the messages are 'hey', 'yo' and 'wassup'. If I make a request to just /messages I will get all of the messages. Let's say that only two of the messages are assigned to 'Room1' and the other message is assigned to another room not named.
I want a way to make a get request and only get those two messages assigned to 'Room1 with id = 3' (localhost:8000/rooms/3/messages) instead of: (localhost:8000/messages).
This is an example of when I make a get request to /rooms/3/
{
"id": 3,
"name": "Room 1",
"members": [
{
"id": 1,
"username": "william"
},
{
"id": 2,
"username": "eric"
},
{
"id": 3,
"username": "ryan"
}
],
"messages": [
{
"id": 7,
"content": "hej",
"date": "2019-07-08",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 8,
"content": "yoyo",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 9,
"content": "tjo bror",
"date": "2019-07-08",
"sender": {
"id": 3,
"username": "ryan"
}
},
{
"id": 10,
"content": "hej jag heter Eric och jag gar pa polhemskolan i lund och jag ar 17 ar gammal",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 11,
"content": "vi vet hahah",
"date": "2019-07-09",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 12,
"content": "amen sluta",
"date": "2019-07-09",
"sender": {
"id": 2,
"username": "eric"
}
}
]
}
This is what I want to get in response if I do rooms/3/messages:
"messages": [
{
"id": 7,
"content": "hej",
"date": "2019-07-08",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 8,
"content": "yoyo",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 9,
"content": "tjo bror",
"date": "2019-07-08",
"sender": {
"id": 3,
"username": "ryan"
}
},
{
"id": 10,
"content": "hej jag heter Eric och jag gar pa polhemskolan i lund och jag ar 17 ar gammal",
"date": "2019-07-08",
"sender": {
"id": 2,
"username": "eric"
}
},
{
"id": 11,
"content": "vi vet hahah",
"date": "2019-07-09",
"sender": {
"id": 1,
"username": "william"
}
},
{
"id": 12,
"content": "amen sluta",
"date": "2019-07-09",
"sender": {
"id": 2,
"username": "eric"
}
}
]
}
Django Models:
class UserProfile(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
class Meta:
verbose_name_plural = 'All Users'
def __str__(self):
return self.user.username
#receiver(post_save, sender=User)
def create_user_data(sender, update_fields, created, instance, **kwargs):
if created:
user = instance
profile = UserProfile.objects.create(user=user)
class Message(models.Model):
sender = models.ForeignKey(UserProfile, on_delete=models.CASCADE, related_name="sendermessage")
content = models.CharField(max_length=500)
date = models.DateField(default=date.today)
canview = models.ManyToManyField(UserProfile, blank=True, related_name="messagecanview")
class Meta:
verbose_name_plural = 'Messages'
def __str__(self):
return "{sender}".format(sender=self.sender)
class Room(models.Model):
name = models.CharField(max_length=50)
members = models.ManyToManyField(UserProfile, blank=True)
messages = models.ManyToManyField(Message, blank=True)
class Meta:
verbose_name_plural = 'Rooms'
def __str__(self):
return "{name}".format(name=self.name)enter code here
Django Serializers:
class UserProfileSerializer(serializers.ModelSerializer):
username = serializers.CharField(source='user.username')
class Meta:
model = UserProfile
fields = ('id', 'username')
class MessageSerializer(serializers.ModelSerializer):
sender = UserProfileSerializer()
class Meta:
model = Message
fields = ('id', 'content', 'date', 'sender')
class RoomSerializer(serializers.ModelSerializer):
messages = MessageSerializer(many=True)
members = UserProfileSerializer(many=True)
class Meta:
model = Room
fields = ('id', 'name', 'members', 'messages')
Django Views:
class UserProfileView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = UserProfile.objects.all()
serializer_class = UserProfileSerializer
class MessageView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Message.objects.all()
serializer_class = MessageSerializer
class UserMessageView(MessageView):
def get_queryset(self):
return Message.objects.filter(canview__user=self.request.user)
class RoomView(viewsets.ModelViewSet):
http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Room.objects.all()
serializer_class = RoomSerializer
class UserRoomView(RoomView):
def get_queryset(self):
return Room.objects.filter(members__user=self.request.user)
Django Urls:
router = routers.DefaultRouter()
router.register('users', views.UserProfileView),
router.register('rooms', views.UserRoomView),
router.register('messages', views.UserMessageView),
urlpatterns = [
path('', include(router.urls)),
]
To get all Messages assigned to a room, let's:
Install django-filter:
pip install django-filter
Modify the Room model to specify a related_name:
class Room(models.Model):
name = models.CharField(max_length=50)
members = models.ManyToManyField(UserProfile, blank=True)
messages = models.ManyToManyField(Message, blank=True, related_name='rooms')
# ^^^^^^^^^^^^^^^^^^^^^^
Enable filtering for the rooms related field:
import django_filters
import rest_framework.filters
[...]
class MessageView(viewsets.ModelViewSet):
# vvvvvvvvvvv I don't think this line is needed vvvvvvvvvvvvvv
# http_method_names = ['get', 'post', 'put', 'delete', 'patch']
queryset = Message.objects.all()
serializer_class = MessageSerialize
filter_backends = (
django_filters.rest_framework.DjangoFilterBackend,
rest_framework.filters.OrderingFilter,
)
filter_fields = ['rooms']
Then, you can request all messages for that room with a GET to:
localhost:8000/messages/?rooms=3
Comment question:
You also need to expose the Message object's sender field. Currently it is aliased:
class MessageSerializer(serializers.ModelSerializer):
# vvvv vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
sender_obj = UserProfileSerializer(source='sender', read_only=True)
class Meta:
model = Message
fields = ('id', 'content', 'date', 'sender', 'sender_obj')
# ^^^^^^^^^^^^^^
Then you can POST to /message with the data {"content": "blah", "date": "2019-07-09","sender": 1}

Distinct field Rest Framework Django

I need to make a distinct with a field of my model and not how to make
My model is:
class CheckList(CoreModel):
date = models.DateTimeField(default=datetime.now, blank=True, null=True, verbose_name=_('Date'))
establishment = models.ForeignKey(Establishment, related_name="checklists", on_delete=models.CASCADE, null=True, verbose_name=_('Establishment'))
user = models.ForeignKey(ITManager, related_name="checklists", on_delete=models.CASCADE, null=True, verbose_name=_('User'))
class Meta:
verbose_name_plural = _("Checklist")
verbose_name = _("Checklists")
def __str__(self):
return str(self.date)
My serializer and view:
class CheckListSerializer(BulkSerializerMixin, serializers.ModelSerializer):
user = ITManagerSerializer()
class Meta:
model = CheckList
list_serializer_class = BulkListSerializer
fields = ['id', 'user', 'establishment', 'date']
class ChecklistBulkViewSet(BulkModelViewSet):
queryset = CheckList.objects.values('establishment', 'user', 'date').distinct()
model = CheckList
serializer_class = CheckListSerializer
filter_class = ChecklistFilter
The api return me:
"results": [
{
"id": 1,
"user": {
"id": 3,
"first_name": "Andres",
"last_name": "Gallardo",
"rut": "21312",
"email": null,
"user_name": "andres",
"password": null,
"user": 4,
"country": [],
"active": true
},
"establishment": 3,
"date": "2016-06-14T15:15:00Z"
},
{
"id": 2,
"user": {
"id": 2,
"first_name": "Ramiro",
"last_name": "Gutierrez",
"rut": "15616+",
"email": null,
"user_name": null,
"password": null,
"user": 2,
"country": [
{
"id": 1,
"name": "Argentina",
"code_area": null
}
],
"active": false
},
"establishment": 3,
"date": "2016-06-09T15:40:04Z"
}]
I need you just leave me an establishment with the same id
any suggestions??
Thanks !