How to join 3 tables in query with Django, combined select related and prefetch_related - django-models

I have tree models
class Category(models.Model):
name = models.CharField(max_length=60)
class Product(models.Model):
description = = models.CharField(max_length=255)
category = models.ForeignKey(Category, related_name='products')
class Inventory(models.Model):
userReservation = models.ForeignKey(User)
Product=models.ForeignKey(Product related_name='products_reservation')
Quantity = models.IntegerField()
I want to get all product by category, with quantity registered in inventory, for the user and the product
{
"id": 1,
"name": "Corbata",
"products": [{
"id": 10,
"description": "shoes",
"quantitybyInventory": 3
},
{
"id": 9,
"description": "shirt",
"quantitybyInventory": 1
}]}
I have a view with this class
views.py
class inventoryList(generics.ListCreateAPIView):
queryset = Category.objects.prefetch_related('products')
serializer_class = CategorybyProductSerializer
def get_object(self):
queryset = self.queryset()
obj = get_object_or_404(queryset)
return obj
And my serializer
class CategorybyProductSerializer(serializers.ModelSerializer):
products = ProductSerializer(many=True)
class Meta:
model = Category
fields = ('id', 'name', 'products')
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ('id', 'description')
but I can not show the amount of the inventory table
this query just show me it
{
"id": 1,
"name": "Corbata",
"products": [{
"id": 10,
"description": "shoes"
},
{
"id": 9,
"description": "shirt"
}
]
}

I use SerializerMethodField, and this post
class ProductbyUserSerializer(serializers.ModelSerializer):
quantitybyInventory = serializers.SerializerMethodField(read_only=True)
def get_quantitybyInventory(self, product):
return product.products_reservation.filter(userReservation = self.context['request'].user).count()
class Meta:
model = Product
fields = ('id', 'description', 'quantitybyInventory')

Related

How to include related models using Django Rest Framework ListAPIView

Having 2 models and i need a list, a single queryset of lists that will combine all related fields from the 2 models.
class Product(models.Model):
name = models.CharField(...)
price= models.Decimal(...)
image = models.ImageField(...)
description2 = models.TextField(....)
class Order(models.Model):
buyer = models.CharField(...)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
have it return something that includes the full related model. A queryset Lists of ORDER with this result
{
"id": 1,
"buyer": 1,
"product": 3,
"name": "Product 1",
"image": "url",
"price": 10.50
},
{
"id": 2,
"buyer": 2,
"product": 2,
"name": "Product 2",
"image": "url",
"price": 6.50
},
OR
{
"id": 1,
"buyer": 1,
"product": [
{
'id': 1,
'name': 'Product 1',
'image': "url",
'price': 10.50
}],
},
{
"id": 2,
"buyer": 2,
"product": [
{
'id': 2,
'name': 'Product 2',
'image': "url",
'price': 6.50
}],
}
Is this possible?
First, you need to define the serializer in serializers.py file.
from rest_framework import serializers
from .models import Product, Order
class ProductSerializer(serializers.ModelSerializer):
class Meta:
fields = "__all__"
model = Product
class OrderSerializer(serializers.ModelSerializer):
product = ProductSerializer(read_only = True)
class Meta:
fields = ("buyer", "product", )
model = Order
And then, you need to create the ListAPIView for Order in views.py file.
from rest_framework import generics, mixins
from .models import Order
from .serializers import OrderSerializer
class OrderView(mixins.ListModelMixin, generics.GenericAPIView):
queryset = Order.objects.all()
serializer_class = OrderSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
Last you need to add the api url in urls.py,
from .views import *
urlpatterns = [
path('orders', OrderView.as_view(), name="order")
]

Submitting SUMMARY Data from Django to React using DRF

