I have the two following classes:
class Position(models.Model):
product = models.ForeignKey(Product, on_delete=models.CASCADE)
quantity = models.PositiveIntegerField()
price = models.FloatField(blank=True)
created = models.DateTimeField(blank=True)
def save(self, *args, **kwargs):
self.price = self.product.price * self.quantity
return super().save(*args, **kwargs)
def __str__(self):
return f"id: {self.id}, product: {self.product.name}, quantity: {self.quantity}"
class Sale(models.Model):
transaction_id = models.CharField(max_length=12, blank=True)
positions = models.ManyToManyField(Position)
total_price = models.FloatField(blank=True, null=True)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
salesman = models.ForeignKey(Profile, on_delete=models.CASCADE)
created = models.DateTimeField(blank=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return f"Total sales price: ${self.total_price}"
def get_absolute_url(self):
return reverse('sales:detail', kwargs={'pk': self.pk})
def save(self, *args, **kwargs):
if self.transaction_id == '':
self.transaction_id = generate_code()
if self.created is None:
self.created = timezone.now()
return super().save(*args, **kwargs)
def get_position(self):
return self.positions.all()
How can I relate each position instance with its related sale instance?
I've tried implementing this method:
def get_sales_id(self):
sale_obj = self.sale_set.first()
return sale_obj.id
but in this case I will always get the first id of a determined position occurrence.
Exaple:
pos1: id 1, product, quanity, price ...
pos2: id 2, product, quantity, price ...
sale1: pos 1, pos 2 ...
sale2: pos 1, pos3 ...
When I try to merge these, based on the sale id, I get:
pos1: id 1, ... , sale_id 1
pos1: id 1, ... , sale_id 1 <= when it should be 2!
I've tried to set up this filter, but I just can't wrap my head around how to make it work:
def get_id(self):
related_sale_obj = Sale.objects.filter(positions = self)
#related_id = related_obj.id
#sales_id_prefetched = self.sale_set.only('Position').explain()
return related_sale_obj
If you have any idea on how I could fix this, it'd be much appreciated.
Have a nice day
Related
I have this model in my django code. I want to check whether VariationPrice for a product with the variations exist. If it exists, make changes to the already existing VariationPrice else save the new VariationPrice.
The error I'm getting on saving new VariationPrice is
"<VariationPrice: >" needs to have a value for field "id" before this many-to-many relationship can be used.
The code I have in models.py is:
class Product(models.Model):
....
product_name = models.CharField(max_length=200, unique=True)
class Variation(models.Model):
....
variation_value = models.CharField(max_length=100)
class VariationPrice(models.Model):
price = models.IntegerField()
product = models.ForeignKey(Product, on_delete=models.CASCADE)
variations = models.ManyToManyField(Variation, blank=True)
def __str__(self):
if self.pk is not None:
return ", ".join(str(var) for var in self.variations.all())
else:
return ''
def save(self, *args, **kwargs):
if self.pk is None:
var_list = [i['variation_value'] for i in self.variations.values()]
vprice = VariationPrice.objects.filter(product=product,variations__variation_value__in=var_list).annotate(num_attr=Count('variations__variation_value')).filter(num_attr=len(var_list))
if vprice.exists():
self.pk = vprice.first().pk
super(VariationPrice, self).save(*args, **kwargs)
class Employee:
num_of_emps = 0
raise_amount = 1.04
def __init__(self, first, last, pay):
self.first = first
self.last = last
self.pay = pay
self.email = first + last + '#gmail.com'
Employee.num_of_emps += 1
def fullname(self):
return f'I am {self.first} {self.last}'
def apply_raise(self):
self.pay = int(self.pay * Employee.raise_amount)
#classmethod
def set_raise_amt(cls, amount):
cls.raise_amount = amount
#classmethod
def from_string(cls, emp_str):
first, last, pay = emp_str.split('-')
return cls(first, last, pay)
#staticmethod
def is_workday(day):
if day.weekday() == 5 or day.weekday() == 6:
return False
return True
class Developer(Employee):
raise_amount = 1.50
def __init__(self, first, last, pay, prog_lang):
super().__init__(first, last, pay)
self.prog_lang = prog_lang
class Manager(Employee):
def __init__(self, first, last, pay, employees=None):
super().__init__(first, last, pay)
if employees is None:
self.employees = []
else:
self.employees = employees
def add_emp(self,emp):
if emp not in self.employees:
self.employees.append(emp)
def remove_emp(self,emp):
if emp in self.employees:
self.employees.remove(emp)
def print_emps(self):
for emp in self.employees:
print('--->', emp.full_name())
dev_1 = Developer('John','Doe',30000, 'Python')
dev_2 = Developer('Emily','Smith',23000, 'Java')
# print(help(Developer))
print(dev_1.email)
print(dev_2.email)
print(dev_1.pay)
dev_1.apply_raise()
print(dev_1.pay)
mgr_1 = Manager('Sarah','Smith',34000, [dev_1])
print(type(mgr_1.employees))
print(mgr_1.employees)
print(type(dev_1))
print(type([dev_1]))
print([dev_1])
mgr_1.print_emps()
I recently studied this code on youtube. So basically this code started with a class named 'Employee' at the beginning, and then a subclass called 'Developer' was created. I still able to catch up with the logic behind the code at the moment, but after another subclass called 'Manager' was created, I lost.
I don't know why the parameter,'employees' in the class 'Manager' would suddenly become a list in the end
And I also don't know why the for loop could be able to run
Please help, thank you so much
mgr_1 = Manager('Sarah','Smith',34000, [dev_1])
first='Sarah', last='Smith', pay=34000, employees=[dev_1]
Your parameter is an list
I was trying to implement a simple logic in my e-commerce website where I will be calculating total cart price by looping through orders and getting their price with the help of get_final_price but suddenly this error occurred so please help me
Function due to which error is occurring
def get_total(self):
total_sum = 0
for order_item in self.items.all():
total_sum += order_item.get_final_price()
return total_sum
Models.py file
from django.db import models
from django.conf import settings
from django.db.models.deletion import CASCADE
from django.db.models.fields import DateTimeField
from django.urls import reverse
# # Create your models here.
CATEGORY_CHOICES = (
('S', 'Shirts'),
('SW', 'Sports wear'),
('OW', 'Outwear')
)
LABEL_CHOICES = (
('P', 'primary'),
('S', 'secondary'),
('D', 'danger')
)
class Item(models.Model):
title = models.CharField(max_length=100)
price = models.FloatField()
discount_price = models.FloatField(blank=True,null=True)
category = models.CharField( choices=CATEGORY_CHOICES, max_length=2)
label = models.CharField( choices=LABEL_CHOICES, max_length=1)
slug = models.SlugField()
description = models.TextField()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse("product", kwargs={
'slug' : self.slug
})
def get_add_to_cart_url(self):
return reverse("add_to_cart", kwargs={
'slug' : self.slug
})
def get_remove_from_cart_url(self):
return reverse("remove_from_cart", kwargs={
'slug' : self.slug
})
class OrderItem(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
ordered = models.BooleanField(default=False)
item = models.ForeignKey(Item, on_delete=models.CASCADE)
quantity = models.IntegerField(default = 1)
def __str__(self):
return f"{self.quantity} of {self.item.title}"
def get_total_item_price(self):
return self.quantity*self.item.price
def get_total_discount_item_price(self):
return self.quantity*self.item.discount_price
def get_amount_saved(self):
return self.get_total_item_price() - self.get_total_discount_item_price()
def get_final_price(self):
if self.item.discount_price:
return self.get_total_discount_item_price
return self.get_total_item_price
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
start_date = models.DateTimeField(auto_now_add=True)
ordered_date = models.DateTimeField()
ordered = models.BooleanField(default=False)
items = models.ManyToManyField(OrderItem)
def __str__(self):
return self.user.username
def get_total(self):
total_sum = 0
for order_item in self.items.all():
total_sum += order_item.get_final_price()
return total_sum
Error that occured
In your OrderItem class, your get_final_price() method is returning a function, not a value. Instead of returning a function, you need to return a value like this:
def get_final_price(self):
if self.item.discount_price:
discount_price = self.get_total_discount_item_price()
return discount_price
item_price = self.get_total_item_price()
return item_price
I got this error as well, because I never addded #property
Remember to add #property like this:
#property
def get_final_price(self):
if self.item.discount_price:
return self.get_total_discount_item_price
return self.get_total_item_price
https://docs.djangoproject.com/en/4.0/topics/db/models/#model-methods-1
I am working on an ecommerce project but my OrderManager() class does not saving the instance(i think)
When i am clicking on BOOK button i am getting this error which is defined in my view
order_amount = order_obj.total * 100
AttributeError: 'NoneType' object has no attribute 'total'
But when i refresh the page error goes way and order_obj.total * 100 is calculated, But my question is why i need to refresh the page again and again when i create a new order.
Here is my models.py
class OrderQuerySet(models.query.QuerySet):
def not_created(self):
return self.exclude(status='created')
class OrderManager(models.Manager):
def get_queryset(self):
return OrderQuerySet(self.model, using=self.db)
def create_or_get_order(self, product):
created = None
obj = None
qs = self.get_queryset().filter(product=product, active=True, status='created')
if qs.count() == 1:
obj = qs.first()
else:
self.model.objects.create(product=product)
created = True
return obj, created
class Order(models.Model):
order_id = models.CharField(max_length=120, blank=True)
product = models.ForeignKey(Product, on_delete=models.CASCADE)
total = models.PositiveIntegerField()
active = models.BooleanField(default=True)
objects = OrderManager()
class Meta:
ordering = ['-ordered_on', '-updated']
def __str__(self):
return self.order_id
def check_done(self): # check everything is correct before final checkout
order_id = self.order_id
total = self.total
if order_id and total > 0:
return True
return False
def mark_paid(self):
if self.check_done():
self.status = 'paid'
self.save()
return self.status
def pre_save_create_order_id(sender, instance, *args, **kwargs):
if not instance.order_id:
instance.order_id = unique_order_id_generator(instance)
pre_save.connect(pre_save_create_order_id, sender=Order)
def pre_save_order_total(sender, instance, *args, **kwargs):
"""calculate the product total while clicking on Book Button
(Still booking is not done you just clicked on Book button)"""
instance.total = instance.product.price
pre_save.connect(pre_save_order_total, sender=Order)
Views.py
def checkout_home_view(request, *args, **kwargs):
order_obj = None
order_amount = None
order_currency = None
order_id = None
slug = kwargs['slug']
product = Product.objects.get(slug=slug)
if product is not None:
# ****************** Here is problem ******************************
order_obj, order_create = Order.objects.create_or_get_order(product)
''' HERE I AM GETTING order_obj as None BUT WHEN I REFRESH ERROR GOES WAY '''
print('order_obj', order_obj) # printing None initally
order_amount = order_obj.total * 100
order_currency = 'INR'
order_id = order_obj.order_id
if request.method == 'POST':
'check that booking is done'
is_prepared = order_obj.check_done() # check_done() defined in Order model
if is_prepared:
client = razorpay.Client(auth=("xxx", "xxx"))
payment = client.order.create(dict(amount=order_amount, currency=order_currency))
if payment:
order_obj.mark_paid() # mark_paid() defined in Order model
order_obj.save()
class OrderManager(models.Manager):
...
def create_or_get_order(self, product):
created = None
obj = None
qs = self.get_queryset().filter(product=product, active=True, status='created')
if qs.count() == 1:
obj = qs.first()
else:
# -------------- catch the returned obj and return --------------
obj = self.model.objects.create(product=product)
created = True
return obj, created
I'm trying to build a logging application that stores date, exercise type, duration and comments in a database. It renders the form as i expect it but it does not create the database table from my base class. I just got stuck and hope anyone can help me what's going wrong.
CHOICES = [
(None, 'Choose Exercise'),
('Aerobics', 'Aerobics'),
('Box & Kick', 'Box & Kick'),
('Circle Training', 'Circle Training'),
('Core', 'Core'),
('Afrodance', 'Afro Dance'),
('HIT', 'HIT'),
('StepUp', 'StepUp'),
('Zumba', 'Zumba')]
class AerobicExercise(models.Model):
date = models.DateField(default='YYYYMMDD')
duration = models.DurationField()
comment = models.TextField(blank=True)
exercise = models.CharField(choices=CHOICES, max_length=20)
def __str__(self):
return self.exercise
class SplitDurationWidget(forms.MultiWidget):
def __init__(self, attrs=None):
widgets = (forms.NumberInput(attrs=attrs),
forms.NumberInput(attrs=attrs),
forms.NumberInput(attrs=attrs))
super(SplitDurationWidget, self).__init__(widgets, attrs)
def decompress(self, value):
if value:
hours = value.seconds // 3600
minutes = (value.seconds % 3600) // 60
seconds = value.seconds % 60
return [int(value.days), int(hours), int(minutes), int(seconds)]
return [0, 0, 0, 0]
class Duration(MultiValueField):
widget = SplitDurationWidget
def __init__(self, *args, **kwargs):
fields = (
forms.IntegerField(),
forms.IntegerField(),
forms.IntegerField(),
)
super(Duration, self).__init__(
fields=fields,
require_all_fields=True, *args, **kwargs
)
def compress(self, data_list):
if len(data_list) == 3:
return timedelta(
hours=int(data_list[0]),
minutes=int(data_list[1]),
seconds=int(data_list[2])
)
else:
return timedelta(0)
class AerobicForm(ModelForm):
def __init__(self, *args, **kwargs):
super(AerobicForm, self).__init__(*args, **kwargs)
self.fields['duration'] = Duration()
date = forms.DateField(initial=datetime.date.today())
class Meta:
model = AerobicExercise
fields = '__all__'
localized_fields = ('date',)
widgets = {
'comment': Textarea(attrs={'placeholder': 'The highlight of this workout was...'}),
}