I'm trying to export a csv with information from the model order which has a relation 1 to 1 with delivery channel and restaurant and a 1 to many relationship with orderlines. It is taking way too much time for download it (around 20 seconds for 10k lines).
This is my code:
orderlines = OrderLine.objects.select_related("product").only(
"product__display_name", "quantity", "paid_amount", "discount_amount"
)
return (
Order.objects.prefetch_related(Prefetch("orderlines", queryset=orderlines, to_attr="orderlines_list"))
.select_related("delivery_channel")
.select_related("restaurant")
)
These are my models:
class Order(TimeStampedModel, TenantModel):
id = models.AutoField
objects = OrderManager()
restaurant = models.ForeignKey(
Restaurant,
blank=False,
null=False,
on_delete=models.PROTECT,
help_text=_("References the restaurant the order is for"),
)
delivery_channel = models.ForeignKey(
DeliveryChannel,
blank=False,
null=False,
on_delete=models.PROTECT,
)
class Restaurant(TenantModel):
id = models.AutoField
name = models.CharField(max_length=255, blank=False, null=False, default="", unique=False)
class DeliveryChannel(models.Model):
id = models.AutoField
name = models.CharField(
max_length=255, blank=False, null=False, unique=True, default="",
)
class OrderLine(TimeStampedModel, TenantModel):
id = models.AutoField
order = models.ForeignKey(
Order,
blank=False,
null=False,
on_delete=models.CASCADE,
related_name="orderlines",
)
product = models.ForeignKey(
Product, blank=False, null=False, on_delete=models.CASCADE,
)
unit_price = models.DecimalField(
blank=False,
null=False,
max_digits=8,
decimal_places=2,
)
quantity = models.IntegerField(blank=False, null=False, unique=False)
paid_amount = models.DecimalField(
blank=False,
null=False,
max_digits=8,
decimal_places=2,
)
discount_amount = models.DecimalField(
blank=False,
null=False,
max_digits=8,
decimal_places=2,
help_text=_("Amount of the discount applied to the product"),
)
class Product(TenantModel):
id = models.AutoField
objects = ProductManager()
display_name = models.CharField(max_length=255, blank=False, null=False, unique=False)
I thought about using only in the end but I can't use it on orderlines as it is a 1 to many relationship. I'm stuck on how to improve the performance. Many thanks.
You can use .only(…) [Django-doc], but you need to add the foreign key to the model itself, otherwise this will result in another N+1 problem: where it will each time have to make a query to determine to what Order it belongs, so:
orderlines = OrderLine.objects.select_related('product').only(
'product__display_name',
# add ForeignKey to the Order object ↓
'quantity', 'paid_amount', 'discount_amount', 'order'
)
return Order.objects.prefetch_related(
Prefetch('orderlines', queryset=orderlines, to_attr='orderlines_list')
).select_related(
'delivery_channel'
'restaurant'
)
Related
Models.py
class BaseModel(models.Model):
branch = models.ForeignKey(Branch, on_delete=models.PROTECT, blank=True, null=True)
company = models.ForeignKey(
Company, on_delete=models.PROTECT, blank=True, null=True
)
class Meta:
abstract = True
class MealMenu(BaseModel):
employee = models.ForeignKey(
Employee, on_delete=models.PROTECT, null=True, blank=True
)
item_name = models.CharField(max_length=50, null=True, blank=True)
quantity = models.PositiveIntegerField()
price = models.FloatField()
def __str__(self):
return f"{self.item_name} {self.price}"
class MealOrder(BaseModel):
RECEIVED = "Received"
PENDING = "Pending"
REJECTED = "Rejected"
MEAL_CHOICES = (
("Breakfast", "Breakfast"),
("Lunch", "Lunch"),
("Dinner", "Dinner"),
)
STATUS_CHOICES = (
(RECEIVED, "Received"),
(PENDING, "Pending"),
(REJECTED, "Rejected"),
)
id = models.UUIDField(primary_key=True, default=uuid.uuid4, null=False)
total_items = models.IntegerField(null=True, default=0)
total_amounts = models.FloatField(default=0.0)
menu = models.ForeignKey(MealMenu, on_delete=models.PROTECT)
quantity = models.PositiveIntegerField(default=1, blank=False)
meal_time = models.CharField(max_length=25, choices=MEAL_CHOICES)
employee = models.ForeignKey(Employee, on_delete=models.PROTECT)
date = models.DateField(auto_now=True)
status = models.CharField(max_length=25, choices=STATUS_CHOICES, default=PENDING)
I have two models. In First Model i have created a menu item_name,price and quantity.
In MealOrder i have foreign key MealMenu Model and created quantity field separately.
I want to select multiple items with their multiple quantities. But i can't understand the scenario.
So you could have a separate model to handle the quantity for different items in an order.
Like this:
class MealOrderItem(BaseModel):
order = models.ForeignKey(
MealOrder, on_delete=models.PROTECT, null=True, blank=True
)
quantity = models.PositiveIntegerField()
meal = ForeignKey(
MealMenu, on_delete=models.PROTECT, null=True, blank=True
)
This will help you create multiple meal menu selections for an order with each having its own quantity.
I am new in web development with Django and MySQL database, I got to develop a web application with Django framework, after deployment of my project in the server.
after 2 months, I noticed that data from my order table was deleted as well as the data of one user is displayed in the profile of another,
I want to know what I must do as a test to know the PR eventual error and to stop the deletion of data in my database.
data often deleted in the order and customer table.
the ORDER model bind with a foreign key to other Model:
class Order(models.Model):
user = models.ForeignKey(User, null=True, blank=True, on_delete=models.CASCADE)
created = models.DateTimeField( auto_now_add=True, verbose_name=_('Creation Date'))
payed = models.DateTimeField( verbose_name=_('Payment Date'), default=datetime.now, null=True, blank=True)
reference = models.IntegerField( verbose_name=_('Order Reference'), default=0, null=True, blank=True )
customer = models.ForeignKey( Customers, verbose_name=_('Customer'), null=True, blank=True, on_delete=models.CASCADE )
company = models.ForeignKey( Compagnie, verbose_name=_('Company'), null=True, blank=True, on_delete=models.CASCADE )
class Customers(models.Model):
company = models.ForeignKey(
Compagnie,
verbose_name=_('Company'),
null=True,
blank=True,
on_delete=models.CASCADE
)
forename = models.CharField(
verbose_name=_('First Name'),
max_length=255,
null=True,
blank=True)
GENDER = [('M', _('Male')),
('F', _('Female'))]
gender = models.CharField(
verbose_name=_('Gender'),
max_length=1,
choices=GENDER,
null=True,
blank=True)
city = models.ForeignKey(
City,
verbose_name=_('City'),
null=True,
blank=True,
on_delete=models.CASCADE
)
additionalNum = models.CharField(
verbose_name=_('Additional Number:'),
max_length=60,
null=True,
blank=True,
)
adressCustomer = models.TextField(
verbose_name=_('Address Customer:'),
max_length=500,
null=True,
blank=True,
)
telCustomer = models.CharField(
verbose_name=_('Phone Customer:'),
max_length=30,
null=True,
blank=True,
)
emailCustomer = models.EmailField(
verbose_name=_('Email Customer:'),
null=True,
blank=True,
)
otherBuyerId = models.CharField(
verbose_name=_('Other Buyer ID:'),
max_length=50,
null=True,
blank=True
)
vatNumber = models.CharField(
max_length=120,
null=True,
verbose_name=_('Vat Number:'),
blank=True
)
needs_attention = models.BooleanField(
verbose_name=_('Needs attention'),
default=False)
biography = models.TextField(
verbose_name=_('Biography'),
null=True,
blank=True)
_is_updating_cache_fields = False
def get_name(self):
first = self.forename or ''
name = "%s" % (first)
return name.strip()
class Meta:
verbose_name = _('Customer')
verbose_name_plural = _('Customers')
def __unicode__(self):
return u'%s %s: %s' % (
type(self).__name__,
self.pk,
self.forename)
def __str__(self):
if self.forename:
return self.forename
else:
return "Unnamed"
Can someone give me an explanation for this problem?
Currently im working on an Ecommerce project in Django where i have a Order model which has Foreign key relation with Product. So all the product details are fetched from product model. Now im facing issue with the same. Whenever I make any change to Product object its getting updated in all the related Order objects too even for orders placed in past.
Is it possible to keep past order's product values unchanged whenever Product object is updated in future? Please help. Below are the codes for your reference.
Product Model
class Product(models.Model):
measurement_choices = (('Liter', 'Liter'), ('Kilogram', 'Kilogram'), ('Cloth', 'Cloth'),
('Shoe', 'Shoe'))
name = models.CharField(max_length=200)
sku = models.CharField(max_length=30, null=True)
stock = models.CharField(max_length=10, null=True)
measurement = models.CharField(choices=measurement_choices, max_length=20, null=True)
description = models.CharField(max_length=10000)
price = models.DecimalField(max_digits=7, decimal_places=2)
discounted_price = models.DecimalField(max_digits=7, decimal_places=2, null=True, blank=True)
image = models.ImageField(upload_to='product/images', default='product.png', null=True,
blank=True)
image_one = models.ImageField(upload_to='product/images', null=True, blank=True)
image_two = models.ImageField(upload_to='product/images', null=True, blank=True)
image_three = models.ImageField(upload_to='product/images', null=True, blank=True)
image_four = models.ImageField(upload_to='product/images', null=True, blank=True)
image_five = models.ImageField(upload_to='product/images', null=True, blank=True)
tags = models.ManyToManyField(Tags)
category = models.ForeignKey(Category,on_delete=models.SET_NULL,null=True,blank=True)
sub_category = models.ForeignKey(SubCategory, on_delete=models.SET_NULL,
null=True,related_name='+')
status = models.CharField(max_length=20, choices=(('Active', 'Active'), ('Inactive',
'Inactive')))
brand = models.ForeignKey(Brand,on_delete=models.PROTECT,blank=True, null=True)
offer = models.ForeignKey(Offer, on_delete=models.CASCADE, null=True, blank=True)
color = models.ForeignKey(Color , blank=True, null=True , on_delete=models.PROTECT)
size_type = models.ForeignKey(Size , blank=True, null=True , on_delete=models.PROTECT)
history = HistoricalRecords()
Order Model
class Order(models.Model):
order_status = (('Pending', 'Pending'), ('Under Process', 'Under Process'), ('Dispatched',
'Dispatched'),
('Delivered', 'Delivered'), ('Cancelled', 'Cancelled'), ('Out for delivery',
'Out for delivery'))
customer = models.ForeignKey(Customer, on_delete=models.SET_NULL, null=True, blank=True)
shipping_address = models.ForeignKey(ShippingAddress, on_delete=models.DO_NOTHING, null=True,
blank=True)
order_created = models.DateTimeField(auto_now_add=True,null=True)
date_ordered = models.DateTimeField(null=True)
complete = models.BooleanField(default=False)
transaction_id = models.CharField(max_length=100, null=True)
order_number = models.CharField(max_length=20, unique=True, null=True)
status = models.CharField(choices=order_status, default='Pending', max_length=30)
payment_status = models.CharField(choices=(('Received', 'Received'), ('Failed', 'Failed'),
('Pending', 'Pending')),
default='Pending', max_length=30)
ip_address = models.CharField(max_length=30, null=True)
# Payment details captured from payment gateway
payment_order_id = models.CharField(max_length=100, null=True) # razorpay order id
payment_id = models.CharField(max_length=100, null=True) # Razorpay payment id
payment_signature = models.CharField(max_length=100, null=True)# razorpay paymnet signature
payment_method = models.CharField(max_length=100, null=True)
history = HistoricalRecords()
I think there are a few options for you here if I understand your question correctly.
Either you can serialize the actual product details when saving the order. This could be done by using Django serialization and then storing this serialized product on the order with a JSONField. This way you'll keep the state for a product if you want to display or use the data later.
Another way would be to store a new product with a version ID, instead of updating your old products. This could be done by hooking on the pre save, creating a new version and blocking the saving of the old model. This way you'll store and can reuse the model in your templates. https://docs.djangoproject.com/en/3.2/topics/signals/
The last idea would be to use a historical model insert, such as django-simple-history. This would handle changes and updates for you, but you'll have to relate to a given history instance.
I am designing django models for a E-commerce market place site where user can buy 4 type of products . Like I have 4 type of diff models for them .
For clothes
class Merchandise(models.Model):
adOwner = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
imagesMerchandise = models.ManyToManyField(merchandiseImages)
productName = models.CharField(max_length=50, null=False, blank=False)
price = models.IntegerField()
availableQuality=models.IntegerField()
color=models.CharField(max_length=20, null=False, blank=False)
size = models.CharField(max_length=50 , null=False , blank=False)
description=models.CharField(max_length=250 , null=False , blank=False)
is_approved = models.BooleanField(default=False)
def __str__(self):
return str(self.productName)
for Rent a Car
class Vehicle(models.Model):
adOwner=models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
carImages=models.ManyToManyField(Image)
make=models.CharField(max_length=50, null=False, blank=False)
modelName=models.CharField(max_length=50, null=False, blank=False)
registrationNumber=models.CharField(max_length=50, null=False, blank=False)
modelYear=models.CharField(max_length=50, null=False, blank=False)
modelColor=models.CharField(max_length=50, null=False, blank=False)
carType=models.CharField(max_length=50, null=False, blank=False)
fuelMileage=models.CharField(max_length=50, null=False, blank=False)
SeatingCapacity=models.CharField(max_length=50, null=False, blank=False)
vehicleCondition=models.CharField(max_length=50, null=False, blank=False)
fuelType=models.CharField(max_length=50, null=False, blank=False)
price=models.CharField(max_length=50, null=False, blank=False)
description=models.CharField(max_length=500, null=True, blank=True)
registerIn=models.CharField(max_length=500, null=True, blank=True)
is_approved = models.BooleanField(default=False)
def __str__(self):
return str(self.modelName)
book a hotel
class Accommodation(models.Model):
adOwner = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
hotleImages = models.ManyToManyField(HotleImages)
accommodationTitle=models.CharField(max_length=150)
location = models.CharField(max_length=150)
accommodationName = models.CharField(max_length=150)
checkIn = models.TimeField()
checkOut = models.TimeField()
# accessibility = models.CharField(max_length=20, null=False, blank=False)
address = models.CharField(max_length=150)
pets = models.CharField(max_length=150)
child = models.CharField(max_length=150)
is_approved = models.BooleanField(default=False)
Create a Activity
class ActivityOrganizer(models.Model):
adOwner = models.ForeignKey(VendorProfile, on_delete=models.CASCADE)
activityImage = models.ManyToManyField(ActivityImage)
activityName = models.CharField(max_length=50 , null=False, blank=False)
activityId = models.CharField(max_length=20, null=False, blank=False)
ageSuggestion = models.CharField(max_length=20, null=True, blank=True)
duration = models.CharField(max_length=20, null=False, blank=False)
openTime = models.TimeField()
closeTime=models.TimeField()
expiryDate = models.DateField()
availableQty = models.IntegerField()
price = models.IntegerField()
needToBring = models.CharField(max_length=50 , null=True , blank=True)
personsAllowOnOneTicket = models.IntegerField()
location = models.CharField(max_length=50 , null=True , blank=False)
specialNotes = models.CharField(max_length=250 ,null=True , blank=True)
description = models.CharField(max_length=250 , null=True , blank=True)
is_approved = models.BooleanField(default=False)
Now I made a order Table like this
class Orders(models.Model):
order_number = models.AutoField(primary_key=True)
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
ordertime = models.DateTimeField(auto_now_add=True)
user_note=models.CharField(max_length=150 , null=True, blank=True)
address=models.CharField(max_length=150 , null=True, blank=True)
order_status = models.CharField(choices=STATUS , max_length=50)
payment_status=models.BooleanField(default=0)
Now I am confuse how to bind all these 4 categories to my order object. as If its a for single category I can simply create a foreign key with order model. But How can I bind all these (as user can pick 1,2,3,4 number of categories ) so if user select Accommodation , and Vehicle categories products how I can save 2 categories null in foreign key. Any help would be highly appreciated . thanks
If you have small number of products (4 in your case) and for each order only one item of a type can be ordered, then you can simply add those to the Orders model with nullable fields
class Orders(models.Model):
order_number = models.AutoField(primary_key=True)
total_amount = models.DecimalField(max_digits=10, decimal_places=2)
ordertime = models.DateTimeField(auto_now_add=True)
user_note=models.CharField(max_length=150 , null=True, blank=True)
address=models.CharField(max_length=150 , null=True, blank=True)
order_status = models.CharField(choices=STATUS , max_length=50)
payment_status=models.BooleanField(default=0)
merchandise = models.ForeignKey(Merchandise, on_delete=models.CASCADE, null=True, blank=True)
vehicle = models.ForeignKey(Vehicle, on_delete=models.CASCADE, null=True, blank=True)
accommodation = models.ForeignKey(Accommodation, on_delete=models.CASCADE, null=True, blank=True)
activity_organizer = models.ForeignKey(ActivityOrganizer, on_delete=models.CASCADE, null=True, blank=True)
To list all the orders of a specific category, exclude all the orders with null in given field.
Orders.objects.exclude(merchandise__isnull=True)
Also if only a single category product is ordered rest 3 fields will be null, if you want to enforce that business logic then you can check for it by creating a signal.
I am building a website in django that will allow players to be matched with other players. I have the following model:
class Session(models.Model):
# id = AutoField(primary_key=True) added automatically.
sport = models.ForeignKey('Sport', unique=False, blank=False, null=False, on_delete=models.CASCADE, )
hostplayer = models.ForeignKey('Member', unique=False, blank=False, null=False, on_delete=models.CASCADE, related_name='member_host', )
guestplayer = models.ForeignKey('Member', unique=False, blank=True, null=True, on_delete=models.CASCADE, related_name='member_guest', )
date = models.DateField(blank=False, null=False, )
time = models.TimeField(blank=False, null=False, )
city = models.ForeignKey('City', unique=False, blank=False, null=False, on_delete=models.CASCADE, )
location = models.CharField(max_length=64, unique=False, blank=False, null=False, )
price = models.FloatField(unique=False, blank=False, null=False, default=0, )
details = models.TextField(unique=False, blank=True, null=False, )
def __unicode__(self):
return unicode(self.id)
As you can see, both hostplayer and guestplayer are foreign keys of the Member table.
The problem is that when I go into django admin, if I select the hostplayer as jack, I can also select the guestplayer as jack. This is obviously wrong as a player cannot play against himself.
How can I limit the options of guestplayer to not include the hostplayer?
Also, on the models level, is there a way to specify that the value of one attribute must be different from the value of another attribute in the same tuple? An obvious way would be to use forms and validate them but I am curious whether a simpler alternative exists.