I'm starting to test some API data between django and React using Rest API. I'm able to submit this data between Djnago model and React front end.
[
{
"id": 1,
"gender": "Male",
"age": 40,
"updated": "2022-04-25T18:55:23.304456Z",
"created": "2022-04-25T14:07:48.282139Z"
},
{
"id": 2,
"gender": "Male",
"age": 33,
"updated": "2022-04-25T18:55:23.304456Z",
"created": "2022-04-25T14:07:48.282139Z"
},
{
"id": 3,
"gender": "Female",
"age": 22,
"updated": "2022-04-25T18:55:23.304456Z",
"created": "2022-04-25T14:07:48.282139Z"
},
{
"id": 4,
"gender": "Female",
"age": 33,
"updated": "2022-04-25T18:55:23.304456Z",
"created": "2022-04-25T14:07:48.282139Z"
},
]
My goal is not to submit this raw data, but instead to submit summary data (data analysis) that calculates the average age for males and females, so I should be getting something like this:
[
{
"gender": "Male",
"average_age": 36.5,
},
{
"gender": "Male",
"average_age": 27.5,
}
]
in TestDrf.js
import React from "react"
import axios from 'axios'
export default function App() {
const [incomingData, setIncomingData] = React.useState([])
React.useEffect(function() {
console.log('effect ran')
axios.get('http://127.0.0.1:8000/test/')
.then(data => setIncomingData(data))
}, [])
return (
<div>
<pre>{JSON.stringify(incomingData.data, null, 2)}</pre>
</div>
)
}
in views.py
from rest_framework.response import Response
from rest_framework.decorators import api_view
from .models import Test
from .serializers import TestSerializer
#api_view(['GET'])
def getData(request):
test_data= Test.objects.all()
result = Test.objects.values('gender')
.annotate(average_age=Avg('age'))
serializer = TestSerializer(test_data, many=True)
return Response(serializer.data)
Where should I be making these cross tabulations? on the backend or front end?
if on the backend should I be creating new models for the summary data?
I tried looking online for advice on this but I was unlucky!
A Django query can be used in the backend to perform aggregation; new model is not needed for summary data.
An SQL query for getting average age by gender from a 'person' table would be something like this.
SELECT gender, AVG(age) AS average_age
FROM person
GROUP BY gender;
The equivalent Django query would be similar to this.
from django.db.models import Avg
result = Person.objects.values('gender')
.annotate(average_age=Avg('age'))
UPDATE: Adding a class based API view
class GetData(APIView):
def get(self):
result = Test.objects.values('gender').annotate(average_age=Avg('age'))
response_data = {}
response_data['data'] = list(result)
return Response(response_data, status=status.HTTP_200_OK)
urls.py should be updated to use this API view.
path('getdata/', GetData.as_view()),

How to access forgin key value in react from django api

