sum amount field in model using another model in django - python

I have three models: User, Campaign and Donation. The donation model has a donation amount, donated by each user against each campaign.
Campaign model
class Campaign(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
# this is many to one relationship, on_deleting user, profile will also be deleted
campaign_title = models.CharField(max_length=200, blank=True)
Donation model
class Donation(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True)
# this is many to one relationship, on_deleting user, user's donation details will be set to NULL
campaign = models.ForeignKey(Campaign, on_delete=models.DO_NOTHING)
donation_amount = models.IntegerField()
views.py file
def landing_page(request):
# campaigns = Campaign.objects.all().order_by('-id')
campaigns = Campaign.objects.all().order_by('-id')
////DO SOMETHING HERE TO SHOW TOTAL DONATION AGAINST EACH CAMPAIGN////
return render(request, 'core/landing_page.html',{'campaigns':campaigns})
Using the current views.py file, I'm able to display all the campaigns, how do I pass the total donation against each campaign to the html file?

You can use annotate like this.
from django.db.models import Sum
campaigns = Campaign.objects.annotate(donations=Sum('donation__donation_amount'))
Every compaign object will have a donations attribute with value to sum of total donations for that compaign.

Related

Add product to cart using python in Django

I want to make a simple function that collects the product ID and adds it to the user's shopping cart by clicking the "add to cart" button. I have the shopping cart table and product table created but am struggling to find the correct function to add the product to the cart. Anything helps I am very new to Python and Django and am looking for some help to get me on the right track.
class Cart(models.Model):
cart_id = models.Charfield(primary_key=True)
total = models.DecimalField(max_digits=9,decimal_places=2)
quantity = models.IntegerField()
products = models.ManyToManyField(Product)
class Product(models.Model):
prod_id = models.CharField(max_length=15, null=True)
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10,decimal_places=2)
description = models.TextField(max_length=1000)
def cart_add(request, prod_id):
item = Product.objects.get(pk=prod_id)
I know this isn't much to work with but anything helps, I am just looking for some help with creating the add to cart function
You need to have a relation between Cart model and User model, So that you can save product to respective user's cart.
Moreover a good approach would be adding another model named CartItem and keeping the product information in that model instead of storing product directly to Cart model. This is because when we add a product to cart, we might need to save and later update extra information about the product for example 'quantity'.
class Cart(models.Model):
cart_id = models.Charfield(primary_key=True)
total = models.DecimalField(max_digits=9,decimal_places=2)
quantity = models.IntegerField()
user = models.OneToOneField(User)
class CartItem(models.Model):
cart = models.ForeignKey(Cart, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
product_quantity = models.IntegerField(default=0)
user = models.OneToOneField(User)
So in this case, all you need to do is create a new CartItem object in add to cart view.:
def cart_add(request, prod_id, qty):
item = Product.objects.get(pk=prod_id)
cart_obj = Cart.objects.get(user=request.user)
CartItem.objects.create(cart=cart_obj, product=item, product_quantity=qty)
Hope this helps :)
You need a relation between Cart* and User
class Cart(models.Model):
cart_id = models.Charfield(primary_key=True)
total = models.DecimalField(max_digits=9,decimal_places=2)
quantity = models.IntegerField()
products = models.ManyToManyField(Product)
user = models.OneToOneField(User)
class Product(models.Model):
prod_id = models.CharField(max_length=15, null=True)
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10,decimal_places=2)
description = models.TextField(max_length=1000)
def cart_add(request, prod_id):
item = Product.objects.get(pk=prod_id)
request.user.cart.add(item)

Connect two Django models

