2011-08-19 108 views
1

我試圖在我的應用程序中編寫一個內部API,而不必將它與數據庫耦合。如果我叫p.save()& i.save()調用p.image_set前Django:將對象添加到相關集而不保存到數據庫

IntegrityError: products_images.product_id may not be NULL 

然而,:

class Product(models.Model): 
    name=models.CharField(max_length=4000) 
    price=models.IntegerField(default=-1) 
    currency=models.CharField(max_length=3, default='INR') 

class Image(models.Model): 
    # NOTE -- Have changed the table name to products_images 
    width=models.IntegerField(default=-1) 
    height=models.IntegerField(default=-1) 
    url=models.URLField(max_length=1000, verify_exists=False) 
    product=models.ForeignKey(Product) 

def create_product: 
    p=Product() 
    i=Image(height=100, widght=100, url='http://something/something') 
    p.image_set.add(i) 
    return p 

現在,當我打電話create_product()Django的拋出了一個錯誤。添加(我)它的作品。有沒有什麼方法可以將對象添加到相關的對象集中,而不必先保存到數據庫?

回答

2
def create_product(): 
    product_obj = Product.objects.create(name='Foobar') 
    image_obj = Image.objects.create(height=100, widght=100, url='http://something/something', product=product_obj) 
    return product_obj 

說明: Product對象必須首先創建,然後它,因爲ID和名稱這裏是必填字段分配給Image對象。

我想知道爲什麼你不需要在第一種情況下在數據庫中輸入產品?如果有任何具體原因,那麼我可能會建議你解決一些問題?

編輯:好吧!我想我已經得到了你,你不想最初把一個產品分配給一個圖像對象。如何將產品字段創建爲null等於true。

product = models.ForeignKey(Product, null=True) 

現在,你的功能變得像這樣:

def create_product(): 
     image_obj = Image.objects.create(height=100, widght=100, url='http://something/something') 
     return image_obj 

希望它可以幫助你嗎?

+0

感謝您的回覆。但是,由於對象是在一個函數中創建的,而函數是內部API的一部分,所以我不想將它們保存到數據庫中。在這一點上,物體很可能處於不完整的狀態。 –

+0

另外,如果我使用你的建議,我會損害數據庫的一致性。沒有與產品關聯的圖像不能存在於數據庫中。如果我要強制執行此操作,則必須在數據庫事務塊內完成整個函數調用,以便在發生錯誤時(將映像保存到數據庫後)數據庫將回滾到一致狀態。在我看來,解耦API的假設太多了。 –

0

你的問題是,ID不是由django設置的,而是由數據庫(它在數據庫中由自動遞增的字段表示)設置的,所以直到它被保存,沒有ID。更多關於in the documentation

我能想到的三種可能的解決方案:

  1. 設置你的圖像模型的不同字段作爲主鍵(記錄here)。
  2. 將生產模型的不同字段設置爲外鍵(記錄爲here)。
  3. 使用django的數據庫事務API(記錄here)。
0

我得到@Saurabh南大

我使用Django 1.4.2同樣的問題。當我在Django閱讀,我看到

# file django/db/models/fields/related.py 
def get_query_set(self):            
    try:                
     return self.instance._prefetched_objects_cache[rel_field.related_query_name()] 
    except (AttributeError, KeyError):         
     db = self._db or router.db_for_read(self.model, instance=self.instance) 
     return super(RelatedManager,self).get_query_set().using(db).filter(**self.core_filters) 


# file django/db/models/query.py 
qs = getattr(obj, attname).all()           
qs._result_cache = vals             
# We don't want the individual qs doing prefetch_related now, since we 
# have merged this into the current work.         
qs._prefetch_done = True             
obj._prefetched_objects_cache[cache_name] = qs 

那就是讓澀澀的,我們只需要設置屬性_prefetched_objects_cache的對象。

p = Product() 
image_cached = [] 
for i in xrange(100): 
    image=Image(height=100, widght=100, url='http://something/something') 
    image_cached.append(image) 
qs = p.images.all() 
qs._result_cache = image_cached 
qs._prefetch_done = True 
p._prefetched_objects_cache = {'images': qs}