Additional queryset in DetailView (using self) - python

I am creating application to manage home budget. I've got a few models - Date, Expense, Category, Income.
It looks like this
class Date(models.Model):
name = models.CharField(max_length = 15)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='date')
class Category(models.Model):
name = models.CharField(max_length=100)
budget = models.DecimalField(max_digits=8, decimal_places=2)
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='category')
date = models.ForeignKey(Date, on_delete=models.CASCADE, related_name='date', default='Styczeń 2022')
class Expense(models.Model):
name = models.CharField(max_length=100)
amount = models.DecimalField(max_digits=8, decimal_places=2)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name="account")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='expense')
date = models.ForeignKey(Date, on_delete=models.CASCADE, default='Styczeń 2022')
class Income(models.Model):
name = models.CharField(max_length=100)
amount = models.DecimalField(max_digits=8, decimal_places=2)
account = models.ForeignKey(Account, on_delete=models.CASCADE, related_name="account_income")
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='income')
First of all user should choose a "Date", next it goes to DateDetailView. And on this DetailView I want to display Expense only for this Date. I tried with objects.filter, but I don't know how I should write it properly.
I wrote something like this
class DateDetailView(DetailView):
model = Date
template_name = 'expense/date_detail.html'
context_object_name = 'date'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['expense'] = Expense.objects.filter(date=F('pk'))
return context
I also tried this
class DateDetailView(DetailView):
model = Date
template_name = 'expense/date_detail.html'
context_object_name = 'date'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['expense'] = Expense.objects.filter(date=self.date)
return context
Have you got any ideas? Thanks!

Okey, I found a solution.
class DateDetailView(DetailView):
model = Date
template_name = 'expense/date_detail.html'
context_object_name = 'date'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['expense'] = Expense.objects.filter(date=self.object)
return context

Related

Way to Filter by DB Field in Django using Class Views

I tried to search for answers, but after a few days, I'm here asking:
I'm a beginner, making a todo list app - expanding on a tutorial I followed. Currently, it's filtering by user, which is fine, but I also want to filter by a field in the DB (list).
Models:
class ToDoList(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=200)
description = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
class Meta:
ordering = ['created']
class Task(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
title = models.CharField(max_length=200)
description = models.TextField(null=True, blank=True)
complete = models.BooleanField(default=False)
created = models.DateTimeField(auto_now_add=True)
list = models.ForeignKey(ToDoList, on_delete=models.CASCADE)
def __str__(self):
return self.title
class Meta:
ordering = ['complete']
View I'm trying to change:
class TaskList(LoginRequiredMixin, ListView):
model = Task
context_object_name = "tasks"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['tasks'] = context['tasks'].filter(user=self.request.user)
context['count'] = context['tasks'].filter(complete=False).count
search_input = self.request.GET.get('search-area') or ''
if search_input:
context['tasks'] = context['tasks'].filter(title__startswith=search_input)
context['search_input'] = search_input
return context
Also, is there a way to access the list variable in the html component, like here?
url:
path('tasks/<list>/create', TaskCreate.as_view(), name="task-create"),
html:
← Back

Direct assignment to the forward side of a many-to-many set is prohibited. Use product.set() instead

i'm building a small webstore , in the product page i put the order form using FormMixin and TemplateView, when i submit the order i get a "Direct assignment to the forward side of a many-to-many set is prohibited. Use product.set() instead." error
Bellow you can check the code
Models.py
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=255, unique=True, )
description = models.TextField(max_length=1500)
class Meta:
verbose_name_plural = "categories"
def __str__(self):
return self.name
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
nominal_price = models.PositiveIntegerField(verbose_name='prix normal',)
reduced_price = models.PositiveIntegerField(blank=True, null=True)
quantity = models.PositiveIntegerField(default=10)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='products')
photo = models.ImageField(upload_to="img/products/", default="img/products/user_default.png")
def __str__(self):
return self.name
class Customer(models.Model):
full_name = models.CharField(max_length=150)
address = models.CharField(max_length=1500, null=True)
phone = models.IntegerField()
city = models.CharField(max_length=100)
email = models.EmailField(null=True)
class Order (models.Model):
product = models.ManyToManyField(Product, through='OrderProduct')
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
class OrderProduct(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
Views.py
class ProductDetailView(FormMixin, TemplateView):
model = Product
template_name = 'product.html'
form_class = OrderForm
def get_success_url(self):
return reverse('index')
def post(self, request, *args, **kwargs):
context = self.get_context_data()
form = OrderForm(request.POST)
if context['form'].is_valid():
product = get_object_or_404(Product, name=self.kwargs['product_name'])
customer = form.save()
Order.objects.create(product=product, customer=customer)
return super(TemplateView, self)
def get_context_data(self, **kwargs):
context = super(ProductDetailView, self).get_context_data(**kwargs)
context['product'] = Product.objects.get(name=self.kwargs['product_name'])
context['form'] = self.get_form()
return context
urls.py
path('', views.ProductListView.as_view(), name='index'),
Did i missed something
For handling many-to-many relations, you cannot directly set the product from Order. Also you would need to create the order first before you can set or add a product:
order = Order.objects.create(customer=customer)
order.product.add(product)

How to sum up numbers for a foreign key model in djnago

I want to sum up the total number of votes made for a login in user that has an award going on. An award is having multiple categories and multiple nominations, what am trying to do is show the sum of votes all nominations that is related to an award
model.py
class Award(models.Model):
admin = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=100)
image = models.ImageField(upload_to='award_images')
slug = models.SlugField(max_length=150)
about_the_award = models.TextField(blank=True, null=True)
price = models.CharField(max_length=20, choices=PRICE, default='0.5')
amount = models.DecimalField(default=0.0, max_digits=19, decimal_places=2)
date = models.DateTimeField(auto_now_add=True)
class Category(models.Model):
award = models.ForeignKey(Award, on_delete=models.CASCADE)
category = models.CharField(max_length=100,)
slug = models.SlugField(max_length=150)
date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.category
class Nomination(models.Model):
fullname = models.CharField(max_length=120)
mominee_ID = models.CharField(max_length=100)
category = models.ForeignKey(Category, on_delete=models.CASCADE)
image = models.ImageField(upload_to='nominations_images')
slug = models.SlugField(max_length=150)
votes = models.IntegerField(default=0)
date = models.DateTimeField(auto_now_add=True)
View.py
#method_decorator([login_required], name='dispatch')
class DashboardView(TemplateView):
template_name = 'admin/Dashboard.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['user_awards'] = Award.objects.filter(Admin=self.request.user).order_by('-date')
context['number_of_votes'] = Award.objects.filter(Admin=self.request.user, self.catgory.nomination).annotate(Sum('amount'))
return context
from django.db.models import Sum
total_votes = Nomination.objects.filter(category__award=your_award).aggregate(total_votes=Sum('votes'))['total_votes']
Note: it's good practice for your field names to start with a lowercase lette.

