Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django giving Cannot force an update in save() with no primary key

Tags:

django

I'm getting ValueError: Cannot force an update in save() with no primary key. while code hitting to exception and run get_or_create code. Model has it's table in database with auto incremental id field. And also this is not an update process. I can't get why Django behaving like this.

ERROR:

Traceback (most recent call last):
  File "x.py", line 1980, in <module>
    getattr(a, islem)()
  File "x.py", line 718, in method
    Slug='undefined', Status=False)
  File "~/env/local/lib/python2.7/site-packages/django/db/models/manager.py", line 135, in get_or_create
    return self.get_query_set().get_or_create(**kwargs)
  File "~/env/local/lib/python2.7/site-packages/django/db/models/query.py", line 385, in get_or_create
    obj.save(force_insert=True, using=self.db)
  File ~/core/modules/xx/models.py", line 78, in save
    super(Categories, self).save(args, kwargs)
  File "~/env/local/lib/python2.7/site-packages/django/db/models/base.py", line 460, in save
    self.save_base(using=using, force_insert=force_insert, force_update=force_update)
  File "x/env/local/lib/python2.7/site-packages/django/db/models/base.py", line 541, in save_base
    raise ValueError("Cannot force an update in save() with no primary key.")
ValueError: Cannot force an update in save() with no primary key.

CODE:

try:
    category = Categories.objects.get(Code=category_code)
except ObjectDoesNotExist:
    category, created = Categories.objects.get_or_create(
        Name='Undefined', Code='undefined',ParentCategoryID=None, OrderID=0,
        Slug='undefined', Status=False)

MODEL:

class Categories(models.Model):
    Name = models.CharField(max_length=155)
    Code = models.CharField(max_length=255)
    ParentCategoryID = models.ForeignKey('self', related_name='SubCategory', null=True, blank=True)
    Level = models.IntegerField(default=0, max_length=10, editable=False)
    OrderID = models.IntegerField(blank=True, max_length=10)
    Slug = models.SlugField(max_length=250)
    CreateDate = models.DateTimeField(auto_now_add=True)
    LastUpdateDate = models.DateTimeField(auto_now=True)
    Status = models.BooleanField(default=True)

    def save(self, *args, **kwargs):

        if self.ParentCategoryID is not None:
            parent = Categories.objects.get(id=self.ParentCategoryID.id)
            self.Level = parent.Level + 1

        if self.OrderID <= 0:
            try:
                top = Categories.objects.order_by('-OrderID')[0]
                self.OrderID = top.OrderID + 1
            except:
                self.OrderID = 1
        super(Categories, self).save(args, kwargs)
like image 234
Sencer H. Avatar asked Mar 03 '17 13:03

Sencer H.


1 Answers

You need to use the * and ** when you call super as well:

super(Categories, self).save(*args, **kwargs)

Note there are some other strange things in this code too. Primarily this line:

parent = Categories.objects.get(id=self.ParentCategoryID.id)

is doing two identical queries for no reason; self.ParentCategoryID is already the parent object. You should just do:

parent = self.ParentCategoryID

which should lead you to the conclusion that the ParentCategoryID is badly named; it contains the actual object, not the ID.

Note also that there are quite a few style violation; Python prefers lower_case_with_underscore for attribute names, and Django prefers singular model names. The related name for the foreign key should be plural, though, as it will refer to multiple category objects. So:

class Category(models.Model):
    name = models.CharField(max_length=155)
    code = models.CharField(max_length=255)
    parent_category = models.ForeignKey('self', related_name='sub_categories', null=True, blank=True)
    ...
like image 71
Daniel Roseman Avatar answered Oct 04 '22 15:10

Daniel Roseman