Django serializers filter foreignkey - django

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.

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.

How to add an array object to nested object in Django?

I need to add an array of objects to an another object whose structure has been shown below.
Here is current response from Album:
[
{
"id": "1",
"name": "Skin",
"artists": [
{
"id": "1",
"name": "Flume",
}
],
"tracks": [
{
"id": "1",
"name": "Take A Chance"
}
]
}
]
I need to transform tracks object from Album's response to this:
[
{
"id": "1",
"name": "Skin",
"artists": [
{
"id": "1",
"name": "Flume",
}
],
"tracks": {
"items": [
{
"id": "1",
"name": "Take A Chance"
}
]
}
}
]
EDIT: Here is my current models, views and serializers:
class Artist(models.Model):
name = models.CharField(max_length=300)
albums = models.ManyToManyField('albums.Album', related_name='artists')
tracks = models.ManyToManyField('tracks.Track', related_name='artists')
class Album(models.Model):
name = models.CharField(max_length=400)
class Track(models.Model):
name = models.CharField(max_length=400)
album = models.ForeignKey('albums.Album', related_name='tracks', on_delete=models.CASCADE)
#views.py
class AlbumAPIView(RetrieveAPIView):
queryset = Album.objects.all()
serializer_class = AlbumsSerializer
lookup_field = 'id'
#serializers.py
class AlbumsSerializer(serializers.ModelSerializer):
artists = ArtistsSerializer(many=True)
tracks = TrackSerializer(many=True)
class Meta:
model = Album
fields = [
'id',
'name',
'artists',
'tracks',
]
class ArtistsSerializer(serializers.ModelSerializer):
class Meta:
model = Artist
fields = [
'id',
'name',
]
class TrackSerializer(serializers.ModelSerializer):
artists = ArtistsSerializer(many=True)
class Meta:
model = Track
fields = [
'id',
'name',
'artists',
]
UPD: Added serializers and views!
Any help would be appreciated.
You can do something like this:
class AlbumsSerializer(serializers.ModelSerializer):
artists = ArtistsSerializer(many=True)
tracks = serializers.SerializerMethodField()
def get_tracks(self, obj):
serializer = TrackSerializer(obj.tracks, many=True)
return {'items' : serializer.data}
class Meta:
model = Album
fields = [
'id',
'name',
'artists',
'tracks',
]

How to divide Json strings.?

I have 4 models Category, Vendor, Location, Product. Vendor fall under the Category model (vendor is a foreign key to category). The remaining models are under Vendor (Location, Product)
ProductSerializer and LocationSerializer are nested to VendorSerializer, and VendorSerializer is nested to CategorySerializer.
class ProductSerializer(WritableNestedModelSerializer):
class Meta:
model = Product
fields = ['id', 'item_name', 'price']
read_only_fields = ['id']
class LocationSerializer(WritableNestedModelSerializer):
class Meta:
model = Location
fields = ['place']
class VendorSerializer(WritableNestedModelSerializer):
vendor_location = LocationSerializer()
product = ProductSerializer(many=True)
class Meta:
model = Vendor
fields = ['vendor_name','vendor_location','product']
read_only_fields = ['id']
class CategorySerializer(WritableNestedModelSerializer):
vendor = VendorSerializer(many=True)
class Meta:
model = Category
fields = ['id', 'category_name', 'tittle', 'vendor']
read_only_fields = ['id']
# View
class ProductView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None, *args, **kwargs):
products = Category.objects.all()
serializer = CategorySerializer(products, many=True, context={'request': request})
return Response({'response': 'ok', 'result': serializer.data})
# Output
{
"response": "ok",
"result": [
{
"id": 1,
"category_name": "Cake",
"tittle": "test title",
"vendor": [
{
"vendor_name": "Test_Name",
"vendor_location": {
"place": "Test_Place"
},
"product": [
{
"id": 1,
"item_name": "test_1",
"price": 3200,
},
{
"id": 2,
"item_name": "test_2",
"price": 2010,
}
]
}
]
}
]
}
# Expected output
{
"response": "ok",
"result": [
{
"id": 1,
"category_name": "Cake",
"tittle": "test title",
"vendor": [
{
"vendor_name": "Test_Name",
"vendor_location": {
"place": "Test_Place"
},
"product": [
{
"id": 1,
"item_name": "test_1",
"price": 3200,
}
]
}
]
},
{
"id": 1,
"category_name": "Cake",
"tittle": "test title",
"vendor": [
{
"vendor_name": "Test_Name",
"vendor_location": {
"place": "Test_Place"
},
"product": [
{
"id": 2,
"item_name": "test_2",
"price": 2010,
}
]
}
]
}
]
}
In my output, two products are listed. There may be more than two. I only need one product under the product. All products must be printed in the same structure as I mentioned in expected output. How do I do this? Is it possible? Can someone help me do this?
You can modify this line:
# old:
products = Category.objects.all() # definately these are not products
# new:
products = Product.objects.values_list('id', flat=True) # get all products ids
categories = Category.objects.filter(vendor__product__in=products)
And send categories to CategorySerializer, thought this is still not what you want, as every duplicated category will hold information about all products (not only one).
Where I would go from this point? I'd create method get_product in VendorSerializer and somehow save information what Category/Vendor are we in right now and if we have already added a Product for this Category - I'd skip adding next.
PS. I still don't get why you need this format though.

Inserting foreign key in django rest framework

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)

How can I make tastypie filter on a foreign field?

I have two models like this:
class CompanyResource(ModelResource):
class Meta:
queryset = Company.objects.all()
fields = ['title', 'latitude', 'longitude']
resource_name = 'company'
filtering = {
'latitude': ALL,
'longitude': ALL
}
class EventResource(ModelResource):
company = fields.ToOneField(CompanyResource, 'company', full=True)
class Meta:
fields = ['title', 'company']
queryset = Event.objects.all()
resource_name = 'event'
filtering = {
'company': ALL_WITH_RELATIONS
}
Then I try to access /api/v1/event/?format=json&company_latitude__within=2,3 or /api/v1/event/?format=json&company_latitude__lt=1 it isn't filtered on latitude:
{
"meta": {
"limit": 20,
"next": "/api/v1/event/?offset=20&limit=20&format=json",
"offset": 0,
"previous": null,
"total_count": 329
},
"objects": [
{
"company": {
"latitude": "1.30521100000000",
"longitude": "103.81116299999996",
"resource_uri": ""
},
"resource_uri": "/api/v1/event/16/",
"title": "50% off at Infusion#Dempsey, $50 for $100 worth of Fine Dining"
}
]
}
How can I make this work?
Oh it's because of two things. I can't do field__within in Django (why did I think that?) and it should've been /api/v1/event/?format=json&company__latitude__lt=2.