Matching query does not exist when update view is called in django

I have a custom user model from AbstractBaseUser and BaseUserManager. The user model is extended to a model called Employee. The employee model is related with(Foreignkey) two other model named WorkExperience and education. A single template form is designed with Employee, WorkExperience and Education modelform.
models.py:
class Employee(models.Model):
"""
Create employee attributes
"""
employee_user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
e_id = models.IntegerField(unique=True, null=True)
first_name = models.CharField(max_length=128, null=True)
last_name = models.CharField(max_length=128, null=True)
gender_choices = (
('Male', 'Male'),
('Female', 'Female'),
)
......
#receiver(post_save, sender=UserProfile)
def create_or_update_user_profile(sender, instance, created, **kwargs):
if created:
Employee.objects.create(employee_user=instance, email=instance.email)
instance.employee.save()
class WorkExperience(models.Model):
"""
Stores employee previous work experiences
"""
employee_user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
employee = models.ForeignKey('Employee', related_name='we_employee', on_delete=models.CASCADE, null=True)
previous_company_name = models.CharField(max_length=128, null=True)
job_designation = models.CharField(max_length=128, null=True)
from_date = models.DateField(null=True)
to_date = models.DateField(null=True)
job_description = models.CharField(max_length=256, null=True)
class Education(models.Model):
"""
Stores employee education background
"""
employee_user = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, null=True)
employee = models.ForeignKey('Employee', related_name='edu_employee', on_delete=models.CASCADE, null=True)
institution_name = models.CharField(max_length=128, null=True)
degree = models.CharField(max_length=128, null=True)
passing_year = models.IntegerField(null=True)
result = models.DecimalField(max_digits=5, decimal_places=2, null=True)
I have a CreateView of this three models. I have three modelform. I implemented CRUD using this modelforms. My problem is in UpdateView. When I call UpdateView an error is showing stating WorkExperience matching query does not exist.I think the query is not correct.
views.py:
class EmployeeUpdateView(LoginRequiredMixin, UpdateView):
"""
Update a created a employee
"""
login_url = '/authentication/login/'
template_name = 'employee/employee_update_form.html'
form_class = EmployeeAddModelForm
work_form_class = WorkExperienceForm
education_form_class = EducationForm
context_object_name = 'employee'
model = Employee
queryset = Employee.objects.all()
# Override default get method
def get(self, request, *args, **kwargs):
id_ = self.kwargs.get("id")
employee_id = Employee.objects.get(id=id_)
work_info = WorkExperience.objects.get(employee=employee_id)
education_info = Education.objects.get(employee=employee_id)
form = self.form_class(instance=employee_id)
work_form = self.work_form_class(prefix='work_form', instance=work_info)
education_form = self.education_form_class(prefix='education_form',instance=education_info)
return render(request, self.template_name, {
'form': form,
'work_form': work_form,
'education_form': education_form,
'supervisor_assigned': employee_id.supervisor_select
}
)
# Override default post method
def post(self, request, *args, **kwargs):
id_ = self.kwargs.get("id")
employee_id = Employee.objects.get(id=id_)
work_info = WorkExperience.objects.get(employee=employee_id)
education_info = Education.objects.get(employee=employee_id)
form = self.form_class(request.POST, instance=employee_id)
work_form = self.work_form_class(request.POST, prefix='work_form', instance=work_info)
education_form = self.education_form_class(request.POST, prefix='education_form',instance=education_info)
# Check form validation
if form.is_valid() and work_form.is_valid() and education_form.is_valid():
instance = form.save()
work = work_form.save(commit=False)
education = education_form.save(commit=False)
work.employee = instance
education.employee = instance
work.save()
education.save()
return redirect('employee:employee-list')
return render(request, self.template_name, {
'form': form,
'work_form': work_form,
'education_form': education_form
}
)
urls.py:
urlpatterns = [
path('employee-list/', EmployeeListView.as_view(), name='employee-list'),
path('employee-add/', EmployeeAddView.as_view(), name='employee-add'),
path('employee-list/<int:id>/', EmployeeDetailView.as_view(), name='employee-detail'),
path('employee-list/<int:id>/update/', EmployeeUpdateView.as_view(), name='employee-update'),
How can I modify my query? i think my query is not correct.
you need to use foreign Key to use the employee id :
work_info = WorkExperience.objects.get(employee__id=employee_id)
I Hope it works fine

Django Queryset - Issue with retrieving data from 3rd model

I want to get the 'profilephoto' from the Profile model for each Review that a Product has but that requires the Review models profile_id which is already apart of a context. Is there any way to do this?
models.py
class Profile(models.Model):
user = models.OneToOneField(User, on_delete = models.CASCADE)
profilephoto = models.ImageField(default='profiles/default_profile.jpg', upload_to='profiles')
class Product(models.Model):
name = models.CharField(max_length=100)
brand = models.CharField(max_length=100)
cost = models.DecimalField(max_digits=8, decimal_places=2, default=0.00)
category = models.CharField(max_length=100)
releasedate = models.DateField()
description = models.TextField()
productphoto = models.ImageField(default='products/default_product.jpg', upload_to='products')
class Review(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
profile = models.ForeignKey(Profile, on_delete=models.CASCADE)
author = models.ForeignKey(User, on_delete=models.CASCADE)
rating = models.PositiveSmallIntegerField(default=1, validators = [MinValueValidator(1), MaxValueValidator(5)])
reviewtext = models.TextField()
views.py
class ProductDetailView(TemplateView):
# template_name = 'reviewApp/test.html'
template_name = 'reviewApp/product_detail.html'
def get_context_data(self, **kwargs):
prod = self.kwargs['pk']
context = super(ProductDetailView, self).get_context_data(**kwargs)
context['Products'] = Product.objects.filter(id=prod)
context['Reviews'] = Review.objects.filter(product=prod)
prof = Review.objects.only('profile_id')
context['Profiles'] = Profile.objects.filter(id__in=prof)
return context
class ProductDetailView(TemplateView):
# template_name = 'reviewApp/test.html'
template_name = 'reviewApp/product_detail.html'
def get_context_data(self, **kwargs):
prod = self.kwargs['pk']
context = super(ProductDetailView, self).get_context_data(**kwargs)
context['Product'] = Product.objects.get(id=prod)
context['Reviews'] = Review.objects.filter(product_id=prod)
profile_ids = Review.objects.values_list('profile_id', flat=True)
context['Profiles'] = Profile.objects.filter(id__in=profile_ids)
return context

Categories

Resources