Django ORM - Первичный ключ недоступен после сохранения при использовании UUIDField и RandomUUID в Postgres
Для проекта, над которым я работаю, в одной из моделей я использую models.UUIDField
для первичного ключа со значением по умолчанию django.contrib.postgres.functions.RandomUUID
Вот моя модель.
from django.contrib.postgres.functions import RandomUUID
from django.db.models import JSONField
class NewsItem(models.Model):
id = models.UUIDField(primary_key=True, default=RandomUUID())
title = models.ForeignKey(RichText, models.DO_NOTHING, related_name='+',
null=True)
subtitle = models.ForeignKey(RichText, models.DO_NOTHING, related_name='+',
null=True)
excerpt = models.ForeignKey(RichText, models.DO_NOTHING, related_name='+',
null=True)
text = models.ForeignKey(RichText, models.DO_NOTHING, related_name='+',
null=True)
image = models.ForeignKey(ImageObject, models.DO_NOTHING, related_name='+',
null=True)
priority = models.IntegerField(null=True, default=0)
frequency = models.IntegerField(null=True, default=1)
text_effects = JSONField(blank=True, null=True, default=dict)
scroll_speed = models.IntegerField(null=True, default=1)
scroll_direction = models.IntegerField(null=True, default=0)
created_at = models.DateTimeField(blank=True, null=True, auto_now_add=True)
updated_at = models.DateTimeField(blank=True, null=True, auto_now=True)
class Meta:
managed = True
db_table = 'news_items'
Проблема в том, что мне нужно немедленно получить доступ к первичному ключу после того, как объект был вставлен в базу данных, однако попытка получить доступ к pk
или id
после вызова save
просто возвращает литеральную строку RandomUUID()
In [1]: from media.models import NewsItem
In [2]: n = NewsItem()
In [3]: n.save()
In [4]: n.id
Out[4]: RandomUUID()
In [5]: str(n.id)
Out[5]: 'RandomUUID()'
Однако, если я выдаю запрос типа model.objects.first()
или model.objects.last()
, а затем обращаюсь к id
или pk
возвращенного экземпляра, все работает, как ожидалось.
In [6]: from media.models import NewsItem
In [7]: n = NewsItem.objects.first()
In [8]: n.id
Out[8]: UUID('9c485bd2-bb86-4aac-8d20-7cc85abec929')
In [9]: str(n.id)
Out[9]: '9c485bd2-bb86-4aac-8d20-7cc85abec929'
Это не может быть использовано, поскольку нет гарантии, что first
или last
вернет в базу данных строку, которую я только что вставил. Это навело меня на мысль, что, возможно, все, что мне нужно сделать, это просто вызвать obj.refresh_from_db()
. Однако это приводит к исключению DoesNotExist
.
In [12]: from media.models import NewsItem
In [13]: n = NewsItem()
In [14]: n.save()
In [15]: n.id
Out[15]: RandomUUID()
In [16]: n.refresh_from_db()
---------------------------------------------------------------------------
DoesNotExist Traceback (most recent call last)
<ipython-input-16-735aeb087dd1> in <module>
----> 1 n.refresh_from_db()
~/.var/envs/xkern/vdjango/lib/python3.9/site-packages/django/db/models/base.py in refresh_from_db(self, using, fields)
635 db_instance_qs = db_instance_qs.only(*fields)
636
--> 637 db_instance = db_instance_qs.get()
638 non_loaded_fields = db_instance.get_deferred_fields()
639 for field in self._meta.concrete_fields:
~/.var/envs/xkern/vdjango/lib/python3.9/site-packages/django/db/models/query.py in get(self, *args, **kwargs)
433 return clone._result_cache[0]
434 if not num:
--> 435 raise self.model.DoesNotExist(
436 "%s matching query does not exist." %
437 self.model._meta.object_name
DoesNotExist: NewsItem matching query does not exist.
In [17]:
Поэтому я попробовал другие решения, например, попытался явно вызвать model.objects.get(pk=inserted_obj.id)
или models.objects.filter(pk=inserted_obj.id)
.
Это тоже не работает. Вот выданный запрос для последнего варианта.
In [21]: q = NewsItem.objects.filter(pk=n.id)
In [22]: print(q.query)
SELECT "news_items"."id", "news_items"."title_id", "news_items"."subtitle_id", "news_items"."excerpt_id", "news_items"."text_id", "news_items"."image_id", "news_items"."priority", "news_items"."frequency", "news_items"."text_effects", "news_items"."scroll_speed", "news_items"."scroll_direction", "news_items"."created_at", "news_items"."updated_at" FROM "news_items" WHERE "news_items"."id" = GEN_RANDOM_UUID()
In [23]:
Очевидно, что это не сработает, поскольку в этом случае генерируется новый случайный uuid.
Я не знаю, как действовать дальше, и на данный момент уперся в бетонную стену. Есть идеи? Спасибо.