Update model that is connected via ForeignKey - django

Hi I have models that are contectet via foregin key. I can have multiple orders so let's say that i have 3 orders. 2xTshirt 1xPants and 4xHats. How can I acces each product and change the stock of them based on quantity of an order.
views
order = Order.objects.get_or_create(customer=customer, complete=False)
order_items = OrderItem.objects.filter(order=order)
for item in order_items:
item.product.stock = int(item.product.stock) - int(item.quantity)
item.transaction_id = transaction_id
item.save()
models
class Product(models.Model):
title = models.CharField(max_length=70, null=True, blank=True)
producent = models.CharField(max_length=40, null=True, blank=True)
stock = models.PositiveIntegerField(null=True, blank=True)
class OrderItem(models.Model):
product = models.ForeignKey(Product, on_delete=models.SET_NULL, blank=True, null=True)
quantity = models.IntegerField(default=0, null=True, blank=True)

You are not saving the product object. Try this:
for item in order_items:
product = item.product
product.stock = product.stock - item.quantity
product.save()
item.transaction_id = transaction_id
item.save()

Related

django objects.create method is too slow How to make faster?

multiple tables are mapped and, when I create post request,
it takes about 2~3 seconds. Is there any ways to fix it?
I guess it takes a long time on:
objects.create
for loop
product.objects.get
however, I am not able to find the better ways..
models:
#product, Order, OrderItems, ShippingAddress are mapped
class Order(models.Model):
user = models.ForeignKey(User, on_delete= models.CASCADE)
order_date = models.DateTimeField(auto_now=True)
is_paid = models.BooleanField(default=False)
paid_at = models.DateTimeField(auto_now=False, null=True, blank=True)
delivery_code = models.CharField(max_length=255, null=True, blank=True)
is_delivered = models.BooleanField(default=False)
delivered_date = models.DateTimeField(auto_now=False, null=True, blank=True)
total_price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
shipping_price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
payment_method = models.CharField(max_length=255,null=True)
def __str__(self):
return str(self.user)
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete= models.CASCADE, null=True, blank=True)
product = models.ForeignKey(Product, on_delete= models.CASCADE)
name = models.CharField(max_length=200, null=True)
image = models.CharField(max_length=255, null=True)
qty = models.IntegerField(default=0, null=True)
price = models.DecimalField(max_digits=7, decimal_places=2, null=True)
def image_preview(self):
if self.image:
return mark_safe('<img src="{0}" width="55" height="55" />'.format(self.image))
else:
return '(No image)'
def __str__(self):
return str(self.product)
class ShippingAddress(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
order = models.OneToOneField(Order, on_delete=models.CASCADE, null=True, blank=True)
address = models.CharField(max_length=255, null=False)
city = models.CharField(max_length=255, null=False)
postal_code = models.CharField(max_length=255, null=False)
country = models.CharField(max_length=255, null=False)
def __str__(self):
return str(self.user)
view:
#permission_classes(IsAuthenticated)
#api_view(['POST'])
def OrderCreate(request):
data = request.data
user = request.user
order_items = data['orderItems']
#1.create order
order = Order.objects.create(
user = user,
total_price = data['totalPrice'],
shipping_price = data['shippingPrice'],
payment_method = data['paymentMethod']
)
#2.create orderItems
for i in order_items:
product = Product.objects.get(id=i['id'])
order_item = OrderItem.objects.create(
order = order,
product = product,
name = i['name'],
qty = i['qty'],
price = i['price'],
image = i['image']
)
#3. update stock
product.stock -= i['qty']
product.save()
#4.create shipping address
shipping_address = ShippingAddress.objects.create(
user = user,
order = order,
address = data['shippingAddress']['address'],
city = data['shippingAddress']['city'],
postal_code = data['shippingAddress']['postalCode'],
country = data['shippingAddress']['country'],
)
#5.serializing and save
serializer = OrderSerializer(order, many=False)
return Response(serializer.data)
You can instantiate the order_items without ever fetching the product, provided you have sufficient trust for the product ids in i['id']
for i in order_items:
# product = Product.objects.get(id=i['id'])
order_item = OrderItem.objects.create(
order = order,
product_id = i['id'], # set the id (magic suffix) without fetching product
name = i['name'],
qty = i['qty'],
price = i['price'],
image = i['image']
)
Instead of using .create you might instantiate these order_items as a list of unsaved instances and create them using OrderItem.bulk_create Read the bulk_create documentation; it has a number of caveats.
You could then run a loop updating the product stock field using an F expression to subtract from the current value in the product row without actually fetching a product object from the DB
for i in order_items:
product_id = i['id']
Product.objects.filter(
pk = product_id
).update(
stock = F('stock') - i['qty']
)
If you do fetch all the product instances into a list with updated stock values, there's also bulk_update which would let you apply all the updated stock values in a single DB operation. This might be better than doing them one by one with an F expression. You can also fetch them in bulk using
Product.objects.filter( pk__in=[ i['id'] for i in order_items ] )
(Warning, I don't think that there's any guarantee that the queryset contains the objects in the same order that you supply the i['id'] values )
Treat this as brainstorming. I'm not entirely certain that this is correct and I really don't know whether it will speed things up a lot, a little, or at all. I'd be interested to know, if you try it.

how to make relationship in django model

models.py
So,here i want to make Invoicemgmt model in which i can have multiple entries for Invoice table having
customer,project and Invoice_amount.
Basically,requirement is that whenever i see 'view_Invoice' of some id,first i will see all data of that
specific id on that page and then i want to have small table below for invoice_mgmt,where i can add amount received for that specific id invoice.
*so,i want to know what fields should i add in invoice_mgmt model for relationship "
class Invoice(models.Model):
company_choice = (
('VT_India', 'VT_India'),
('VT_USA', 'VT_USA'),
)
company = models.CharField(
max_length=30, blank=True, null=True, choices=company_choice)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE)
project = models.ForeignKey(Allproject, on_delete=models.CASCADE)
invoice_title = models.CharField(max_length=15)
invoice_id = models.IntegerField(primary_key=True)
invoice_amount = models.IntegerField()
invoice_date = models.DateField(
blank=True, null=True)
invoice_duedate = models.DateField(
blank=True, null=True)
invoice_description = models.TextField()
def __str__(self):
return self.invoice_title
class Paymentmethod(models.Model):
paymentmethod_id = models.IntegerField(primary_key=True)
paymentmethod_name = models.CharField(max_length=15)
def __str__(self):
return self.paymentmethod_name
class Invoicemgmt(models.Model):
invoicemanagement_id = models.IntegerField(primary_key=True)
invoice_received = models.IntegerField()
date = models.DateField(
blank=True, null=True)
payment_method = models.ForeignKey(Paymentmethod, on_delete=models.CASCADE)
"So, basically i want to have multiple entries in invoice mgmt table for one specific invoice table id(one specific data)"

