Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Django: "Cannot assign must be a "X" instance", don't want to fetch the object

I have the following view on my Django app and I need to update one object

status_id is a ForeignKey field and it has some default values loaded via fixtures

def stopObject(request, id_object):
    object = Object.objects.get(id=id_object)
    object.status_id = 1
    object.save()

I’m getting the classical error where I need to assign the object, not its Id. There are countless questions on SO about this problem, but I came looking for an answer I didn’t found

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I know very well I can just perform a fetch from the database and assign to status, but I want to explore other possibilities, even though they may not be the best practices

EDIT sharing the models:

class Status(models.Model):
    id = models.AutoField(primary_key=True)
    description = models.CharField(max_length=32, unique=True)

class Object(models.Model):
    id = models.AutoField(primary_key=True)
    status_id = models.ForeignKey(Status,
                                  db_column="status_id",
                                  default=3,
                                  null=True,
                                  blank=True,
                                  related_name='objects',
                                  on_delete=models.SET_NULL)
    # other fields

>Solution :

status_id is a ForeignKey.

Normally one does not add a suffix …_id to a ForeignKey field, since Django will automatically add a "twin" field with an …_id suffix. Therefore it should be status, instead of status_id, so:

class Object(models.Model):
    status = models.ForeignKey(
        Status,
        default=3,
        null=True,
        blank=True,
        related_name='objects',
        on_delete=models.SET_NULL,
    )

this then also prevents having to specify the db_column='status_id'.

If you thus rename the field to status, you can use status_id. If not, you can use:

# if the field is named status
def stopObject(request, id_object):
    object = Object.objects.get(id=id_object)
    object.status_id = 1
    object.save()

If you decide to keep it status_id for some reason, we can use:

# if the field is remains status_id
def stopObject(request, id_object):
    object = Object.objects.get(id=id_object)
    object.status_id_id = 1
    object.save()

You can boost performance further by just updating the Object instead of fetching and saving:

# if the field is remains status_id
def stopObject(request, id_object):
    object = Object.objects.filter(id=id_object).update(status_id_id=1)

or with the renamed field:

# if the field is named status
def stopObject(request, id_object):
    object = Object.objects.filter(id=id_object).update(status_id=1)

Note: Django will add by default an AutoField [Django-doc] as primary_key=True to a model with name id if you do not specify a primary key yourself, so there is no need to explicitly declare a primary key.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading