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].
Related
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
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
I have a ledger account table that consist of ledger accounts of all the companies. The user in logged into a specific company and hen he selects an account to use on a form only the accounts that company must be available for the user. for this purpose I use the request.user to determine the user. I however get an error "request does not exist". I understand why it is not available on the forms.py as there is no request executed. Is there a way that I can make request.user available of the form.
Models.py
class tledger_account(models.Model):
id = models.AutoField(primary_key=True)
description = models.CharField(max_length=30, unique=True)
gl_category = models.CharField(max_length=30, choices=category_choices, verbose_name='category', db_index=True)
note = models.CharField(max_length=25, blank=True, default=None)
active = models.BooleanField(default=True)
company = models.ForeignKey(tcompany, on_delete=models.PROTECT, db_index=True)
forms.py
class SelectAccountForm(forms.ModelForm):
date_from = forms.DateField(widget=forms.SelectDateWidget(years=year_range))
date_to = forms.DateField(widget=forms.SelectDateWidget(years=year_range))
select_account = forms.ModelChoiceField(queryset=tledger_account.objects.filter(
company = request.user.current_company))
class Meta:
model = ttemp_selection
fields = ['select_account', 'date_from', 'date_to']
When you use request.user you are using the fields of the user model so it is not necessary to have them in the form, for that you need to have a forensic relationship with the user model:
class tledger_account(models.Model):
id = models.AutoField(primary_key=True)
user = models.ForeignKey(User, on_delete=models.CASCADE)
description = models.CharField(max_length=30, unique=True)
gl_category = models.CharField(max_length=30, choices=category_choices, verbose_name='category', db_index=True)
note = models.CharField(max_length=25, blank=True, default=None)
active = models.BooleanField(default=True)
company = models.ForeignKey(tcompany, on_delete=models.PROTECT, db_index=True)
and the view:
def tledger_account_view(request):
template_name = 'your template'
user = request.user
tledger_account = tledger_account.objects.get(user=user)
return render(request, template_name, {
'tledger_account': tledger_account,
})
more info https://docs.djangoproject.com/en/3.1/topics/auth/default/
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
I have a model and I am trying to save the user to the models database when the user submits the form. I had a site that did this but now my editor says "Use of super on an old style class"
I am using django 1.8 and i get
IntegrityError at /auction/createview/ NOT NULL constraint failed:
auction_auction.user_id
which is the nicest error I have been able to get. with all the tinkering i have done
class AuctionCreateView(LoginRequiredMixin,CreateView):
model = Auction
action = "created"
form_class = AuctionForm
auction_form = AuctionForm(initial={'user':request.user})
class AuctionForm(forms.ModelForm):
class Meta:
model = Auction
fields = (
"user",
"item_name",
"reserve",
"start_date",
"end_date",
"description",
"tags",
)
class Auction(models.Model):
user = models.ForeignKey(User)
item_id = models.CharField(max_length=255, blank=True, null=True)
item_name = models.CharField(max_length=255, blank=True, null=True)
winner = models.ForeignKey(User, related_name='Auction_Winner', blank=True, null=True)
reserve = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
created = models.DateTimeField(editable=False, null=True)
slug = AutoSlugField(('slug'), max_length=128, unique=True, populate_from=('item_name',))
start_date = models.DateTimeField(verbose_name="Start date")
end_date = models.DateTimeField(verbose_name="End date")
active = models.BooleanField(default=False, verbose_name='Active')
total_bids = models.IntegerField(default=0, verbose_name='Total bids')
date_added = models.DateTimeField(auto_now_add=True, verbose_name='Date added')
last_modified = models.DateTimeField(auto_now=True, verbose_name='Last modified')
description = models.TextField(max_length=3000)
tags = tagging.fields.TagField()
# bid_set = models.IntegerField(default= 0, verbose_name = "Bid set")
starting_amount = MoneyField(max_digits=10, decimal_places=2, default_currency='USD')
def __unicode__(self):
return '%s selling %s' % (self.user, self.item_name)
def _get_increment(self):
""" add some logic to base incrementing amount on starting price """
def get_absolute_url(self):
return reverse('auction_detail',
kwargs={'slug': self.slug})
when i saw this post I thought i'd be able to figure it out. thanks ★ ✩
You need insert user_id before form save.
AuctionForm - need update request.user value. Added this fields from form initial.
You have to include 'user' on the fields of the Auction form class to solve that error and just put an initial parameter on the form instance in the views.py like
auction_form = AuctionForm(initial={'user':request.user})
because request.user on the form_valid method will not work at all