简体   繁体   中英

Django: Adding objects to a related set without saving to DB

I'm trying to write an internal API in my application without necessarily coupling it with the database.

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

Now, when I call create_product() Django throws up an error:

IntegrityError: products_images.product_id may not be NULL

However, if I call p.save() & i.save() before calling p.image_set.add(i) it works. Is there any way that I can add objects to a related object set without saving both to the DB first?

I got same issue with @Saurabh Nanda

I am using Django 1.4.2. When I read in django, i see that

# 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

That 's make sese, we only need to set property _prefetched_objects_cache for the object.

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}
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

Explanation: Product object has to be created first and then assign it to the Image object because id and name here is required field.

I am wondering why wouldn't you not require to make a product entry in DB in first case? If there is any specific reason then i may suggest you some work around?

EDIT: Okay! i think i got you, you don't want to assign a product to an image object initially. How about creating a product field as null is equal to true.

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

Now, your function becomes something like this:

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

Hope it helps you?

Your problem is that the id isn't set by django, but by the database (it's represented in the database by an auto-incremented field), so until it's saved there's no id. More about this in the documentation .

I can think of three possible solutions:

  1. Set a different field of your Image model as the primary key (documented here ).
  2. Set a different field of your Production model as the foreign key (documented here ).
  3. Use django's database transactions API (documented here ).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM