Output the count from two Models in the same view in Django - python

class Album(models.Model):
title = models.CharField(max_length=100, blank=True, default='')
price = models.FloatField()
upload_time = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ('upload_time',)
class Status(models.Model):
user_id = models.IntegerField()
album_id = models.IntegerField()
favorite = models.BooleanField(default=False)
purchase = models.BooleanField(default=False)
history = models.BooleanField(default=False)
def __str__(self):
return self.user_id
in a ModelViewSet I wrote like this:
class index(viewsets.ModelViewSet):
serializer_class = AlbumSerializer
queryset = Album.objects.all()
As the image shown above, I need output the count of purchases of each Album, e.g. Album 1 has been purchased 4 times, Album 3 has been purchased 1 time.
But right now, my index view only generate the fields in Album data model.
What should I do to implement this, add the purchase number for each Album? Need your help...

You can add something like this to your serializer class to count it:
class AlbumSerializer(serializers.ModelSerializer):
purchase_count = serializers.SerializerMethodField(read_only=True)
def get_purchase_count(self, obj):
return Status.objects.filter(album_id=obj.id, purchase=True).count()

Connect your Album and User models as many to many relation:
class Status(models.Model):
user = models.ForeignKey('userapp.User', on_delete=models.CASCADE)
album = models.ForeignKey('albumapp.Album', on_delete=models.CASCADE)
favorite = models.BooleanField(default=False)
purchase = models.BooleanField(default=False)
history = models.BooleanField(default=False)
Don't forget to apply migrations.
Do query with annotation:
queryset = Album.objects.all().annotate(
purchase_count=Count('status', filter=Q(status__purchase=True)),
favorite_count=Count('status', filter=Q(status__favorite=True)),
history_count=Count('status', filter=Q(status__history=True)),
)
In attributes purchase_count, favorite_count and history_count you'll have corresponding values.

Related

Django Admin One-To-Many-To-One (Site->Product->Price) Relationship

I'm developing a web app for fun and the goal is to use Django Admin and only Django Admin, without any custom templates (yet). I'm unable to figure out how I should structure my models.py and admin.py files, where what I'm trying to do is:
There are many items and many departments: Each item can only belong to one department and each department can have several items. This currently works.
Now, what I can't seem to figure out is:
There are many sites. Each site can have many items, but the PRICE of each item at each site can be different. For example:
Site #123 can have a can of coke for $1.00
Site #124 can also have a can of coke, but at a price of $0.95
Site #123 can have a bag of chips for $1.50
Site #124 can also have a bag of chips, but at a price of $1.95
etc...
How do I establish this relationship in Django models.py/admin.py? Also, how could I edit the price using the inline (screenshot below)? In other words, how could the price be shown to the right of the description?
Thanks in advance
Current Code:
admin.py:
from django.contrib import admin
from .models import Site, Department, Item
class ItemInline(admin.TabularInline):
model = Site.items.through
can_delete = False
verbose_name = 'Item'
verbose_name_plural = 'Items'
extra = 0
#admin.register(Site)
class SiteAdmin(admin.ModelAdmin):
fields = ("site", "address")
list_display = ("site", "address")
inlines = (ItemInline, )
exclude = ("items", )
#admin.register(Department)
class DepartmentAdmin(admin.ModelAdmin):
fields = ("number", "description")
list_display = ("number", "description")
#admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
fields = ("upc", "description", "department")
list_display = ("upc", "description", "department")
save_as = True
def formfield_for_dbfield(self, *args, **kwargs):
formfield = super().formfield_for_dbfield(*args, **kwargs)
formfield.widget.can_delete_related = False
formfield.widget.can_change_related = False
formfield.widget.can_add_related = False
# formfield.widget.can_view_related = False
return formfield
models.py:
from django.db import models
class Department(models.Model):
number = models.IntegerField(unique=True)
description = models.CharField(max_length=30)
def __str__(self):
return str(self.number) + ": " + self.description
class Meta:
ordering = ["number", ]
class Item(models.Model):
upc = models.CharField(max_length=30, unique=True, verbose_name="UPC")
description = models.CharField(max_length=30)
department = models.ForeignKey(Department, on_delete=models.SET_NULL, null=True)
def __str__(self):
return self.upc + ": " + self.description
class Meta:
ordering = ["upc", ]
class Site(models.Model):
site = models.IntegerField(unique=True)
address = models.CharField(max_length=50)
items = models.ManyToManyField(Item)
def __str__(self):
return str(self.site)
class Meta:
ordering = ["site", ]
I figured this out about 20 minutes after posting. The key was to create a new model (named ItemPrice) with site, upc, and price -- with site and upc FK'd to Site and Item. I then created a new Inline pointing to ItemPrice:
class ItemPrice(models.Model):
site = models.ForeignKey(Site, on_delete=models.CASCADE, null=True)
upc = models.ForeignKey(Item, on_delete=models.CASCADE, null=True, verbose_name="UPC")
price = models.DecimalField(max_digits=6, decimal_places=2, default=0)
class Meta:
constraints = [
models.UniqueConstraint(fields=['site', 'upc'], name='unique_site_upc')
]
and
class ItemPriceInline(admin.TabularInline):
model = ItemPrice
# can_delete = False
verbose_name = 'Item Price'
verbose_name_plural = 'Item Prices'
extra = 0

