Django ModelManager not saving the model instance correctly - python-3.x

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

Related

How can I connect different class instances based on their ids?

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

Trying to show created date of order on another view i get KeyERROR "list_id"

Been trying to show the created_date of the customer order on another view, kindly help much appreciated.
ListListView
class ListListView(generic.ListView):
model = HBTYList
template_name = "accounts/modals/nomodal/index.html"
paginate_by = 3
def get_queryset(self):
qs = self.model.objects.all().order_by('-id')
p_f = HbtyCustomerListFilter(self.request.GET, queryset=qs)
return p_f.qs
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['dc'] = HBTYItem.objects.filter(hbty_cust_id=self.kwargs["list_id"]) #Fix this method to show created_data
context['filter'] = HbtyCustomerListFilter(self.request.GET, queryset=self.get_queryset())
return context
ItemListView
class ItemListView(ListView):
model = HBTYItem
template_name = "accounts/modals/nomodal/todo_list.html"
paginate_by = 2
ordering = ['id']
def get_queryset(self):
return HBTYItem.objects.filter(hbty_cust_id=self.kwargs["list_id"])
def get_context_data(self):
context = super().get_context_data()
context['t_sum'] = HBTYItem.objects.filter(hbty_cust_id=self.kwargs["list_id"]).aggregate(Sum('price'))
context["hbty_list"] = HBTYList.objects.get(id=self.kwargs["list_id"])
return context
Urls.py
path("hbtylist/", views.ListListView.as_view(), name="hbtylist"),
path("list/<int:list_id>/", views.ItemListView.as_view(), name="list"),
# CRUD URL FOR HBTYCUSTOMERS
path("list/add/", views.ListCreate.as_view(), name="list-add"),
path("list/<int:pk>/delete/", views.ListDelete.as_view(), name="list-delete"),
# CRUD URL FOR HBTYCUSTOMERSAPPOINMENTS
path("list/<int:list_id>/item/add/", views.ItemCreate.as_view(),name="item-add",),
path("list/<int:list_id>/item/<int:pk>/",views.ItemUpdate.as_view(),name="item-update",),
path("list/<int:list_id>/item/<int:pk>/delete/",views.ItemDelete.as_view(),name="item-delete",),
Thank You For The Help.

how solve django create model class dynamically

When dynamically creating and generating Model class, modify some
properties, fill in the information required by the sub-table, the
first time can return the normal result, the second result error,
after the analysis of the second result field to retain the first
table name:
class Object:
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
def _model_new(cls, *args, **kwargs):
return cls(*args, **kwargs)enter code here
class ShardModel(object):
_shard_db_models = {}
temp_class = []
def __new__(cls, *args, **kwargs):
shard_key = kwargs.pop('shard_key', 0) % cls.Config.table_num
model_name = cls.__name__
model_name += '_%s' % shard_key
model_class = cls._shard_db_models.get(model_name)
if model_class is not None:
return model_class
# Deep copy attrs
attrs = dict()
attrs.update(cls.__dict__)
if 'objects' in attrs:
attrs['objects'] = attrs['objects'].__class__()
# Set table name with shard_key
meta = Object(**cls.Meta.__dict__)
meta.db_table = meta.db_table % shard_key
meta.abstract = False
attrs['Meta'] = meta
attrs['new'] = classmethod(_model_new)
attrs['__module__'] = cls.__name__
cursor = connection.cursor()
tables = [table_info.name for table_info in connection.introspection.get_table_list(cursor)]
# Create model class dynamically
model_class = type(model_name, tuple([models.Model] + list(cls.__bases__[1:])), attrs)
print(model_class)
if meta.db_table not in tables:
for cmd in ('makemigrations', 'migrate'):
exec_command(cmd, meta.app_label)
cls._shard_db_models[model_name] = model_class
return model_class
this is my model
class Nice(ShardModel):
user_id = models.IntegerField()
user_name = models.CharField(max_length=256)
password = models.CharField(max_length=256)
class Config:
table_num = 3
class Meta:
app_label = 'Test'
db_table = 'test_%s'
abstract = True
this my view
def NiceView(request):
user_id = int(request.GET.get('user_id'))
user = Nice(shard_key=user_id).objects.get(user_id=user_id)
return HttpResponse(json.dumps(model_to_dict(user)))
Here are the two times test results
url:http://127.0.0.1:8000/test?user_id=7
results:{"id": 2, "user_id": 7, "user_name": "ni", "password": "hao"};url:http://127.0.0.1:8000/test?user_id=5;error:(1054, "Unknown column 'test_1.user_id' in 'field list'")

Django unsupported operand type(s) for +=: 'int' and 'method'

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

Doesn't create a database table from my model baseclass

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...'}),
}

Resources