How to Fetch Data in ManyToMany Django And render in view.py - django

I want to fetch Data to my view.py where the buyer select a specific market. Which Means the Buyer can only see the Market he selects.
class Market(models.Model):
name = models.CharField(max_length=30)
address = models.TextField("Market Address")
interval = models.PositiveIntegerField("Market Day Interval", default=5)
startdate = models.DateField("Initial Date", auto_now=False, auto_now_add=False)
location = models.ForeignKey(Local, related_name='market_location', on_delete=models.CASCADE)
desciption = models.TextField("Good Description")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Buyer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, primary_key=True)
market = models.ManyToManyField(Market, related_name='interested_markets')
status = models.BooleanField("User Status", default=False)
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.user.username
view.py
#login_required
#buyer_required
def welcome_buyer(request):
buyer = request.user.buyer
market = buyer.interested_markets.all()
return render(request, 'buyer/home.html', {
'market': market
})

you can simply iterate over this using your buyer object:
for market in buyer.market_set.all()
or
markets = buyer.market_set.all()
in your case it would be:
markets = buyer.interested_markets_set.all()
or
markets = buyer.market # you should consider changing it's name to be plural to indicate that it's a list of objects like: buyer.markets
for more details read the docs here: django many to many

Related

Filter queryset of django inline formset based on attribute of through model

