I have two tables: Event and EventTicket. I have to return total transactions and total tickets sold of each event. I am trying to achieve this using Django serializers. Using only serializers, I need to find the following:
1. total tickets sold: count of items in EventTicket table for each event
2. total transactions: sum of total_amount of items in EventTicket table for each event where payment_status: 1
I read about SerializerMethodField but couldn't find a solution specific to this scenario.
class Event(models.Model):
name = models.CharField(max_length=100, null=False, blank=False)
description = models.TextField(null=False, blank=False)
date_time = models.DateTimeField()
class EventTicket(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
event = models.ForeignKey(Event,on_delete=models.CASCADE)
payment_status = models.SmallIntegerField(default=0, null=False, blank=False) ## payment_success: 1, payment_failed: 0
total_amount = models.FloatField()
date_time = models.DateTimeField()
My desired output is:
"ticket_details": [
{
"event_id": 1,
"event_name": Event-1,
"total_transactions": 10000, ## Sum of all ticket amounts of event_id: 1, where payment_status: 1
"total_tickets": 24, ## Count of all tickets that belong to event_id: 1
},
{
"event_id": 2,
"event_name": Event-2,
"total_transactions": 10000, ## Sum of all ticket amounts of event_id: 2, where payment_status: 1
"total_tickets": 24, ## Count of all tickets that belong to event_id: 2
}]
This is what I have done:
models.py:
class EventTicket(models.Model):
event = models.ForeignKey(Event,on_delete=models.CASCADE, related_name='event_tickets')
serializers.py:
class EventListSerializer(serializers.ModelSerializer):
# ticket_id = serializers.IntegerField(source='id')
# event_id = serializers.PrimaryKeyRelatedField(source='event', read_only=True)
# event_name = serializers.PrimaryKeyRelatedField(source='event.name', read_only=True)
total_transactions = serializers.SerializerMethodField()
total_tickets = serializers.SerializerMethodField()
class Meta:
model = Event
fields = ('total_transactions', 'total_tickets')
def get_total_transactions(self, obj):
return obj.event_tickets.all().aggregate(sum('total_amount'))['total_amount__sum']
def get_total_tickets(self, obj):
return obj.event_tickets.count()
You can do it as property in the model like this:
class EventTicket(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE)
event = models.ForeignKey(Event,on_delete=models.CASCADE)
payment_status = models.SmallIntegerField(default=0, null=False, blank=False) ## payment_success: 1, payment_failed: 0
total_amount = models.FloatField()
date_time = models.DateTimeField()
#property
def total_transactions(self):
if self.payment_status:
return self.event.eventTicket_set.count()
return -1
One solution could be like this with SerializerMethodField:
class EventSerializer(serializers.ModelSerializer):
total_transactions = serializers.SerializerMethodField()
total_tickets = serializers.SerializerMethodField()
class Meta:
model = Event
fields = ('id', 'name', 'total_transactions', 'total_tickets')
def get_total_transactions(self, obj):
return obj.tickets.all().aggregate(Sum('total_amount'))['total_amount__sum']
def get_total_tickets(self, obj):
return obj.tickets.count()
Note:
Add related name tickets in Event Foreign Key in EventTicket model:
event = models.ForeignKey(Event, on_delete=models.CASCADE, related_name='tickets')
Related
I am doing an ecommerce project as my first django project and I am having some trouble on how to calculate my actual price and my discount price if there is a discount price so what I want to do is that if the admin adds a discount to a product I want to add a value to a field inside a model called discount price and in that model I want to calculate how much discount percentage the admin has put in and what the discounted price would be after applying the discount percentage
ps: English is my second language and I'm sorry if you were not able to understand
tldr : I want to calculate the price and the discount percentage and make the value it to another field in the model called discount price
this is my models for the product and discounts(please point out how I should improve and any of my mistakes)
from django_extensions.db.fields import AutoSlugField
from django.core.validators import MinValueValidator, MaxValueValidator
# Create your models here.
class Products(models.Model):
product_name = models.CharField(max_length=200, unique=True)
slug = AutoSlugField(populate_from=['product_name'], unique=True)
description = models.TextField(max_length=500, blank=True)
price = models.IntegerField(validators = [MinValueValidator(0)])
discount_price = models.IntegerField(validators = [MinValueValidator(0)],null=True)
image1 = models.ImageField(upload_to='photos/Products')
image2 = models.ImageField(upload_to='photos/Products')
image3 = models.ImageField(upload_to= 'photos/Products')
image4 = models.ImageField(upload_to= 'photos/Products')
stock = models.IntegerField(validators=[MinValueValidator(0)])
Is_available = models.BooleanField(default=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
created_date = models.DateTimeField(auto_now_add=True)
modified_date = models.DateTimeField(auto_now=True)
class Meta:
verbose_name = 'products'
verbose_name_plural = 'products'
def get_url(self):
return reverse('product_page',args=[self.category.slug, self.slug])
def __str__(self):
return self.product_name
class OfferProduct(models.Model):
product = models.OneToOneField(Products, related_name='category_offers', on_delete=models.CASCADE)
discount = models.IntegerField(validators=[MinValueValidator(0),MaxValueValidator(99)],null=True,default = 0)
is_active = models.BooleanField(default =True)
class Meta:
verbose_name = 'Offer Product'
verbose_name_plural = 'Offer Products'
def __str__(self):
return self.product.product_name
========= model.py =================
class ProductModel(models.Model):
name= models.CharField(max_length=300)
og_price = models.IntegerField()
discount = models.IntegerField()
discounted_price = models.IntegerField(null=True)
sell_price = models.IntegerField(null=True)
created_at = models.DateField(auto_now_add=True)
#property
def discounted_price(self):
return ((self.og_price)*(self.discount))/100
#property
def sell_price(self):
return (self.og_price)-(self.discounted_price)
=========== Output ============
example : price : 1000, discount: 100 so the percentage is 10%
you can add a property in the OfferProduct:
#property
def discount_percentage(self):
return (100 * discount)/product.price #add your logic
i have table "Books" with some fields, and i have table "Prices", each customer have self price, i don't know how get price for definitely client, how i must configure serializer? please, help me,
for example:
Book1 have 2 prices: Price1 - 100$, Price2 - 150$
Customer1 must buy with just Price1,
Customer2 must buy with just Price2
i need get for first Customer json like:
[{"code":"УТ-11111","author":"Пушкин","title":"Книга 1","price":"100"}]
for Second Customer
[{"code":"УТ-11111","author":"Пушкин","title":"Книга 1","price":"150"}]
.
class Book(models.Model):
title = models.CharField('Заголовок', max_length=250)
code = models.CharField('Код', primary_key=True, max_length=10)
isbn = models.CharField('ISBN', max_length=18, null=True, blank=True)
ean13 = models.CharField('EAN-13', max_length=13, null=True, blank=True)
author = models.ForeignKey(Author, on_delete=models.SET_NULL, null=True, blank=True, verbose_name='Автор')
class PricesName(models.Model):
name = models.CharField('Вид цены', max_length=20)
def __str__(self):
return self.name
class Price(models.Model):
book = models.ForeignKey(Book, on_delete=models.CASCADE)
PricesName = models.ForeignKey(PricesName, on_delete=models.CASCADE)
price = models.FloatField()
def __str__(self):
return self.book.title+" "+self.PricesName.name
######### Serializers.py ##########################
class BookSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField()
class Meta:
model = Book
fields = #'__all__'
#### API.py ####
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
permission_classes = [
permissions.AllowAny
]
serializer_class = BookSerializer
filter_backends = (DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter)
filter_fields = ('title', 'author')
search_fields = ('title', 'author')
pagination_class = StandardResultsSetPagination
problem is solved
class BookSerializer(serializers.ModelSerializer):
prices = serializers.SerializerMethodField()
def get_prices(self, serializer):
#PriceName__id - price number allowed to current Customer
book_price = Price.objects.filter(book=serializer.code, PricesName__id=2).first()
try:
price = getattr(book_price, "price")
except:
price = 0
return price
class Meta:
model = Book
fields = "__all__"
I'm using Django as Backend, PostgresSQl as DB and HTML, CSS and Javascript as Frontend. I want to show Children Table in DJANGO REST FRAMEWORK, as I'm using Multi Table Inheritance.
As we can see in above image, that only Product list is been displayed but not the children table. I want to show all the data which is selected by customer. I'm showing Cart Product in DRF
views.py
class AddToCartView(TemplateView):
template_name = "status.html"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
product_id = self.kwargs['pk']
product_obj = Product.objects.get(id = product_id)
cart_id = self.request.session.get("cart_id", None)
if cart_id:
cart_obj = Cart.objects.get(id = cart_id)
this_product_in_cart = cart_obj.cartproduct_set.filter(product = product_obj)
if this_product_in_cart.exists():
cartproduct = this_product_in_cart.last()
cartproduct.quantity += 1
cartproduct.subtotal += product_obj.price
cartproduct.save()
cart_obj.total += product_obj.price
cart_obj.save()
else:
cartproduct = CartProduct.objects.create(
cart = cart_obj, product = product_obj, rate = product_obj.price, quantity = 1, subtotal = product_obj.price)
cart_obj.total += product_obj.price
cart_obj.save()
else:
cart_obj = Cart.objects.create(total=0)
self.request.session['cart_id'] = cart_obj.id
cartproduct = CartProduct.objects.create(
cart = cart_obj, product = product_obj, rate = product_obj.price, quantity = 1, subtotal = product_obj.price)
cart_obj.total += product_obj.price
cart_obj.save()
return context
API View (views.py)
#api_view(['GET'])
def showproduct(request):
result = CartProduct.objects.all()
serialize = productserializers(result, many = True)
return Response(serialize.data)
models.py
class Product(models.Model):
name = models.CharField(max_length=1330)
image_src = models.URLField(max_length=1330,null=True, blank=True)
link_href = models.URLField(max_length=1330,null=True, blank=True)
brand = models.CharField(max_length = 1330, null=True, blank=True)
price = models.DecimalField(max_digits=15, decimal_places=2)
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('-created',)
class Refrigerator(Product):
series = models.CharField(max_length = 300, null=True, blank=True)
model = models.CharField(max_length = 300, null=True, blank=True)
...
class Cart(models.Model):
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
total = models.PositiveIntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return "Cart: " + str(self.id)
class CartProduct(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
rate = models.PositiveIntegerField()
quantity = models.PositiveIntegerField()
subtotal = models.PositiveIntegerField()
def __str__(self):
return "Cart: " + str(self.cart.id) + " CartProduct: " + str(self.id)
I want to show refrigerator details aslo in DRF which is been selected by customer.
serializer.py
class productserializers(serializers.ModelSerializer):
class Meta:
model = CartProduct
fields = "__all__"
depth = 2
You can try this, in your Product(models.Model)
class Meta:
abstract = True
you can refer here for explanation : here
(I should have comment this but don't have enough reputations for that :/)
Note: IF INFORMATION BELOW IS NOT CLEAR TO UNDERSTAND - PLEASE ASK ME, I WILL UPDATE AND POST INFORMATION YOU NEED | It is important for me
In Warehouse(models.Model) I have amount attribute and
in ChosenProduct(models.Model) - quantity
I'm trying to get amount in Warehouse through chosen_products instance in App_formSerializer to add the quantity of chosen_product
But I can not get the chosen_products objects from instance
--> below Out:
class WarehouseSerializer(serializers.ModelSerializer):
category_name = serializers.ReadOnlyField(
source='category_product.category_name')
posted_user = serializers.ReadOnlyField(
source='posted_user.username')
class Meta:
model = Warehouse
fields = ['id', 'category_product', 'category_name', 'condition',
'product_name', 'amount', 'barcode', 'f_price', 'created_at', 'updated_at', 'posted_user']
class ChosenProductSerializer(serializers.ModelSerializer):
product_info = WarehouseSerializer(source='product', read_only=True)
period_info = Product_periodSerializer(source='period', read_only=True)
class Meta:
model = ChosenProduct
exclude = ('app_form',)
class App_formSerializer(serializers.ModelSerializer):
chosen_products = ChosenProductSerializer(many=True)
def update(self, instance, validated_data):
instance.terminated = validated_data.get('terminated', instance.terminated)
if instance.terminated == True :
print('-----------TRUE--------------------')
print(instance.chosen_products)
print('-----------PRINT--------------------')
instance.save()
return instance
class Meta:
model = App_form
fields = '__all__'
Out
-----------TRUE--------------------
creditapi.ChosenProduct.None
-----------PRINT--------------------
QUESTION UPDATED
models.py
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)
posted_user = models.ForeignKey(User, on_delete=models.CASCADE, default=1)
def __str__(self):
return self.product_name
class App_form(models.Model):
phone_regex = RegexValidator(regex=r'^\+?1?\d{9,12}$', message="Phone number must be entered in the format: '998981234567'. Up to 12 digits allowed.")
terminated = models.BooleanField(default=False)
name = models.CharField(max_length=150)
phone_number = models.CharField(validators=[phone_regex], max_length=13)
def __str__(self):
return self.surname
class ChosenProduct(models.Model):
product = models.ForeignKey(Warehouse, on_delete=models.CASCADE)
quantity = models.IntegerField()
app_form = models.ForeignKey(App_form, on_delete=models.CASCADE, related_name='chosen_products')
def __str__(self):
return self.product.product_name
If you write instance.chose_products you access the manager, not the QuerySet that contains the items. You can use .all() to obtain the QuerySet with all the objects:
print(instance.chosen_products.all())
If you access a ForeignKey in reverse, you have a manager, since zero, one, or more elements can refer to the instance.
You can for example aggregate over the chose_products, for example if you want to retrieve the number of related chose_products, you can use:
print(instance.chosen_products.count())
I would however advise not store (aggregated) data in the App_form, but aggregate data when you need it. Data duplication is an anti-pattern, and it turns out it is hard to keep data in sync.
I have these models:
product.py
class Product(models.Model):
product_title = models.CharField(max_length=100)
product_price = models.DecimalField(max_digits=12, decimal_places=2)
product_multiple = models.PositiveIntegerField(blank=True, null=True)
order_item.py
class OrderItem(models.Model)
order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name='items', null=True, blank=True)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
price = models.FloatField(default=0)
quantity = models.BigIntegerField(default=1)
profitability = models.CharField(max_length=50, null=True, blank=True)
I want to validate in serializers.py if the order_item.quantity % product_multiple != 0
serializers.py
class OrderItemSerializer(serializers.ModelSerializer):
class Meta:
model = OrderItem
fields = ('id', 'order', 'product', 'price',
'quantity', 'profitability')
def validate_quantity(self, value):
data = self.get_initial()
quantity = data.get("quantity")
# This is where the `product.product_multiple` value is needed
if int(quantity) % product.product_multiple != 0:
raise serializers.ValidationError("Quantity is not multiple")
return value
How can I get the actual product_multiple inside the validate function?
As you are doing a validation that involves multiple fields, you should use the validate method as follows:
def validate(self, data):
quantity = data.get('quantity')
product = data.get('product')
if int(quantity) % product.product_multiple != 0:
raise serializers.ValidationError("Quantity is not multiple")
return data