How can I filter items in DjangoRestFramework?

I am complete beginner and I made a django project a while ago. Its main purpose is adding restaurants and categories and food menu respectively. For now, it is working well, if I go to the required restaurant, it shows its categories. But now, I want to improve it via Vuejs and that's why I'm trying to make Django REST API. But I can't filter categories and food according to their restaurant, because category model is not directly connected to restaurant model. My models.py is:
from django.db import models
from django.conf import settings
class Restaurant(models.Model):
owner = models.OneToOneField(settings.AUTH_USER_MODEL, related_name="restaurant", on_delete=models.CASCADE)
name = models.CharField(max_length=256, db_index=True)
slug = models.SlugField(max_length=256, unique=True)
logo = models.ImageField(upload_to='logos/', blank=True)
def __str__(self):
return str(self.name)
class Category(models.Model):
name = models.CharField(max_length=256, db_index=True)
slug = models.SlugField(max_length=256, unique=True)
icon = models.ImageField(upload_to='categories/', blank=True)
class Meta:
verbose_name = 'category'
verbose_name_plural = 'categories'
def __str__(self):
return str(self.name)
class Food(models.Model):
restaurant = models.ForeignKey(Restaurant, related_name='foods', on_delete=models.CASCADE)
category = models.ForeignKey(Category, related_name='foods', on_delete=models.CASCADE)
name = models.CharField(max_length=256, db_index=True)
slug = models.SlugField(max_length=256, blank=True)
price = models.IntegerField(default=0)
description = models.TextField(blank=True)
image = models.ImageField(upload_to='foods/', blank=True)
available = models.BooleanField(default=True)
def __str__(self):
return str(self.name)
As you see, category class is not directly connected to restaurant. It is filtered with views.py. My views.py is:
from django.shortcuts import render, get_object_or_404
from .models import Restaurant, Category, Food
def food_list(request, restaurant_slug, category_slug):
restaurant = get_object_or_404(Restaurant, slug=restaurant_slug)
category = get_object_or_404(Category, slug=category_slug)
foods = Food.objects.filter(restaurant=restaurant, category=category, available=True)
categories = set(list(Category.objects.filter(foods__restaurant=restaurant)))
return render(request, 'restaurant/food_list.html', {'restaurant': restaurant, 'category': category, 'foods': foods, 'categories': categories})
def category_list(request, restaurant_slug=None):
restaurant = get_object_or_404(Restaurant, slug=restaurant_slug)
categories = set(list(Category.objects.filter(foods__restaurant=restaurant)))
return render(request, 'restaurant/category_list.html', {'restaurant': restaurant, 'categories': categories})
As I mentioned above it is working well now. But I want to GET categories and food respect to their restaurants. How to filter it with Django REST API?
Example code of filtering in Django :
class PassengerList(generics.ListCreateAPIView):
model = Passenger
serializer_class = PassengerSerializer
# Show all of the PASSENGERS in particular WORKSPACE
# or all of the PASSENGERS in particular AIRLINE
def get_queryset(self):
queryset = Passenger.objects.all()
workspace = self.request.query_params.get('workspace')
airline = self.request.query_params.get('airline')
if workspace:
queryset = queryset.filter(workspace_id=workspace)
elif airline:
queryset = queryset.filter(workspace__airline_id=airline)
return queryset

Using One Model inside another model in Django

