I have two models, I have to make an endpoint where the results of two tables should appear in the json, which have a fongeringkey that joins them.
My code is the following:
models.py
class Property(models.Model):
address = models.CharField(max_length=120)
city = models.CharField(max_length=32)
price = models.BigIntegerField()
description = models.TextField(blank=True, null=True)
year = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'property'
class StatusHistory(models.Model):
property = models.ForeignKey(Property, on_delete=models.CASCADE)
status = models.ForeignKey(Status, on_delete=models.CASCADE)
update_date = models.DateTimeField()
class Meta:
managed = False
db_table = 'status_history'
views.py
class StandardResultsSetPagination(PageNumberPagination):
page_size = 10
page_size_query_param = "page_size"
max_page_size = 1000
class PropertyListView(viewsets.ModelViewSet):
http_method_names = ['get', 'head']
serializer_class = PropertyListSerializer
queryset = Property.objects.all()
pagination_class = StandardResultsSetPagination
def get_serializer_class(self):
if self.action == 'list':
return PropertyListSerializer
return PropertyListSerializer
def get_queryset(self):
queryset = Property.objects.all()
if self.request.GET.get('year'):
queryset = queryset.filter(year=self.request.GET.get('year'))
if self.request.GET.get('city'):
queryset = queryset.filter(city=self.request.GET.get('city'))
if self.request.GET.get('status'):
#what would I do here?
pass
else:
queryset = queryset.order_by('-year')
return queryset
def list(self, request):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
serializers.py
class PropertyListSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Property
fields = ('id', 'address', 'city', 'price', 'description', 'year')
class StatusHistoryListSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = StatusHistory
fields = ('property', 'status', 'update_date')
I don't know how to filter by get with the parameters, city, year(model Property) and status(model StatusHistory).
You only need to filter based in the status of the history you can do the following:
if self.request.GET.get('status'):
queryset = queryset.filter(statushistory__status=self.request.GET.get('status'))
Related
I have two models, I have to make an endpoint where the results of two tables should appear in the json, which have a fongeringkey that joins them.
My code is the following:
models.py
class Property(models.Model):
address = models.CharField(max_length=120)
city = models.CharField(max_length=32)
price = models.BigIntegerField()
description = models.TextField(blank=True, null=True)
year = models.IntegerField(blank=True, null=True)
class Meta:
managed = False
db_table = 'property'
class StatusHistory(models.Model):
property = models.ForeignKey(Property, on_delete=models.CASCADE)
status = models.ForeignKey(Status, on_delete=models.CASCADE)
update_date = models.DateTimeField()
class Meta:
managed = False
db_table = 'status_history'
views.py
class StandardResultsSetPagination(PageNumberPagination):
page_size = 10
page_size_query_param = "page_size"
max_page_size = 1000
class PropertyListView(viewsets.ModelViewSet):
http_method_names = ['get', 'head']
serializer_class = PropertyListSerializer
queryset = Property.objects.all()
pagination_class = StandardResultsSetPagination
def get_serializer_class(self):
if self.action == 'list':
return PropertyListSerializer
return PropertyListSerializer
def get_queryset(self):
queryset = Property.objects.all()
if self.request.GET.get('year'):
queryset = queryset.filter(year=self.request.GET.get('year'))
if self.request.GET.get('city'):
queryset = queryset.filter(city=self.request.GET.get('city'))
if self.request.GET.get('status'):
queryse = queryset.filter(statushistory__status=self.request.GET.get('status'))
else:
queryset = queryset.order_by('-year')
return queryset
def list(self, request):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)
serializers.py
class PropertyListSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = Property
fields = ('id', 'address', 'city', 'price', 'description', 'year')
class StatusHistoryListSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = StatusHistory
fields = ('property', 'status', 'update_date')
I can correctly filter the parameters, city, year(model Property) and above all status(model StatusHistory) with the following code snippet:
if self.request.GET.get('status'):
queryset = queryset.filter(statushistory__status=self.request.GET.get('status'))
My problem is how I show in my JSON Response the new field fusion of the two models statushistory__statustry adding the following in serializers.py
class PropertyListSerializer(serializers.HyperlinkedModelSerializer):
statushistory_set =StatusHistoryListSerializer(many=True)
class Meta:
model = Property
fields = ('id', 'address', 'city', 'price', 'description', 'year', 'statushistory_set')
class StatusHistoryListSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = StatusHistory
fields = ('property', 'status', 'update_date')
Without any result.
I think you could set related_name attribute in the foreign key field.
class StatusHistory(models.Model):
property = models.ForeignKey(Property, on_delete=models.CASCADE, related_name = 'status_histories')
status = models.ForeignKey(Status, on_delete=models.CASCADE)
...
And in the PropertyListSerializer,
class PropertyListSerializer(serializers.HyperlinkedModelSerializer):
status_histories = StatusHistoryListSerializer(many=True, read_only = True)
class Meta:
model = Property
fields = ('id', 'address', 'city', 'price', 'description', 'year', 'status_histories')
You can also get property field as an object in the StatusHistory like the following:
class StatusHistoryListSerializer(serializers.HyperlinkedModelSerializer):
property = PropertyListSerializer(read_only = True)
class Meta:
model = StatusHistory
fields = ('property', 'status', 'update_date')
django rest framework gives me this error when i am trying to perform a post request to create a new order even though i specified the usr value in my serializer.save method.
here is my view
class OrderListCreateAPI(generics.ListCreateAPIView):
serializer_class = OrderSerializer
permission_classes = [IsOwner]
def get_queryset(self):
user = self.request.user
return Order.objects.filter(user= user)
def perform_update(self, serializer):
instance = serializer.save(user = self.request.user)
order = Order.objects.get(id = instance['id'].value)
order.item.quantity -= order.quantity
order.save()
my models.py
payment_methods = ((1,'credit card'),(2, 'cash'),(3, 'paypal'))
class Product(models.Model):
title = models.CharField(max_length=100)
description = models.TextField()
image = models.ImageField(upload_to = 'images/', height_field=300, width_field=300)
price = models.IntegerField()
quantity = models.IntegerField()
seller = models.ForeignKey(User, on_delete=models.CASCADE, related_name='products')
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Order(models.Model):
item = models.ForeignKey(Product, on_delete= models.CASCADE, related_name='orders')
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='orders')
quantity = models.IntegerField()
payment_options = models.CharField(choices=payment_methods, max_length=50)
Delivery = models.CharField(max_length=200)
my serializers
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ['id', 'title', 'description','image', 'price', 'quantity', 'seller', 'date']
read_only_fields = ['date', 'seller']
class OrderSerializer(serializers.ModelSerializer):
class Meta:
model = Order
fields = '__all__'
read_only_fields = ['user']
You need to use perform_create and not perform_update in your view.
class OrderListCreateAPI(generics.ListCreateAPIView):
serializer_class = OrderSerializer
permission_classes = [IsOwner]
def get_queryset(self):
user = self.request.user
return Order.objects.filter(user= user)
def perform_create(self, serializer):
instance = serializer.save(user = self.request.user)
order = Order.objects.get(id = instance['id'].value)
order.item.quantity -= order.quantity
order.save()
I have a problem with nested serializers.
In Shell everything works, but when I make an HTTP request i'ts always an error like "field required".
Models:
class Product(models.Model):
index = models.CharField(max_length=12, unique=True, db_index=True)
quantity = models.PositiveIntegerField(default=0)
def __str__(self):
return self.index
class Name(models.Model):
product = models.ForeignKey(Product, related_name='names', on_delete=models.CASCADE, null=True)
language = models.CharField(max_length=50, default="name_pl")
title = models.CharField(max_length=300, blank=True, null=True)
def __str__(self):
return self.language
Serializers:
class ProductSerializer(serializers.ModelSerializer):
names = NameSerializer(many=True)
class Meta:
model = Product
fields = ["index", "quantity", "names"]
def create(self, validated_data):
names = validated_data.pop('names')
product = Product.objects.create(**validated_data)
for name in names:
Name.objects.create(product=product, **name)
return product
views:
class NameView(viewsets.ModelViewSet):
queryset = Name.objects.all()
serializer_class = NameSerializer
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
filterset_fields = ('id',)
search_fields = ['id']
class ProductView(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_backends = [DjangoFilterBackend, filters.SearchFilter]
filterset_fields = ('id',)
search_fields = ['id']
permission_classes = (CustomDjangoModelPermissions,)
I'm trying to POST data:
data = {
"index": "11111",
"quantity": 1213,
"names": [
{"language": "DE","title": "GER"},
{"language": "CZ","title": "CZZ"}
]
}
RESPOND:
names field required
I've tried to override create in view, to "look" whats wrong:
def create(self, request):
data = request.data
serializer = ProductSerializer(data=data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=201)
return Response(request.data, status=400)
Then I get:
{'index': '11111', 'quantity': '1213', 'names': 'title'}
So it can't send all of data, so it can't validate.
Need help, pls ;)
Problem solved:
Just forget to add in request:
data = json.dumps(data)
Models.py
Categories:
class Category_product(models.Model):
category_name = models.CharField(max_length=200, unique=True)
def __str__(self):
return self.category_name
Products:
class Warehouse(models.Model):
category_product = models.ForeignKey(
Category_product, on_delete=models.CASCADE)
product_name = models.CharField(max_length=200, unique=True)
condition = models.BooleanField(default=False)
amount = models.IntegerField()
barcode = models.BigIntegerField()
f_price = models.CharField(max_length=255, null=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.product_name
urls.py
path('products-list/', views.WarehouseList.as_view()),
Views.py
class WarehouseList(generics.ListCreateAPIView):
queryset = Warehouse.objects.all()
serializer_class = WarehouseSerializer
Serializers.py
# SERIALIZER OF CATEGORY PRODUCTS
class Category_productSerializer(serializers.ModelSerializer):
class Meta:
model = Category_product
fields = ['id', 'category_name']
# SERIALIZER OF WAREHOUSE
class WarehouseSerializer(serializers.ModelSerializer):
category_name = serializers.ReadOnlyField(
source='category_product.category_name')
def get_serializer(self, *args, **kwargs):
if isinstance(kwargs.get('data', {}), list):
kwargs['many'] = True
return super(Category_productSerializer, self).get_serializer(*args, **kwargs)
class Meta:
model = Warehouse
fields = ['id', 'category_product', 'category_name', 'condition',
'product_name', 'amount', 'barcode', 'f_price', 'created_at', 'updated_at']
I want to get products by exact category
For example:
I have product category
{
"id": 1
"category_name": "Electronics"
}
If I send GET request to api/products-list/?cat=1
I want to get products which have this category
Create a get_queryset method as follow.
class WarehouseList(generics.ListCreateAPIView):
queryset = WareHouse.objects.all()
serializer_class = WarehouseSerializer
def get_queryset(self):
cat = self.request.query_params.get('cat', None)
if cat is not None:
self.queryset = self.queryset.filter(category_product__id=cat)
return self.queryset
I have already asked this question but I got no response can you please elaborate how should I proceed. I am trying to create the order but i stuck at logic.
models.py:
class OrderItem(models.Model):
image_number = models.CharField(max_length=20)
title = models.CharField(max_length=20)
image_size = models.CharField(max_length=50)
file_type = models.CharField(max_length=20)
price = models.CharField(max_length=50)
def __str__(self):
return self.title
class Order(models.Model):
user = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
items = models.ManyToManyField(OrderItem)
start_date = models.DateTimeField(auto_now_add=True)
ordered_date = models.DateTimeField()
ordered = models.BooleanField(default=False)
def __str__(self):
return str(self.user)
serializers.py:
class AddtocartSerializers(serializers.ModelSerializer):
class Meta:
model = OrderItem
fields = ['image_number','title','image_size','file_type','price']
class CartSerializers(serializers.ModelSerializer):
class Meta:
model = Order
fields = ['item',
'start_date',
'ordered_date'
]
views.py:
class AddtocartView(generics.CreateAPIView):
authentication_classes = []
permission_classes = []
pagination_class = None
queryset=OrderItem.objects.all()
serializer_class = AddtocartSerializers
class CartView(generics.ListCreateAPIView):
authentication_classes = []
permission_classes = []
pagination_class = None
queryset=Order.objects.all()
serializer_class = CartSerializers
def create(self, request):
return super(AddtocartView, self).create(request, *args, **kwargs)
urls.py:
path('addtocart/',views.AddtocartView.as_view(),name='addtocart'),
path('cart/',views.CartView.as_view(),name='cart'),
how can i create order after addtocart?
Yes you can do a post request to addtocart endpoint. But there must be logic written in addtocart endpoint to create an order and add OrderItem to the order. Then the order number must be returned to browser so that user can resume shopping / checkout the order.
After receiving the order number you can do some javascript stuff to show user his order details.
First of my suggestion for you don't to use ModelViewSet, because all you need is create and update for you view, for create use CreateAPIView, for update RetrieveAPIView.
you code will be like below:
class OrderItemSerializer(serializers.ModelSerializer)
class Meta:
model = OrderItem
fields = ['id', 'image_number', 'image_size', 'file_type', 'price']
class OrderCreateSerializer(serializers.ModelSerializer)
user = serializers.PrimaryKeyRelatedField(queryset=User.objects.all())
items = serializers.ListField(child=serializers.PrimaryKeyRelatedField(queryset=OrderItem.objects.all(), required=True), required=True)
ordered_date = serializers.DateField()
class Meta:
model = Order
fields = ['user', 'items', 'ordered_date']
def create(self, validated_data):
validated_data['user'] = self.context['request'].user
instance = Order.objects.create(**validated_data)
instance.save()
return instance
class CartView(CreateAPIView):
authentication_classes = []
queryset=Order.objects.all()
serializer_class = OrderCreateSerializer
def create(self, request):
return super(AddtocartView, self).create(request, *args, **kwargs)
ModelViewSet include more code which you don't use in you case. And also you can get user from request, and you can just add
validated_data['user'] = self.context['request'].user