I have the following models:
class Asset(models.Model):
isin = models.CharField(max_length=100)
asset_type = models.CharField(max_length=50)
last_price = models.FloatField
security_weight = models.FloatField
update_date = models.DateTimeField
def __str__(self):
return self.isin
class Meta:
ordering = ('isin',)
class PortfolioElement(models.Model):
nominal = models.FloatField
weight = models.FloatField
asset = models.OneToOneField(
Asset,
on_delete=models.CASCADE,
primary_key=True,
)
def __str__(self):
return self.asset.isin
class Meta:
ordering = ('asset',)
class Portfolio(models.Model):
number = models.CharField(max_length=100)
update_date = models.DateTimeField
elements = models.ManyToManyField(PortfolioElement)
def __str__(self):
return self.number
class Meta:
ordering = ('number',)
class Client(models.Model):
number = models.CharField(max_length=100)
update_date = models.DateTimeField
portfolios = models.ManyToManyField(Portfolio)
def __str__(self):
return self.number
class Meta:
ordering = ('number',)
and the following serializer:
class ClientSerializer(serializers.ModelSerializer):
class Meta:
model = Client
fields = ('number', 'portfolios')
depth = 1
However, I would like to see the actual data in the portfolios (and portfolio elements). But when I try to make a GET request on an arbitrary Client (by the (Client).number field) I can only see the following:
{
"number": "28101317",
"portfolios": [
{
"id": 14,
"number": "5471-339425",
"elements": [
{
"asset": 326
},
{
"asset": 327
}, ... (and so on)
How can a tweak my code, so that I also can get the actual "asset" information?
/Niclas
You can try this:
class AssetSerializer(serializers.ModelSerializer):
class Meta:
model = Asset
fields = '__all__'
class PortfolioElementSerializer(serializers.ModelSerializer):
asset = AssetSerializer()
class Meta:
model = PortfolioElement
fields = ('nominal', 'weight', 'asset')
class PortfolioSerializer(serializers.ModelSerializer):
elements = PortfolioElementSerializer(many=True)
class Meta:
model = Portfolio
fields = ('number', 'update_date', 'elements')
class ClientSerializer(serializers.ModelSerializer):
portfolios = PortfolioSerializer(many=True)
class Meta:
model = Client
fields = ('number', 'portfolios')
Related
I need the products that each user has ordered, like in the "UsuarioSerializer" i was thinking to put a field "productos" which is a list of "ProductoSeralizer", but the model "Usuario" do not have a direct relation with "ProductoSeralizer", so it give me an error when I try that, how can solve this? I need a JSON response like this:
[
{
"id": 1,
"cantidad_de_productos": 12,
"fecha": "2021-03-21T06:26:26.981487Z",
"correo": "user1#email.com",
"password": "pass",
"productos" : [
{},
{}
]
},
{
"id": 2,
"cantidad_de_productos": 0,
"fecha": "2021-03-21T06:26:56.700399Z",
"correo": "user2#email.com",
"password": "pass",
"productos" : [
{},
{}
]
}
]
models.py
class Entidad(models.Model):
fecha = models.DateTimeField(auto_now=True)
class Meta:
abstract = True
class Usuario(Entidad):
correo = models.EmailField(unique=True)
password = models.CharField(max_length=20)
def __str__(self) -> str:
return self.correo
class Orden(Entidad):
solicitante = models.ForeignKey(Usuario, related_name='ordenes', on_delete=models.CASCADE)
productos = models.ManyToManyField('Producto', through='Detalle')
class Producto(Entidad):
nombre = models.CharField(max_length=20, unique=True)
ordenes = models.ManyToManyField('Orden', through='Detalle')
def __str__(self) -> str:
return self.nombre
class Detalle(Entidad):
cantidad = models.PositiveIntegerField()
orden = models.ForeignKey(Orden, related_name='detalles', on_delete=models.CASCADE)
producto = models.ForeignKey(Producto, related_name='detalles', on_delete=models.CASCADE)
serializers.py
class ProductoSerializer(serializers.ModelSerializer):
class Meta:
model = Producto
fields = '__all__'
class ProductosUsuarioSerializer(serializers.ModelSerializer):
cantidad = models.IntegerField()
class Meta:
model = Producto
fields = '__all__'
class DetalleOrdenSerializer(serializers.ModelSerializer):
class Meta:
model = Detalle
exclude = ['orden']
class OrdenSerializer(serializers.ModelSerializer):
detalles = DetalleOrdenSerializer(many=True)
class Meta:
model = Orden
exclude = ['productos']
def create(self, validated_data):
detalles_data = validated_data.pop('detalles')
orden = Orden.objects.create(**validated_data)
for detalle_data in detalles_data:
Detalle.objects.create(orden=orden, **detalle_data)
return orden
class DetalleSerializer(serializers.ModelSerializer):
class Meta:
model = Detalle
fields = '__all__'
class UsuarioSerializer(serializers.ModelSerializer):
cantidad_de_productos = serializers.IntegerField()
class Meta:
model = Usuario
fields = '__all__'
views.py
class Usuario(ListCreateAPIView):
queryset = Usuario.objects.annotate(cantidad_de_productos=Coalesce(Sum('ordenes__detalles__cantidad'), 0))
serializer_class = UsuarioSerializer
You can add a SerializerMethodField field to serializer.
from models import Orden, Producto
class UsuarioSerializer(serializers.ModelSerializer):
cantidad_de_productos = serializers.IntegerField()
productos = serializers.SerializerMethodField()
class Meta:
model = Usuario
fields = '__all__'
def get_productos(self, obj):
ordenes = Orden.objects.filter(solicitante=obj.id)
# get all product ids from orders
product_ids = [product.id for orden in ordenes for product in orden.productos.all()]
# find products (It does not matter if there are duplicate ids, it will not repeat products.)
user_products = Producto.objects.filter(id__in=product_ids)
# format the response
products = [{
'id': product.id,
'name': product.nombre
} for product in user_products]
return products
The method is called by each returned user
I want to design solution for ordering items. I have endpoint that create orders BUT I need to to have items object in the order. let me show you the code
class ItemModel(models.Model):
name = models.CharField(max_length=50)
price = models.FloatField()
discretion = models.CharField(max_length=500)
available = models.BooleanField(default=True)
class OrderModel(models.Model):
phone = models.CharField(max_length=20)
delevary_time = models.DateTimeField()
class CartModel(models.Model):
order = models.ForeignKey(OrderModel, on_delete=models.CASCADE, related_name='order_m')
item = models.ForeignKey(ItemModel, on_delete=models.CASCADE, related_name='item_m')
I need endpoint that create order to me. her what I did
class CartSerializer(serializers.ModelSerializer):
class Meta:
model = CartModel
exclude = ['order',]
depth = 2
class OrderSerializer(serializers.ModelSerializer):
cart = serializers.SerializerMethodField()
class Meta:
model = OrderModel
fields = ['phone', 'state', 'delevary_time', 'cart']
def get_cart(self, obj):
cart = CartModel.objects.filter(order__id=obj.id)
serializer = CartSerializer(cart, many=True)
return serializer.data
this is the endpoint
router.register('order', OrderViewSet, 'api-order')
{
"phone": 124997988698,
"delevary_time": "2020-07-17T19:34:00",
"cart": [
{
"item": 1
},
{
"item": 2
}
]
}
when I post the json it don't save the cart it only save the oder phone and delevary_time. How I can save the cart at the same time
class CartSerializer(serializers.ModelSerializer):
class Meta:
model = CartModel
exclude = ['order',]
depth = 2
class OrderSerializer(serializers.ModelSerializer):
order_m = CartSerializer(many=True) # adding this
class Meta:
model = OrderModel
fields = ['phone', 'state', 'delevary_time', 'order_m']
def create(self, validated_data):
cart_data = validated_data.pop('order_m')
order = OrderModel.objects.create(**validated_data)
for c in cart_data:
CartModel.objects.create(order=order, **c)
return order
I want to serialize data in the format given below.I'm new to django-rest framework.I am working in a varsity project.So, little help will be appreciated.
{
{
"Series_name":"something",
"Home_team":"anything",
"Away_team":"sbh",
"players":[
{
"id":"1",
...
}
{
"id":"2",
...
}
]
},
{
"Series_name":"something2",
"Home_team":"anything",
"Away_team":"sbh",
"players":[
{
"id":"1",
...
}
{
"id":"1",
...
}
]
}
}
I have tried this.But this doesn't give satisfactory result.In fact it returns empty set.
class PlayersSerializer2(serializers.ModelSerializer):
class Meta:
model = Players
fields = ['name', 'country', 'image', 'role', 'credit']
class SeriesListSerializer2(serializers.ModelSerializer):
class Meta:
model = SeriesList
fields = '__all__'
class SeriesSquadsSerializer(serializers.ModelSerializer):
players = PlayersSerializer2(many=True, read_only=True)
series = SeriesListSerializer2(many=True, read_only=True)
class Meta:
model = SeriesSquads
fields = ['series', 'players']
these are the models I'm working with.I've 3 models SeriesList,Series_Squads and Players.Series_sqauds has unique pairs (Series_name,Players).It has two foreign keys pointing objects of SeriesList and Players.
class SeriesList(models.Model):
Series_name = models.CharField(max_length=250,
unique=True,primary_key=True)
No_of_matches = models.IntegerField()
Home_team = models.CharField(max_length=250)
Away_team = models.CharField(max_length=250)
class SeriesSquads(models.Model):
Series_name = models.ForeignKey(SeriesList, on_delete=models.CASCADE)
Squad_player = models.ForeignKey(Players, on_delete=models.CASCADE)
class Players(models.Model):
name = models.CharField(default="", max_length=250)
country = models.CharField(max_length=250)
image = models.CharField(max_length=500)
role = models.CharField(max_length=30)
credit = models.FloatField(default=None)
You can get user of SerializerMethodField to get your ForeignKey related objects into your serializer. Update your serializer so that:
class PlayersSerializer2(serializers.ModelSerializer):
class Meta:
model = Players
fields = ['name', 'country', 'image', 'role', 'credit']
class SeriesSquadsSerializer(serializers.ModelSerializer):
players = PlayersSerializer2(many=True, read_only=True)
Series_name = serializers.SerializerMethodField()
Home_team = serializers.SerializerMethodField()
Away_team = = serializers.SerializerMethodField()
class Meta:
model = SeriesSquads
fields = ['players']
def get_Series_name(self, obj):
return obj.Series_name.Series_name
def get_Home_team(self, obj):
return obj.Series_name.Home_team
def get_Away_team(self, obj):
return obj.Series_name.Away_team
I have the following Django models:
class Product(models.Model):
name = models.CharField(max_length=250, unique=True)
quantity = models.IntegerField(default=0)
class Order(models.Model):
products = models.ManyToManyField(
Product,
through='PositionInOrder'
)
discount = models.CharField(max_length=50, blank=True)
total_sum = models.DecimalField(max_digits=11, decimal_places=2, default=0)
class PositionInOrder(models.Model):
sale = models.ForeignKey(Order)
product = models.ForeignKey(Product)
quantity = models.PositiveIntegerField()
price = models.PositiveIntegerField()
And the following serializers:
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = '__all__'
class PositionInOrderSerializer(serializers.HyperlinkedModelSerializer):
sale = serializers.ReadOnlyField()
product = serializers.ReadOnlyField()
class Meta:
model = PositionInOrder
fields = "__all__"
class OrderSerializer(serializers.ModelSerializer):
products = PositionInOrderSerializer(many=True)
def create(self, validated_data):
products = validated_data.pop('products')
order = Order.objects.create(**validated_data)
return order
class Meta:
model = Order
fields = '__all__'
I want to create new Order. Send post query which contains this json:
{
"products": [{"id": 2606, "name": "Some name", "quantity": 140, "price": 250}],
"discount": "15",
"total_sum": 500
}
And in the create() method of a class OrderSerialization I obtain that products=: [OrderedDict([('quantity', 140), ('price', 250)])] and there are no information about product_id and product_name. How can I get them?
Try to explicit define id and name fields in PositionInOrderSerializer:
class PositionInOrderSerializer(serializers.HyperlinkedModelSerializer):
sale = serializers.ReadOnlyField()
id = serializers.IntegerField(source='product.id')
name = serializers.IntegerField(source='product.name')
class Meta:
model = PositionInOrder
fields = "__all__"
I got events that happen at locations:
class Event(models.Model):
title = models.CharField(max_length=200)
date_published = models.DateTimeField('published date',default=datetime.now, blank=True)
date_start = models.DateTimeField('start date')
date_end = models.DateTimeField('end date')
def __unicode__(self):
return self.title
description = models.TextField()
price = models.IntegerField(null=True, blank=True)
tags = TaggableManager()
location = models.ForeignKey(Location, blank=False)
class Location(models.Model):
location_title = models.CharField(max_length=200)
location_date_published = models.DateTimeField('published date',default=datetime.now, blank=True)
location_latitude = models.CharField(max_length=200)
location_longitude = models.CharField(max_length=200)
location_address = models.CharField(max_length=200)
location_city = models.CharField(max_length=200)
location_zipcode = models.CharField(max_length=200)
location_state = models.CharField(max_length=200)
location_country = models.CharField(max_length=200)
location_description = models.TextField()
def __unicode__(self):
return u'%s' % (self.location_title)
I can get the results of all via:
class EventSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.Field()
class Meta:
model = Event
depth = 2
fields = ('url','id','title','date_start','date_end','description', 'price', 'location')
Which outputs:
{
"url": "http://localhost:8000/api/event/3/",
"id": 3,
"title": "Testing",
"date_start": "2013-03-10T20:19:00Z",
"date_end": "2013-03-10T20:19:00Z",
"description": "fgdgdfg",
"price": 10,
"location": {
"id": 2,
"location_title": "Mighty",
"location_date_published": "2013-03-10T20:16:00Z",
"location_latitude": "37.767475",
"location_longitude": "-122.406878",
"location_address": "119 Utah St, San Francisco, CA 94103, USA",
"location_city": "San Francisco",
"location_zipcode": "94103",
"location_state": "California",
"location_country": "United States",
"location_description": "Some place"
}
},
However, I don't want it to grab all fields, as I don't need all of them. How can I define what fields should be retrieved from my nested object? Thanks!
Serializers can be nested, so do something like this...
class LocationSerializer(serializers.ModelSerializer):
class Meta:
model = Location
fields = (...)
class EventSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.Field()
location = LocationSerializer()
class Meta:
model = Event
fields = ('url','id','title','date_start','date_end','description', 'price', 'location')
I have been to this and did not get a perfect solution, But I did something you may check for it.
This method will not create nested serializers
**class LocationSerializer(serializers.ModelSerializer):**
class Meta:
model = Location
fields = (...) #does not matter
exclude = (...) #does not matter
class EventSerializer(serializers.ModelSerializer):**
loc_field_1 = serializers.CharField(required=False,*source='location.loc_field_1'*)
loc_field_2 = serializers.CharField(required=False,*source='location.loc_field_2'*)
***#ADD YOUR DESIRE FIELD YOU WANT TO ACCESS FROM OTHER SERIALIZERS***
class Meta:
model = Event
fields =('url','id','title','date_start','date_end','description', 'price', 'location')
I found this question when I was trying to figure out how to exclude certain fields from a serializer only when it was being nested. Looks like Tasawer Nawaz had that question as well. You can do that by overriding get_field_names. Here's an example based on Tom Christie's answer:
class LocationSerializer(serializers.ModelSerializer):
class Meta:
model = Location
fields = (...)
exclude_when_nested = {'location_title', 'location_date_published'} # not an official DRF meta attribute ...
def get_field_names(self, *args, **kwargs):
field_names = super(LinkUserSerializer, self).get_field_names(*args, **kwargs)
if self.parent:
field_names = [i for i in field_names if i not in self.Meta.exclude_when_nested]
return field_names
class EventSerializer(serializers.HyperlinkedModelSerializer):
id = serializers.Field()
location = LocationSerializer()
class Meta:
model = Event
fields = ('url','id','title','date_start','date_end','description', 'price', 'location')