I am Developing a E-commerce Application with Django
So what I was thinking is getting the category of the Product in a separate Model and list them down in another using choice field in CharField.
So Here is the code for this
This is the model for getting the Categories from the user
class ProjektCat(models.Model):
id = models.AutoField(primary_key=True)
Option_Name = models.CharField(max_length=50)
Option_Number = models.IntegerField()
Number_Visits = models.IntegerField(default=0)
def __str__(self):
return f'{self.Option_Name}'
and here is the code to list those categories as a dropdown in the CharField
class Software_And_Service(models.Model):
id = models.AutoField(primary_key=True)
Product_Name = models.CharField(max_length=100, default='')
projectKats = ProjektCat.objects.all()
choice = []
for i in projectKats:
option = (i.Option_Number, i.Option_Name)
choice.append(option)
Cateogary = models.CharField(
max_length=256, choices=choice)
Price = models.IntegerField(default=0)
Description = models.TextField(default='', max_length=5000)
pub_date = models.DateField(auto_now_add=True, blank=True, null=True)
image = models.URLField(default='')
linkToDownload = models.URLField(default='')
def __str__(self):
return f'Projekt : {self.Product_Name}'
But it's Showing me an Error that there is no such table in app_name.projektcat
Is there is any solution for this??
It's not how you do this. First correctly assign the projectKats field i.e
# You can set max_length as per your choice
projectKats = models.CharField(max_length=50)
You need to do this logic in django forms rather than django models.
So this is how you can do it.
forms.py
from django import forms
from .models import ProjektCat, Software_And_Service
def get_category_choices():
return [(obj.Option_Name,obj.Option_Name) for obj in ProjektCat.objects.values_list('Option_Name',flat=True).distinct()]
class SoftwareAndServiceForm(forms.ModelForm):
projectKats = forms.ChoiceField(choices=get_category_choices)
class Meta:
model = Software_And_Service
fields = [
'projectKats',
# whatever fields you want
]

How to create a function that counts total string objects in my ArrayField column for my model?

Trying to create a column in my model called, stock_count, that finds the sum of the total string objects in my ArrayField(), aka stock_list. Here is my function.
def total_stocks_calc(self):
self.stock_count = Bucket.objects.aggregate(Sum('stock_list', distinct=True))
self.save()
However it doesn't seem to be doing anything, no calculating, leaving the field blank in my model, admin page, and DRF interface...
EDIT: updated post with new implementation.
Here is my model.
class Bucket(models.Model):
owner = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='buckets')
users = models.ManyToManyField(settings.AUTH_USER_MODEL)
category = models.CharField(max_length=30, choices=category_options)
name = models.CharField(max_length=35)
created = models.DateTimeField(default=timezone.now)
slug = models.SlugField(unique=True, blank=True)
stock_count = models.IntegerField(blank=True, null=True)
stock_list = ArrayField(models.CharField(max_length=6,null=True),size=30,null=True)
about = models.CharField(max_length=75)
objects = models.Manager()
bucketobjects = BucketObjects()
class Meta:
ordering = ('-created',)
def total_stocks_calc(self):
self.stock_count = Bucket.objects.annotate(stock_count=F('stock_list__len'))
self.save()
def __unicode__(self):
return self.stock_list
Would like to know the proper way to count total items in ArrayField(), thank you in advance.
The ArrayField provides the len lookup field, through that you can get the count
like
from django.db.models import F
Bucket.objects.annotate(stock_count=F('stock_list__len'))

count likes in ManyToManyField - django rest framework

in models.py:
class Post(models.Model):
body = models.TextField(max_length=10000)
date = models.DateTimeField(auto_now_add=True, blank=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
liked_by = models.ManyToManyField(User, blank=True, related_name='liked_by')
class Meta:
ordering = ['-date']
in serializers.py:
class PostSerializer(serializers.ModelSerializer):
user = UserSerializers()
class Meta:
model = Post
fields = ('body','date','user')
how to count likes of a single post? and also show which user liked the post.
class PostSerializer(serializers.ModelSerializer):
user = UserSerializers()
total_likes = serilaizers.SerializerMethodField()
liked_by = UserSerializers(many=True)
class Meta:
model = Post
fields = ('body','date','user', 'total_likes', 'liked_by')
def get_total_likes(self, instance):
return instance.liked_by.count()
You need to change class Post manyToMany relation adding "through=".
liked_by = models.ManyToManyField(User, through='liked_users', blank=True, related_name='liked_by')
Create manually model LikedUsers:
class LikedUsers(models.Model):
liked_count = models.IntegerField(default=0)
post = models.ForeignKey(Post, related_name='likedusers', on_delete=models.CASCADE)
user = models.ForeignKey(User, related_name='likedusers', on_delete=models.CASCADE)
Get access to likes (post.likedusers[0].liked_count, ... next users)
You can get the total likes of a post using SerializerMethodField.
from rest_framework.fields import SerializerMethodField
class PostSerializer(serializers.ModelSerializer):
user = UserSerializers()
total_likes = SerializerMethodField()
class Meta:
model = Post
fields = ('body','date','user')
def get_total_likes(self, instance):
return instance.liked_by.all().count()
Your liked_by field is just referencing to User model, but not to User model and you have only who liked your post but likes quantity. So you can query certain post and count User quantity, but I suggest to have separate filed of likes count

Categories

Resources