Reputation: 145
I have defined two models for retailers and items in their stock. Product is defined in another app. I defined two model methods to get and add stock items. Here is the relevant part of the code:
class Retailer(models.Model):
name = models.CharField(max_length=100)
@property
def stock_items(self):
return StockItem.objects.filter(retailer__id=F('id'))
def add_stock_item(self, product_id):
try:
print "Checking if it's already in stock"
self.stock_items.get(product__id=product_id)
print "It's already in stock"
except ObjectDoesNotExist:
try:
print "Adding item to stock"
product = Product.objects.get(pk=product_id)
StockItem.objects.create(retailer=self, product=product)
print "Added to stock"
except Product.DoesNotExist:
print "Such product doesn't exist"
def __unicode__(self):
return self.name
StockItem(models.Model):
retailer = models.ForeignKey(Retailer)
product = models.ForeignKey(Product)
def __unicode__(self):
return "%s - %s %s" % (self.retailer, self.product.brand, self.product)
When I want to use these model methods, something weird happens. They stop working correctly after adding the first item (In these examples, product 1 is 16 GB iPhone and Product 2 is 32 GB iPhone).
First let's add some products to our stock:
>>> r = Retailer.objects.get(pk=1)
>>> r.stock_items
[]
>>> r.add_stock_item(1)
Checking if it's already in stock
Adding item to stock
Added to stock
>>> r.add_stock_item(2)
Checking if it's already in stock
Adding item to stock
Added to stock
So far so good. Now let's try adding products again to see how it handles errors:
>>> r.add_stock_item(1)
Checking if it's already in stock
It's already in stock
>>> r.add_stock_item(2)
Checking if it's already in stock
Adding item to stock
Added to stock
What? Why did it add product 2 again. It was supposed to show a message similar to product 1. Let's see our stock:
>>> r.stock_items
[<StockItem: hh - Apple iPhone 4S 16GB>]
What happened to product 2? Did it fail to add it to database?
[<StockItem: hh - Apple iPhone 4S 16GB>, <StockItem: hh - Apple iPhone 4S 32GB>, <StockItem: hh - Apple iPhone 4S 32GB>]
Apparently not. It was added to database, but somehow our program fails to check it correctly. Only the first product added to stock is shown by calling r.stock_items. Restarting shell doesn't change the situation either, so I guess the reason couldn't be because of when the function is evaluated.
Why does this happen and how can I fix it?
Upvotes: 0
Views: 82
Reputation: 599610
The reason why your method was failing is because that expression doesn't do what you think it does. The F()
syntax is for comparing values within the same row: so that expression was checking that the related retailer ID was the same as the current row's ID. It so happened that this was true for the first item, but it would never be true of any subsequent items, because the row ID has incremented with the new items but the retailer ID remains the same.
Upvotes: 1
Reputation:
Try to remove @property
and change the method to this:
def stock_items(self):
return self.stockitem_set.all()
Upvotes: 1