sinθ
sinθ

Reputation: 11493

Django object not saving even after "save" call

I'm really at a loss because this makes no sense at all. I call save/create an object, and it dosn't show up in the admin site. I even checked the SQLite database with a SQLite Viewer program, which again showed that the item had not been saved.

This is the code that saves the Data object:

        data = Data(represents=field, for_entry=entry, value="This can be anything")
        # field is a DataField db object and entry is a Entry db object (see model below and paragraph)
        print("B4", data) #<---- Shows that Data has not been assigned an ID/pk
        data.save()
        print("8ER: ", data) #<--- Shows that Data has been assigned an ID/pk

As you can see from my comments, I know that the Data object is assigned an ID after the save call, which I would think meant that it worked. No error is thrown anywhere. field, and entry are all both. Each one seems to be ok, as in they have the right IDs, were retrieved with [table name].objects.get(id=...), and I can save/edit them and their saves change.

Even strange, this exact code in a function that is called right before this one works.

This is my model.py (I took out some functions to make it shorter):

class Entry(models.Model):
    parent = models.ForeignKey('Entry', blank = True, null = True, default=None) #  The entry this subs. Is left blank for top level entries.
    id_number = models.CharField(max_length=20)
    visible = models.BooleanField()
    data_field = models.ForeignKey('DataField', default=1)  # The field that this entire entry falls under. REDUNDANT BUT NECISSARY

    def __str__(self):
        return str(self.id)+ "-" + str(self.id_number) 

class DataField(models.Model):
    parent = models.ForeignKey('DataField', related_name='parent field', null=True, blank=True, default=1)
    order = models.IntegerField()
    multiple_entries = models.BooleanField(default=True)
    DATA_TYPES = (('t', 'Text'), ('d', 'Date'), ('l', 'List'), ('o', 'Option'), ('b', 'Boolean'), ('f', 'Foreign Key'), ('r', 'Root'), ('bb', 'Branch'), ('i', 'Image'), ('ff', 'File'), ('h', 'Holder'), ('bt', 'Big Text'))  # A number means it is a foreign key. Should go off title.
    foreign_source = models.ForeignKey('DataField', null=True, blank=True) #  Points to DATA FIELD WHO'S MATCHING DATA WILL MAKE UP THE OPTIONS
    data_type = models.CharField(max_length=2, choices=DATA_TYPES, default='t', null=True, blank=True)
    title = models.CharField(max_length=100, null=True, blank=True)
    visibility = models.BooleanField(default=False)

    def __str__(self):
        return str(self.id) + "-" + str(self.title)

    def __eq__(self, other):
        if not isinstance(other, DataField):
            return False
        if self.data_type == 'h':
            return self.title == other.title
        return self.id == other.id


class Data(models.Model):
    represents = models.ForeignKey('DataField')
    for_entry = models.ForeignKey('Entry', null=True)
    value = models.CharField(max_length=1000000)

    def __str__(self):
        return self.represents.title + "-" + str(self.for_entry.id) + "-" + str(self.value) + "-" + str(self.id)

It's possible that I'm missing something obvious, or maybe you need way more information than I can provide to fix it. If there is not enough information, please comment and request more info, or just list possible issues that could be happening.

Upvotes: 10

Views: 16955

Answers (4)

&#214;zer
&#214;zer

Reputation: 2106

I had the same issue. I solved it by assigned the object to a new variable, making my changes and saving the new variable:

    location = self.location  # self.location is set by other methods
    location.is_active = True
    location.save()

Upvotes: 4

user12212723
user12212723

Reputation: 11

Use django refresh_from_db() function in the object you need to be updated.

Upvotes: 1

Nick Brady
Nick Brady

Reputation: 6572

I had a similar issue doing a unit test and encountered an error where it appeared the save method wasn't working --> was as follows

p = MyModel.objects.get(pk=myparam)
self.assertEqual(p.my_attr, value) 
myfunc()  # Code that changed the same object p is referencing
self.assertEqual(p.my_attr, new_value)

The above failed even though I changed the object being referenced to the new value and then did .save() on the object.

To fix the issue, I had to reassign p to the MyModel object. My fixed code in the unit test looked something like this.

p = MyModel.objects.get(pk=myparam)
self.assertEqual(p.my_attr, value) 
myfunc()  # Code that changed the same object p is referencing
p = MyModel.objects.get(pk=myparam)
self.assertEqual(p.my_attr, new_value)

It appears to be an issue with the variable pointing to an old location in memory, but I only started programming 5 months ago so I'm in a little over my head :) I would really appreciate feedback if anyone can explain why this is happening as I'm still stumped.

If you REALLY don't think the save method is executing, you can do a sanity check by overwriting the save method and add a print statement. It might look similar to the following:

class MyModel(models.Model):
    attr = models.IntegerField(default=0)

    def save(self, *args, **kwargs):
        super(MyModel, self).save(*args, **kwargs)
        print('Did this attribute update? (attr):', self.attr)
        print('Save method executed!')

EDIT: Inline with the memory location theory, I made this simple example:

In [3]: a = 1
In [4]: b = a
In [5]: hex(id(a))
Out[5]: '0x100240280'
In [6]: hex(id(b))
Out[6]: '0x100240280'
In [7]: a = 2
In [8]: b
Out[8]: 1
In [9]: hex(id(a))
Out[9]: '0x1002402a0'
In [10]: hex(id(b))
Out[10]: '0x100240280'

Would still love to hear anyones thoughts.

Upvotes: 5

Sid
Sid

Reputation: 7631

Try a manual commit. I don't know what else to suggest.

from django.db import transaction

@transaction.commit_manually
def viewfunc(request):
    ...
    data.save()
    transaction.commit()

Upvotes: 3

Related Questions