I have a basic restaurant inventory tracking app that allows the user to create ingredients, menus, and items on the menus. For each item on a given menu, the user can list the required ingredients for that item along with a quantity required per ingredient for that item.
Menu items have a many-to-many relationship with ingredients, and are connected via an "IngredientQuantity" through table.
Here are my models:
class Ingredient(models.Model):
GRAM = 'Grams'
OUNCE = 'Ounces'
PIECE = 'Pieces'
UNIT_CHOICES = [
('Grams', 'Grams'),
('Ounces', 'Ounces'),
('Pieces', 'Pieces')
]
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField(max_length=200)
unitType = models.CharField(max_length=200, choices=UNIT_CHOICES, verbose_name='Unit')
unitCost = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='Unit Cost')
inventoryQuantity = models.DecimalField(max_digits=10, decimal_places=2, verbose_name='Quantity')
def __str__(self):
return self.name + ' (' + self.unitType + ')'
def totalCost(self):
result = self.inventoryQuantity * self.unitCost
return "{:.0f}".format(result)
class Menu(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField(max_length=200)
timeCreated = models.DateTimeField(auto_now_add=True)
timeUpdated = models.DateTimeField(auto_now=True)
def __str__(self):
return str(self.name)
class MenuItem(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
name = models.CharField(max_length=200)
price = models.DecimalField(max_digits=10, decimal_places=2)
ingredients = models.ManyToManyField(Ingredient, through='IngredientQuantity')
menu = models.ForeignKey(Menu, on_delete=models.CASCADE, null=True)
def __str__(self):
return self.name
def itemCost(self):
relevantIngredients = IngredientQuantity.objects.filter(menuItem=self)
cost = 0
for ingredient in relevantIngredients:
cost += (ingredient.ingredient.unitCost * ingredient.ingredientQuantity)
return cost
class IngredientQuantity(models.Model):
user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
menuItem = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
ingredientQuantity = models.IntegerField(default=0)
def __str__(self):
return str(self.ingredient)
This is a multi-user app, so when a user creates a new item on a menu and adds ingredients to it, they should only have the option of choosing ingredients they have created, not those of other users. Here is my attempt to do that in my views:
def ItemUpdate(request, pk):
item = MenuItem.objects.get(id=pk)
user = request.user
IngredientQuantityFormset = inlineformset_factory(
MenuItem, IngredientQuantity, fields=('ingredient', 'ingredientQuantity'), can_delete=True, extra=0
)
form = ItemCreateForm(instance=item)
formset = IngredientQuantityFormset(instance=item, queryset=IngredientQuantity.objects.filter(ingredient__user=user))
if request.method == 'POST':
form = ItemCreateForm(request.POST, instance=item)
formset = IngredientQuantityFormset(request.POST, instance=item, queryset=IngredientQuantity.objects.filter(ingredient__user=user))
# rest of view...
I've searched everywhere for how to implement the queryset parameter properly, but I cannot get it to work. When creating an item on a menu, the user still has the ability to choose from every ingredient in the database (including the ones created by other users). I would like the user to only be able to choose from the ingredients they themselves created.
Does anyone know how to do this properly? Thank you!
I received some guidance on Django forums and arrived at a solution which is documented below:
https://forum.djangoproject.com/t/filter-dropdown-options-in-django-inline-formset-based-on-attribute-of-through-model/13374/3

Simple django filter is includes all users’ data rather than that of the logged-in user

I’m new to Django and have built a basic filter that does not filter according to the logged-in user’s data but rather all users’ data, which is incorrect. The filter is for an Automation class, which has a many:many relationship with the Message class (and funnily enough the exact same happens with the message filter).
Views.py:
#login_required(login_url='login')
#allowed_users(allowed_roles=['admin', 'customer'], own_account_only=True)
def automation_list(request, pk):
account = Account.objects.get(id=pk)
automations = account.automation_set.all()
filter = AutomationFilter(request.GET, queryset=automations)
automations = filter.qs
context = {'account': account,
'automations': automations, 'filter': filter}
return render(request, 'automations/automation_list.html', context)
Filters.py:
class AutomationFilter(django_filters.FilterSet):
start_date = DateFilter(field_name='date_joined', lookup_expr='gte')
end_date = DateFilter(field_name='date_joined', lookup_expr='lte')
class Meta:
model = Automation
fields = '__all__'
exclude = ['account', 'date_created']
Models:
class Automation(models.Model):
name = models.CharField(max_length=100)
description = models.CharField(max_length=200)
account = models.ForeignKey(Account, on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now_add=True, null=True)
messages = models.ManyToManyField(Message, blank=True)
def __str__(self):
return self.name
class Message(models.Model):
name = models.CharField(max_length=100)
subject = models.CharField(max_length=128)
text = models.TextField()
account = models.ForeignKey(Account, on_delete=models.CASCADE)
date_created = models.DateTimeField(auto_now_add=True, null=True)
automations = models.ManyToManyField('automations.Automation', blank=True)
def __str__(self):
return self.name
Why is the filter not just filtering according to the logged-in user? I’d have thought that I’m only passing in the user’s data via this line:
filter = AutomationFilter(request.GET, queryset=automations)
Thanks

Django model query with Foreign key and get logged in user

Hi I am trying to add "fields" to my django projects that would be calculated based on query..
Basically I have 2 models one is a user which is an extension of Abstract user
class CustomUser(AbstractUser):
pass
and my main model is Project
class Project(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(CustomUser, on_delete=models.PROTECT, editable=False)
name = models.CharField(max_length=20, editable=False)
total = models.DecimalField(max_digits=6, decimal_places=2, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False, null=False, blank=False)
this_month = datetime.datetime.now().month
allprojectsthismonth = Project.objects.filter(created__month=this_month)
def __str__(self):
return self.name
I create Project objects via a web form using this view:
def homepage(request):
if request.method == "POST":
project = Project()
name = request.POST.get('name')
total = request.POST.get('total')
created = datetime.datetime.now()
user = request.user
project.user = user
project.name = name
project.total = total
project.created = created
project.save()
#return HttpResponse(reverse("homepage.views.homepage"))
return render(request, 'homepage.html')
else:
return render(request, 'homepage.html')
What I need now is to have a queryset that gets me the combination of the total of a given user Project object so that I can make calculations on it, how would I go about doing that?
ideally I would get the logged in user and I could add to my view the sum of all Project.object.total with user = currently logged in.
Thanks
EDIT: Would this work?
class Project(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(CustomUser, on_delete=models.PROTECT, editable=False)
name = models.CharField(max_length=20, editable=False)
total = models.DecimalField(max_digits=6, decimal_places=2, editable=False)
created = models.DateTimeField(auto_now_add=True, editable=False, null=False, blank=False)
this_month = datetime.datetime.now().month
projectsthismonth = self.objects.filter(created__month=this_month)
def monthlyTotal(self,request):
projectsthismonth.objects.filter(
user=request.user
).aggregate(
sum_total=Sum('total')
)['sum_total']
I seem to be missing something however.
You can obtain the queryset of the Projects where the user is the logged in user with:
Project.objects.filter(user=request.user)
If you want to make simple aggregates (like sum, count, etc.), you better use .aggregate(…) [Django-doc] since then the calculations are done at the database level. For example:
from django.db.models import Sum
Project.objects.filter(
user=request.user
).aggregate(
sum_total=Sum('total')
)['sum_total']
will retrieve the sum of the totals of the Projects with user=request.user, this will be None if there are no projects related to the user at all.
from django.utils.timezone import now
class Project(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(CustomUser, on_delete=models.PROTECT, editable=False)
name = models.CharField(max_length=20, editable=False)
total = models.DecimalField(max_digits=6, decimal_places=2, editable=False)
created = models.DateTimeField(auto_now_add=True)
def monthlyTotal(self,user):
this_month = now().month
return Project.objects.filter(
created__month=this_month,
user=user
).aggregate(
sum_total=Sum('total')
)['sum_total']
Note: You can limit views to a view to authenticated users with the
#login_required decorator [Django-doc].

Unable to Understand the below statements of models in Django

I am naive in Django, I have done a sample E-commerce application that is present online. I am unable to understand the highlighted statements, I searched online but unable to understand the statements.
Can someone please explain me like below
productitems = self.name_set.all()
From where this name_set.all() came ?????????
orderItems = self.orderitem_set.all()
likewise from where orderitem_set.all() ?????????
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class Customer(models.Model):
user = models.OneToOneField(User,on_delete=models.CASCADE, null=True,blank=True)
name = models.CharField(max_length=200,null=True)
email = models.CharField(max_length=200,null=True)
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=200, null=True)
price = models.DecimalField(max_digits=7,decimal_places=2)
digital = models.BooleanField(default=False,null=True,blank=False)
image = models.ImageField(null=True,blank=True)
#image
def __str__(self):
return self.name
#property
def imageURL(self):
try:
url = self.image.url
except:
url = ''
return url
#property
def get_product_total(self):
**productitems = **self.name_set.all()****
total = sum([item.get_total for item in productitems])
return total
print('total:',total)
class Order(models.Model):
customer = models.ForeignKey(Customer,on_delete=models.SET_NULL,blank=True,null=True)
date_ordered=models.DateTimeField(auto_now_add=True)
complete = models.BooleanField(default=False,null=True,blank=False)
transaction_id = models.CharField(max_length=200, null=True)
def __str__(self):
return str(self.id)
#property
def shipping(self):
shipping = False
orderItems = **self.orderitem_set.all()**
for i in orderItems:
if i.product.digital == False:
shipping = True
return shipping
#property
def get_cart_total(self):
orderitems = self.orderitem_set.all()
total = sum([item.get_total for item in orderitems])
return total
#property
def get_cart_items(self):
orderitems = self.orderitem_set.all()
total = sum([item.quantity for item in orderitems])
return total
class OrderItem(models.Model):
product = models.ForeignKey(Product,on_delete=models.SET_NULL,blank=True,null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
quantity=models.IntegerField(default=0,blank=True,null=True)
date_added=models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.product)
#property
def get_total(self):
print(self.product.price)
# print("self.product.price:",self.product.price)
# print("self.quantity:", self.quantity)
total = self.product.price * self.quantity
return total
class ShippingAddress(models.Model):
customer = models.ForeignKey(Customer,on_delete=models.SET_NULL,blank=True,null=True)
order = models.ForeignKey(Order, on_delete=models.SET_NULL, blank=True, null=True)
address = models.CharField(max_length=200,null=True)
city = models.CharField(max_length=200, null=True)
state = models.CharField(max_length=200, null=True)
zipcode = models.CharField(max_length=200, null=True)
date_added = models.DateTimeField(auto_now_add=True)
def __str__(self):
return str(self.address)
Those are reverse foreign key lookups. The {field_name}_set pattern is what Django uses by default if you don't define a different term yourself.
The Django documentation explains it more here https://docs.djangoproject.com/en/3.1/ref/models/fields/#django.db.models.ForeignKey.related_name
and here https://docs.djangoproject.com/en/3.1/topics/db/queries/#following-relationships-backward
An example from the docs is:
>>> b = Blog.objects.get(id=1)
>>> b.entry_set.all() # Returns all Entry objects related to Blog.
Instead of using the default you can set the related lookup to a custom value when defining the ForeignKey field on the model, using the related_name argument. I do this often myself, there are usually more fitting terms for the project than the default.

Django querying models with foreignkey

I am creating a project of customer management, in this I want to query some models which are related with foreign key.
I have created these models.
from django.db import models
class Customer(models.Model):
name = models.CharField(max_length=250, null=True)
phone = models.CharField(max_length=10, null=True)
email = models.CharField(max_length=250, null=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
# to get name as string on behalf of "Customer Object 1" in DB.
def __str__(self):
return self.name
class Tag(models.Model):
name = models.CharField(max_length=250, null=True)
def __str__(self):
return self.name
class Product(models.Model):
# To make a dropdown menu to choose category.
CATEGORY = (
('Indoor', 'Indoor'),
('Out Door', 'Out Door'),
)
name = models.CharField(max_length=250, null=True)
price = models.FloatField(null=True)
category = models.CharField(max_length=250, null=True, choices=CATEGORY)
description = models.CharField(max_length=250, null=True, blank=True)
date_created = models.DateTimeField(auto_now_add=True, null=True)
tags = models.ManyToManyField(Tag)
def __str__(self):
return self.name
class Order(models.Model):
# To make a dropdown menu to choose status.
STATUS = (
('Pending', 'Pending'),
('Out for Delivery', 'Out for Delivery'),
('Delivered', 'Delivered'),
)
customer = models.ForeignKey(Customer, null=True,
on_delete=models.SET_NULL)
product = models.ForeignKey(Product, null=True,
on_delete=models.SET_NULL)
date_created = models.DateTimeField(auto_now_add=True, null=True)
status = models.CharField(max_length=250, null=True, choices=STATUS)
Views.py
from django.shortcuts import render
from .models import *
def home(request):
customers = Customer.objects.all()
orders = Order.objects.all()
total_customers = customers.count()
total_orders = orders.count()
delivered = orders.filter(status='Delivered').count()
pending = orders.filter(status='Pending').count()
front_end_stuff = {'customers': customers, 'orders': orders,
'total_customers': total_customers, 'total_orders': total_orders,
'delivered': delivered, 'pending': pending,
}
return render(request, 'accounts/dashboard.html', context=front_end_stuff)
def products(request):
products_ = Product.objects.all()
return render(request, 'accounts/products.html', context={'products': products_})
def customer(request, pk):
customers = Customer.objects.filter(id=pk)
orders = Order.objects.filter(id=pk)
customer_products = Product.objects.filter(id=pk)
total_orders = orders.count()
front_end_stuff = {'customers': customers, 'orders': orders,
'total_orders': total_orders, 'customer_products': customer_products
}
return render(request, 'accounts/customer.html', context=front_end_stuff)
I want to get status of the orders placed by a specific customer, also i have set the dynamic urls for getting customer profile view page and in it i want to loop through it and print out the status in respective field.
I have attached the image of customer profile view page where i want the data.
customer_profile_view_page
I tried one query which i found on internet is :
customers = Customer.objects.filter(id=pk)
status = customers.order_set.all()
but I get an error
AttributeError: 'QuerySet' object has no attribute 'order_set'
I am using :
Windows 10,
Python 3.7,
Django 3.0.7.
To get the list of all the orders of a customer, you can try -
# this will give the list of orders for customer with id = pk
orders = Order.objects.filter(customer__id=pk) # it's a double underscore
You can iterate each order to fetch the status -
for order in orders:
print(order.status)
Or with what you tried, use .get instead of .filter.
customer = Customer.objects.get(id=pk) # the customer has to be present with this id else it will give an exception.
orders = customer.order_set.all()
Doc