Django не может изменить имя пользователя в пользовательской модели User
У меня есть следующая модель User в Django models.py
:
class User(AbstractBaseUser):
username = models.CharField(max_length=30, unique=True, primary_key=True)
full_name = models.CharField(max_length=65, null=True, blank=True)
email = models.EmailField(
max_length=255, unique=True, validators=[EmailValidator()]
)
При попытке обновить имя пользователя через shell python manage.py shell
:
userobj = User.objects.get(username="username1")
userobj.username = user.lower()
userobj.save()
Похоже, что он пытается создать нового пользователя, для которого нарушено ограничение UNIQUE электронной почты:
django.db.utils.IntegrityError: UNIQUE constraint failed: data_app_user.email
Есть ли какие-нибудь решения? Спасибо!
Это происходит потому, что поле username является первичным ключом в вашей модели. Изменение первичного ключа объекта и вызов save приведет к созданию нового объекта.
В этом случае лучше использовать другое поле в качестве первичного ключа:
class User(AbstractBaseUser):
id = models.IntegerField(primary_key=True)
username = models.CharField(max_length=30, unique=True)
... # other fields
Кроме того, если вы хотите обновить некоторые поля экземпляра, лучше использовать метод update класса QuerySet
.
>>> User.objects.filter(username=old_username).update(name=new_username)
Это одна из причин не использовать username
в качестве первичного ключа. Действительно, Django использует первичный ключ в качестве маркера, чтобы проверить, являются ли два элемента одинаковыми. Если первичный ключ изменится, и вы сохраните его, он сначала попытается обновить пользователя с этим первичным ключом, а если это не удастся, выполнит вставку.
Таким образом, это может привести к нескольким нежелательным сценариям: один из них - дублирование данных, в случае если новый первичный ключ не существует, но, возможно, даже хуже: это может привести к копированию данных пользователя в запись "нового" имени пользователя, и таким образом, по сути, переопределить данные этого пользователя.
Как правило, лучше считать первичные ключи "значениями черного ящика". Да, AutoField
работает с целым числом, но лучше предположить, что это токен, детали которого нам неизвестны. Тот факт, что это целое число,
In most database courses, one learns that the primary key is the (subset of) column(s) that makes a record unique, and from a database perspective, that is the right approach, but it is a "Djangoism" that the primary keys use a uniform type, and often don't store real information. This is also useful if you would later work with a GenericForeignKey
[Django-doc], so that means there are essentially two options: using an AutoField
, or a UUIDField
, but regardless, it is better not to store information in the primary key.
Если вы действительно хотите настоять на своем, вы можете обновить первичный ключ с помощью:
User.objects.filter(pk='username1').update(pk='username2')
В результате запрос будет выглядеть следующим образом:
UPDATE app_name_user
SET username = 'username2'
WHERE username = 'username1'
Но это, вероятно, тоже не лучшая идея, поскольку теперь вы опускаете валидацию, сигналы и все остальные "механики", которые Django предусмотрел.
So I would strongly advise to rewrite the model and don't make username
the primary key. You can still set it unique=True
[Django-doc].