how to use two instance id of foreign key

I have four models of the shop, customer, product, an order.
I am showing the relation of models
shop
user = models.OneToOneField(User, null=True, related_name='shop', blank=True, on_delete=models.CASCADE)
name = models.CharField(max_length=70, null=True, default='shop', )
address = models.CharField(max_length=70, null=True)
Shop_category = models.CharField(max_length=200, null=True, )
customer
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
name = models.CharField(max_length=100, null=True, default='customer')
Phone = models.PositiveIntegerField(blank=True, null=True)
product
shop = models.ForeignKey(Shop, models.CASCADE, null=True, blank=True)
name = models.CharField(max_length=100, blank=True)
Brand = models.CharField(max_length=200, blank=True)
description = models.TextField(null=True, blank=True)
order
shop = models.ForeignKey(Shop, models.CASCADE, null=True)
customer = models.ForeignKey(Customer, models.CASCADE, null=True)
product = models.ForeignKey(Product, models.CASCADE, null=True)
quantity = models.CharField(max_length=30)
date_created = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=200, choices=STATUS, default='Pending')
note = models.CharField(max_length=1000, null=True)
when customers login then the shop will print on the screen and a button on shop to show the products by the shop in the form card. On the product card, there is an order button that adds the product in order after submitting the selected product will print with the remaining filled of order that shown in the image
how I create order form show that I get the id of shop and product
If you are getting the id of shop and product then you can create order in this way
def your_view_function(request,shop_id,product_id):
customer = request.user.customer
shop = Shop.objects.get(id=shop_id)
product = Product.objects.get(id=product_id)
# assuming you are getting value of quantity and note
quantity = request.POST.get('quantity')
note = request.POST.get('note')
# or you are getting quantity and note from form
order = Order.objects.create(customer=customer,shop=shop,product=product,quantity=quantity,note=note)

Update an instance of a model in django such that the older instance and its relationship with other instances remain unaffected