I'm trying to make a auctions website for a project and I can't get to connect 2 models, I have in my models.py file, a model for the auction listings (Alisting) and a model for the bids that are made (Bid).
-The Alisting model has 4 fields: title CharField for the title of the auction, sta_bid for a starting bid, las_bid ForeignKey to Bid model, and user ForeignKey to User model.
-The Bid model has 3 fields: user ForeignKey to User for the user that makes the bid, listing a ForeignKey to Alisting, and new_bid IntegerField for the latest bid.
class User(AbstractUser):
pass
class Alisting(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=32)
sta_bid = models.IntegerField()
las_bid = models.ForeignKey(Bid, on_delete=models.CASCADE)
class Bid(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
listing = models.ForeignKey(Alisting, on_delete=models.CASCADE)
new_bid = models.IntegerField()
How could I connect these 2 models so that when I create a listing I can create new bids to this listing from the other model. Because later in the project I'll have to allow users to modify bids from other user's listings.
Thank you in advance!
I suggest you this design:
class User(AbstractUser):
pass
class Alisting(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.CharField(max_length=32)
sta_bid = models.IntegerField()
#property
def last_bid(self):
# You don' t need to update last_bid, since is obtained dynamically with this property
if self.bid_set.objects.count() > 0:
return self.bid_set.order('-creation_date')[0]
return None
class Bid(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
listing = models.ForeignKey(Alisting, on_delete=models.CASCADE)
new_bid = models.IntegerField()
creation_date = models.DateTimeField(auto_now_add=True) # Stores the date when the bid was created
You can access the last bid with:
listing = Alisting.objects.all()[0]
print(listing.last_bid)
You can access the bids of a listing with:
listing = Alisting.objects.all()[0]
listings.bid_set.objects.all()
# Or to get only bids of a given user
listings.bid_set.objects.filter(user=User.objects.all()[0])
You can access bids of an user with:
user = User.objects.all()[0]
user.bid_set.objects.all()
# Or to get only bids of an user with a given listing
user.bid_set.objects.filter(listing=Alisting.objects.all()[0])
You can access listings created by a given user with:
user = User.objects.all()[0]
user.alisting_set.objects.all()

How to display top 5 user list in Django?

I created a system with Django. In this system, users do some analysis. I keep the information of these analyzes in a model named "ApprocalProcess". How can I display the top 5 users who made the most analysis in "ApprovalProcess"?
models.py
class ApprovalProcess(models.Model):
id = models.AutoField(primary_key=True)
user_id = models.ForeignKey(UserProfile, on_delete=models.CASCADE, null=True, related_name='starter')
doc_id = models.ForeignKey(Pdf, on_delete=models.CASCADE, null=True)
...
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, null=True)
views.py
def approval_context_processor(request):
approval_list = ApprovalProcess.objects.filter(user_id__company=current_user.company)
context = {
'approval_list ': approval_list,
....
}
return context
from django.db.models import Count
approval_list = ApprovalProcess.objects.values('user_id').annotate(Count('user_id')).order_by('-user_id__count')[:5]
First we find user_id duplicate in table and count it. Then we order descending with - in -user_id__count and get 5 users duplicatest in table.
Sorry for my bad English.

Django saving some fields to the DB but not others

I'm trying to save some data through a form and I'm trying to use a
FormSet. The data to be saved is an invoice which contains a Product
and it's Details.
I was able to render everything in one place (this wasn't simple) and
to save the invoice and the detail to the DB. For some reason, the
Detail table is saving the Product ID but not the Invoice ID. This is
my models.py:
class Detail(models.Model):
invoice = models.ForeignKey(Invoice, null=True, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField(default=1)
subtotal = models.DecimalField(max_digits=9 , null=True, decimal_places=2)
class Invoice(models.Model):
date = models.DateField(default=datetime.date.today)
number = models.CharField(max_length=10, default='0000000000')
supplier = models.ForeignKey(Supplier, on_delete=models.CASCADE)
products = models.ManyToManyField(Product, null=True, blank=True)
total = models.DecimalField(max_digits=9 , null=True, decimal_places=2)
And this is my views.py:
def invoice_new(request):
DetailFormSet = formset_factory(DetailForm, extra=2)
if request.method == "POST":
invoice_form = InvoiceForm(request.POST)
detail_formset = DetailFormSet(request.POST)
if invoice_form.is_valid() and detail_formset.is_valid():
invoice = invoice_form.save(commit=False)
invoice.save()
for details in detail_formset:
details.save()
return redirect('invoice_detail', pk=invoice.pk)
else:
return redirect('invoice_error')
else:
invoice_form = InvoiceForm()
detail_formset=formset_factory(DetailForm, extra=2)
return render(request, 'invoice/invoice_edit.html', {'invoice_form': invoice_form, 'detail_form': detail_formset} )
I tried adding this to the body of the for loop:
details.invoice_id = invoice.pk
invoice.id prints OK, but it won't save the number to the DB. I don't see how it picks up product id just fine but not invoice's.
I'm adding forms.py
class InvoiceForm(forms.ModelForm):
class Meta:
model = Invoice
fields = ['date','number','supplier']
total = forms.DecimalField(disabled=True)
class DetailForm(forms.ModelForm):
class Meta:
model = Detail
fields = ['product','quantity']
You can set the invoice id before saving the form.
if invoice_form.is_valid() and detail_formset.is_valid():
invoice = invoice_form.save(commit=False)
invoice.save()
for details in detail_formset:
details.invoice = invoice # Set the invoice
details.save()

List of Users ordered by the rank of their Posts reviews

I want to make an API End Point so the user can get a list of the users in his city ordered by their post reviews
I have defined a method in the post model to calculate the total review (up vote and down vote), I'm imagining that the solution can be realized in the following path but I'm not entirely sure groupBy post_owner in the post and orderBy sum(count_reactions()), but I don't know how to do it in django
Post Model
class Post(models.Model):
title = models.TextField(max_length=255, default='Title')
post_owner = models.ForeignKey(MyUser, on_delete=models.CASCADE)
description = models.TextField(max_length=255)
city = models.ForeignKey(City, related_name='location', on_delete=models.CASCADE)
longitude = models.CharField(max_length=255)
image = models.CharField(max_length=255,
default='https://www.eltis.org/sites/default/files/styles/web_quality/public/default_images/photo_default_2.png')
latitude = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
def count_reactions(self):
likes_count = Reaction.objects.filter(post=self.id, is_like=True).count()
dislikes_count = Reaction.objects.filter(post=self.id, is_like=False).count()
return likes_count - dislikes_count
def owner(self):
return self.post_owner
MyUser Model
class MyUser(AbstractUser):
phone_number = models.BigIntegerField(blank=False, unique=True)
city = models.ForeignKey(City, related_name='city', on_delete=models.CASCADE)
address = models.CharField(max_length=255)
def owner(self):
return self
Reaction Model
class Reaction(models.Model):
reaction_owner = models.ForeignKey(MyUser, on_delete=models.CASCADE)
post = models.ForeignKey(Post, related_name='reactions', on_delete=models.CASCADE)
is_like = models.BooleanField(null=False)
def owner(self):
return self.reaction_owner
The expected result is to get the ordered list of the users by their posts reviews but only the users in the same city (city field in MyUser model)
You can put it all into one query.
Depending on where your Reaction naming the query should look something like this:
# Filter for the city you want
users = MyUser.objects.filter(city=your_city_obj)
# Then doing the calculations
users = users.annotate(rank_point=(Count('post__reactions', filter=Q(post__reactions__is_like=True)) - (Count('post__reactions', filter=Q(post__reactions__is_like=False)))))
# And finaly, order the results
users = users.order_by('-rank_point')
The answer is Navid's answer but completing it with excluding the users with rank equal to zero and include also the limit
# Filter for the city you want
users = MyUser.objects.filter(city=your_city_obj)
# Then doing the calculations
users = users.annotate(rank_point=(Count('post__reactions', filter=Q(post__reactions__is_like=True)) - (Count('post__reactions', filter=Q(post__reactions__is_like=False))))).filter(rank_point__gt=0)
# And finaly, order the results
users = users.order_by('-rank_point')[:LIMIT]

Categories

Resources