I have django api in which i have post model which is linked to comments and categories table by forgin key now i am feching data for post detail and when i try to access category of that post it return s id and i want to access name of category this is my post list view
{
"id": 4,
"title": "BLOG PAGE",
"body": "testing",
"owner": "ankit",
"comments": [],
"categories": [
2
],
"created_at": "2021-05-07T17:22:32.989706Z"
},
{
"id": 5,
"title": "Test Post",
"body": "This is a test Post",
"owner": "ankit",
"comments": [],
"categories": [
2
],
and this is my categories
[
{
"id": 2,
"name": "Python",
"owner": "ankit",
"posts": [
4,
5,
6,
8
]
}
]
and this is my post detail component
export class PostDetail extends React.Component {
constructor(props) {
super(props);
const ID = this.props.match.params.id
this.state = {
data: [],
loaded: false,
placeholder: "Loading"
};
}
formatDate(dateString){
const options = { year: "numeric", month: "long", day: "numeric" }
return new Date(dateString).toLocaleDateString(undefined, options)
}
componentDidMount() {
fetch(`${Url}posts/${this.props.match.params.id}`)
.then(response => {
if (response.status > 400) {
return this.setState(() => {
return { placeholder: "Something went wrong!" };
});
}
return response.json();
})
.then(data => {
this.setState(() => {
return {
data,
loaded: true
};
});
});
}
render(){
return(
<>
<h1 className="main-title">{this.state.data.title}</h1>
<div className="container">
<div className="box1">
<h2>Categories</h2>
<div className="categories">{this.state.data.categories}</div>
</div>
</>
);
}
}
and i am getting output as 2 when i try to get data like mention above
i thought i can access it by putting . in front of categories eg. categories.name but it returns TypeError error
TypeError: Cannot read property 'name' of undefined
this are my serializers
class CategorySerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
posts = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Category
fields = ['id', 'name', 'owner', 'posts']
class PostSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
comments = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
class Meta:
model = Post
fields = ['id', 'title', 'body', 'owner', 'comments', 'categories','created_at']
i try to access category of that post it return s id and i want to access name of category this is my post list view
1. For getting only the name of the category.
You can use the SlugRelatedField.
Modify your PostSerializer like so:
class PostSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
comments = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
categories = serializers.SlugRelatedField(many=True, read_only=True, slug_field='name')
class Meta:
model = Post
fields = ['id', 'title', 'body', 'owner', 'comments', 'categories','created_at']
Example JSON response:
{
"id": 4,
"title": "BLOG PAGE",
"body": "testing",
"owner": "ankit",
"comments": [],
"categories": [
"Python"
],
"created_at": "2021-05-07T17:22:32.989706Z"
},
2. To nest full Category objects
class PostSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
comments = serializers.PrimaryKeyRelatedField(many=True, read_only=True)
categories = CategorySerializer(many=True)
class Meta:
model = Post
fields = ['id', 'title', 'body', 'owner', 'comments', 'categories','created_at']
Example JSON response:
{
"id":4,
"title":"BLOG PAGE",
"body":"testing",
"owner":"ankit",
"comments":[],
"categories":[
{
"id":2,
"name":"Python",
"owner":"ankit",
"posts":[
4,
5,
6,
8
]
}
],
"created_at":"2021-05-07T17:22:32.989706Z"
}

How to convert String list to JSON Array Groovy

This is the problem that I'm trying to resolve. I have a list of map that I want to convert into JSON array in Groovy.
The list is:
List<Map<String, String>> studentList = [{id=1,name=John,email=john#google.com},{id=2,name=Peter,email=peter#google.com},{id=3,name=James,email=james#google.com}]
Desired JSON output is:
{
students: [{
"id" = "1",
"name" = "John",
"contact": {
"email": "john#google.com"
}
}, {
"id" = "2",
"name" = "Peter",
"contact": {
"email": "peter#google.com"
}
}, {
"id" = "3",
"name" = "James",
"contact": {
"email": "james#google.com"
}
}
]
}
My code only generates 1 student. Can anyone help me please?
def builder = new JsonBuilder()
for (Map student: studentList) {
builder.students {
id student.id
name student.name
contact {
email student.email
}
}
}
println builder.toPrettyString()
Appreciate your time and advice. Thank you.
Pass a list to the builder
You don't need to iterate through the list, you can pass a list to the builder,
using JsonBuilder's implicit call() method.
def builder = new JsonBuilder()
builder {
students builder( studentList )
}
public Object call( List list )
A list of elements as arguments to the JSON builder creates a root JSON array
See the JsonBuilder Groovydoc page for details of the various call()
methods.
Example code
In this example I've fixed up your map, and introduced a small Student class, to
simplify the code.
import groovy.json.JsonBuilder
class Student { int id; String name; String email }
studentList = [
new Student( id:1, name:'John', email:'john#google.com' ),
new Student( id:2, name:'Peter', email:'peter#google.com' ),
new Student( id:3, name:'James', email:'james#google.com' )
]
def builder = new JsonBuilder()
builder {
students builder( studentList )
}
println builder.toPrettyString()
Resulting JSON
{
"students": [
{
"id": 1,
"email": "john#google.com",
"name": "John"
},
{
"id": 2,
"email": "peter#google.com",
"name": "Peter"
},
{
"id": 3,
"email": "james#google.com",
"name": "James"
}
]
}
I have solved it with ff code.
def students = []
def builder = new JsonBuilder()
for (Map student: studentList) {
builder {
id student.id
name student.name
contact {
email student.email
}
}
students.add(builder.toString())
}
def jsonSlurper = new JsonSlurper()
def items = jsonSlurper.parseText(students.toString())
def json = new JsonBuilder()
json "students": items
println json.toPrettyString()

Json Array with Flask-Restless for Datatables.net

I want to use Datatables.net and it requires and json array like the below
{
"data": [
[
"9",
"1",
"sala",
"zeus",
"lights",
"3",
"7",
"tcp",
]
}
But On Flask-Restfull, the nearest I could get from this is
{
"objects": [
{
"channel": 9,
"id": 1,
"location": "sala",
"name": "zeus",
"purpose": "lights",
"role_id": 3,
"role_permissions": 7,
"type": "tcp"
}
}
with this set-up:
manager.create_api(Device,
results_per_page=1000,
primary_key='id',
exclude_columns=['user_devices','role','num_results'],
app=app,
# exclude_columns=['role_id'],
preprocessors=dict(GET_SINGLE=[auth_func],
GET_MANY=[auth_func]),
postprocessors={
'GET_MANY': [api_post_get_many]
}
)
def api_post_get_many(result=None, **kw):
for key in result.keys():
if key != 'objects':
del result[key]
and this model:
class Device(db.Model):
__tablename__ = 'devices'
__table_args__ = (db.UniqueConstraint('id', 'name', 'purpose', 'channel', 'type','location'),
db.ForeignKeyConstraint(
['role_id', 'role_permissions'],
['roles.id', 'roles.permissions']
)
)
id = db.Column(db.Integer, primary_key=True)
purpose = db.Column( db.String(64))
type = db.Column( db.String(64))
name = db.Column(db.String(64))
location = db.Column(db.String(64))
channel = db.Column( db.Integer)
role_id = db.Column(db.Integer)
role_permissions = db.Column(db.Integer)
role = db.relationship('Role', backref=db.backref('devices'))
Is there a way to make FlaskRESTLESS return a json array instead of a json object? Or should I try to serialize the data with python??

Resources