I have been working on a e-commerce project. I have three models Item, OrderItem, Order. They are linked with Foreignkey(s) (Item -> OrderItem -> Order). Item is the actual product and an Order contain(s) Item(s).
Item basically represents a product. In Item there is an attribute 'price' which needs to updated as need suggest. Like during a sale or something else.
What happens is when I update the price of an Item, the price of that item also gets updated in the instances of the Order(s) that are already completed.
Basically I would want to separate these models in a way such that any changes in the Item model doesn't effect the Orders that are completed.
class Item(models.Model):
title = models.CharField(max_length=100)
sku = models.CharField(max_length=8, validators=[
MinLengthValidator(8)], unique=True)
upc = models.CharField(max_length=12, validators=[
MinLengthValidator(12)], unique=True, blank=True, null=True)
date_updated = models.DateTimeField(
auto_now=True, blank=True, null=True)
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()
image = models.ImageField(upload_to=upload_location, blank=True, null=True)
stock_quantity = models.IntegerField(default=0)
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)
item_variations = models.ManyToManyField(ItemVariation)
quantity = models.IntegerField(default=1)
purchase = models.FloatField(blank=True, null=True)
def get_total_item_price(self):
return self.quantity * self.item.price
class Order(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE)
ref_code = models.CharField(
max_length=20, blank=True, null=True, unique=True)
items = models.ManyToManyField(OrderItem)
start_date = models.DateTimeField(auto_now_add=True)
# Check this
ordered_date = models.DateTimeField()
# When the payment is made it becomes True
ordered = models.BooleanField(default=False)
shipping_address = models.ForeignKey(
'Address', related_name='shipping_address', on_delete=models.SET_NULL, blank=True, null=True)
billing_address = models.ForeignKey(
'Address', related_name='billing_address', on_delete=models.SET_NULL, blank=True, null=True)
payment = models.ForeignKey(
'Payment', on_delete=models.SET_NULL, blank=True, null=True)
coupon = models.ForeignKey(
'Coupon', on_delete=models.SET_NULL, blank=True, null=True)
being_delivered = models.BooleanField(default=False)
received = models.BooleanField(default=False)
refund_requested = models.BooleanField(default=False)
refund_granted = models.BooleanField(default=False)
refund_refused = models.BooleanField(default=False)
Any help will be appreciated, thank you.
You could have ItemPrice as a separate model with a One-to-Many relationship. Which prices for the item are stored with associated date changed.
models.py
class ItemPrice(models.Model):
item = models.ForeignKey(Item, on_delete=models.CASCADE)
price = models.FloatField()
date_changed = models.DateTimeField(auto_now=True, blank=True, null=True)
Then align your order date with the items price at that current time.

Django Simple Left Join

How can I display all related values from my model and display in template as one?
class DentalProcedures(models.Model):
id = models.AutoField(primary_key=True)
patient = models.ForeignKey(PatientInfo, on_delete=models.CASCADE, null=True, blank=True)
proc_date = models.DateField(null=True, blank=True)
proc_tooth_no = models.CharField('Tooth No./s', max_length=10, null=True, blank=True)
procedure = models.CharField('Procedure', max_length=200, null=True, blank=True)
amount_charged = models.IntegerField('Amount Charged', null=True, blank=True)
class DentalPayment(models.Model):
id = models.AutoField(primary_key=True)
procedureid = models.ForeignKey(DentalProcedures, on_delete=models.CASCADE, null=True, blank=True)
patient = models.ForeignKey(PatientInfo, on_delete=models.CASCADE, null=True, blank=True)
amount_paid = models.IntegerField('Amount Paid', null=True, blank=True)
date_paid = models.DateField(null=True, blank=True)
I want to display the patient summary of payment including the, procedure name, amount charged and payment details.
View
class DentalPaymentDetailView(DetailView):
context_object_name = "payment_detail"
model = PatientInfo
template_name = "patient/procedure_payment_detail.html"
def get_context_data(self, **kwargs):
context = super(DentalPaymentDetailView, self).get_context_data(**kwargs)
payment = DentalPayment.objects.filter(patient=self.kwargs['pk'])
context["payment"] = payment.DentalProcedures_set.all()
return context
If you have some logic to provide the patient_id, try this
context["payment"] = DentalPayment.objects.filter(patient_id=patient_id).values('procedureid__procedure', 'procedureid__amount_charged', 'amount_paid', 'date_paid')
to get total amount paid,
from django.db.models import Sum
total_amount = DentalPayment.objects.filter(patient_id=patient_id).aggregate(tota_amount_paid=Sum('amount_paid'))