tortoise / tortoise/tortoise-orm
[BUG] get_or_create function raises "Object does not exist"
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 5.6k
- Forks
- 516
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 9
Description
Describe the bug
While writing a discord bot for a project of a friend of mine i noticed that the get_or_create function does not seem to work as expected.
I can also fully confirm that every value has something in it.
I did a print before the model creation call which confirms that every parameter should receive a proper value.
The following error occurs: (The last one is obviously a discord error)
Traceback (most recent call last):
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/models.py", line 1075, in get_or_create
return await cls.filter(**kwargs).using_db(db).get(), False
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/queryset.py", line 1073, in _execute
raise DoesNotExist("Object does not exist")
tortoise.exceptions.DoesNotExist: Object does not exist
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/fields/base.py", line 284, in validate
v(value)
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/validators.py", line 44, in __call__
raise ValidationError("Value must not be None")
tortoise.exceptions.ValidationError: Value must not be None
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/discord/app_commands/commands.py", line 827, in _do_call
return await self._callback(self.binding, interaction, **params) # type: ignore
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/dominik/Projects/pirate-era-bot/pirate_era_bot/plugins/rule_book/rule_book.py", line 39, in designate_rule_channel
rule_message_tuple = await RuleMessage(
^^^^^^^^^^^^^^^^^^
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/models.py", line 1079, in get_or_create
return await cls.create(using_db=connection, **defaults, **kwargs), True
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/models.py", line 1154, in create
await instance.save(using_db=db, force_create=True)
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/models.py", line 962, in save
await executor.execute_insert(self)
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/backends/base/executor.py", line 224, in execute_insert
self.column_map[field_name](getattr(instance, field_name), instance)
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/fields/base.py", line 256, in to_db_value
self.validate(value)
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/tortoise/fields/base.py", line 286, in validate
raise ValidationError(f"{self.model_field_name}: {exc}")
tortoise.exceptions.ValidationError: title: Value must not be None
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/discord/app_commands/tree.py", line 1248, in _call
await command._invoke_with_namespace(interaction, namespace)
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/discord/app_commands/commands.py", line 853, in _invoke_with_namespace
return await self._do_call(interaction, transformed_values)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/dominik/.cache/pypoetry/virtualenvs/pirate-era-bot-doMltmxG-py3.12/lib/python3.12/site-packages/discord/app_commands/commands.py", line 846, in _do_call
raise CommandInvokeError(self, e) from e
discord.app_commands.errors.CommandInvokeError: Command 'create-or-edit-rule-message' raised an exception: ValidationError: title: Value must not be None
To Reproduce
Using this code it will crash with the mentioned error.
@app_commands.command(
name="create-or-edit-rule-message",
description="Create or edit rule explanation message",
)
@app_commands.describe(
channel="Channel to designate as rule channel",
title="Title of the rule message",
description="Description of the rule message",
colour="Colour of the embed. Must be in hexadecimal format. Example: #FF0000",
footer="Footer of the rule message",
)
async def designate_rule_channel(
self,
interaction: discord.Interaction,
channel: discord.TextChannel,
title: str,
description: str,
colour: Optional[str],
footer: Optional[str],
):
print(f"Title: {title}")
rule_message_tuple = await RuleMessage(
id=channel.id,
title=title,
description=description,
colour=colour,
footer=footer,
).get_or_create()
rule_message: RuleMessage = rule_message_tuple[0]
embed = discord.Embed(
title=rule_message.title,
description=rule_message.description,
colour=discord.Color.from_str(rule_message.colour),
).set_footer(text=rule_message.footer)
assert not isinstance(interaction.channel, discord.ForumChannel)
assert not isinstance(interaction.channel, discord.CategoryChannel)
assert not isinstance(interaction.channel, discord.GroupChannel)
if rule_message.message_id and isinstance(rule_message.message_id, int):
created_message = channel.get_partial_message(rule_message.message_id)
await created_message.edit(embed=embed)
await interaction.response.send_message(
f"Rule message {rule_message.title} edited with ID {rule_message.id}",
ephemeral=True,
)
else:
rule_message = await channel.send(embed=embed)
rule_message = await RuleMessage.filter(id=interaction.channel_id).update(
message_id=rule_message.id
)
await interaction.response.send_message(
f"Rule message {rule_message.title} created with ID {rule_message.id}",
ephemeral=True,
)
RuleMessage looks like this:
from tortoise import fields
from tortoise.models import Model
class RuleMessage(Model):
id = fields.BigIntField(primary_key=True)
title = fields.CharField(256) # Discord limitations
description = fields.CharField(4096) # Discord limitations
colour = fields.CharField(7, null=True) # Hexadecimal colour
footer = fields.CharField(2048, null=True) # Discord limitations
message_id = fields.BigIntField(null=True)
def __str__(self) -> str:
return f"title={self.title} description={self.description} colour={self.colour} footer={self.footer}"
Expected behavior
The model is either written to the database or retrieved from the database.
Additional context
Using .save() on it saves it to the database and works as expected.
But this is rather cumbersome.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with tortoise/models.py around get_or_create, then compare it with the supplied RuleMessage model and reproduction in the Discord command. Check how the call handles the shown lookup and creation arguments, and verify the expected behavior with a focused reproduction or existing ORM tests.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- database
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100