pythondjangodjango-2.2

Django admin saves a copy of the object instead of overwrite


I have a model with OneToOneFiled named alg_id, and when I go to admin panel and change this filed in existing object, then a new object is created, but I'd like to overwrite same object with different alg_id. When I change other simple text fileds - all works fine. If I change alg_id to one, that already exists in Database, then that object gets overwritten - will be better if I'll get a warning here..

How could I achieve that?

ps. this project use 2.2.6 Django version

models.py :

from django.db import models
from django.utils.translation import gettext_lazy as _

class AchievementInfo(models.Model):

    GROUPS = (
        ('Results', 'Results'),
        ('Service', 'Service'),
        ('Team', 'Team'),
        ('Development', 'Development')
    )

    algorithm_id = models.OneToOneField(
        'core.Algorithms',
        models.DO_NOTHING,
        verbose_name=_('Alg id'),
        primary_key=True,
    )
    role_key = models.CharField(_('Role'), max_length=25)
    group = models.CharField(_('Group'), max_length=50, choices=GROUPS)
    name = models.CharField(_('Name'), max_length=100)
    web_name = models.CharField(_('Shown name'), max_length=75)

    class Meta:
        db_table = 'achievements_guide'
        default_permissions = ()
        ordering = ('web_name', 'role_key', 'algorithm_id')
        verbose_name = _('Achievement')
        verbose_name_plural = _('Achievements')

    def __str__(self):
        return f'{self.algorithm_id}: {self.name}, {self.web_name}, {self.role_key}'

admin.py:

from django.contrib import admin
from achievements.models import AchievementInfo

@admin.register(AchievementInfo)
class AchiAdmin(admin.ModelAdmin):
    list_display = ("web_name", "group", "role_key", "algorithm_id")
    list_filter = ("web_name", "role_key")  
    raw_id_fields = ("algorithm_id", )

Solution

  • Django tracks the object you're trying to edit or add only by a primary_key. If the newly set primary key matches some object in the database, this object will be replaced when saving the newly created object. Similarly, if you change your primary key and save the object, Django will not update the old one, but create the new one (or replace newly matching one, if applicable) instead.

    As you are using your OneToOneField as a primary key for your object, what you want to achieve is not possible without a complex, additional logic when saving your object.

    Instead, you can just create additional field as your primary key (or let Django do it for you by not using primary_key=True in any of the fields in your model), so Django can properly track by itself which object are you editing.