New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Create Relationships with Unique Fields (UniqueViolationError) #249
Comments
I don't know of any ORM that works this way. You'll have to write your own |
That's understandable. However the docs (see here: https://sqlmodel.tiangolo.com/tutorial/relationship-attributes/define-relationships-attributes/) clearly state the results of tutorial as: Team:
Hero:
Which is what I am trying to get my data to look like. But instead, I am seeing something like this:
Hero:
I am wondering if async if the culprit. I ran into a situation where I needed to add '.options(selectinload(...))' to my statements to grab the data properly. I wonder if there's something similar that needs to be added somewhere for this use case? |
But you are not doing async, are you? I don't spot |
No, that was my mistake. I forgot to add that when I was editing the example code from the tutorial. I am using async and await on this function using SQLAlchemy with asyncio. I have added that to the example code now. Thanks for catching that. |
So You will need something like this:
|
I think that is a useful workaround, but I'm trying to not have to implement additional logic if SQLModel (and SQLAlchemy behind the scenes) can manage it for me. For some reason, my code is not creating a one-to-many relationship - it's just a bunch of one-to-one relationships between the Hero and Team table were the Team objects happen to have the same team name. I would think SQLModel would handle this, but my implementation is not functioning properly (possibly because of async and the Relationship() from SQLModel aren't playing nice?). And from the tutorial, it seems that SQLModel is meant to handle this. For example, in the original tutorial code:
You can see 3 heroes are added, but only 2 teams are created and get heroes attached to them. If it created 3 teams that would not be a "one-to-many" relationship, which is what the tutorial is meant to be demonstrating. There's no code here to check that Deadpond, Rusty Man, or Spider-Boy's teams already exist in the database or not. In my implementation, if I were to try to look up heroes belonging to team = "Preventers" like this:
I won't get Spider-Boy and Rusty Man (as the tutorial does), because I have two distinct teams that happen to share the name "Preventers". So my "preventers_team" statement (if the ".one()" wasn't added) will return N number of entries from the database, where N is the number of heroes that have been committed to the database with a team name of "Preventers", and all those teams named "Preventers" will only have a single hero each. That's less than useful. I'm looking forward to the "Advanced User Guide"! |
I'm sorry, but the tutorial makes totally sense to me. If I were you, I would (re)enable the unique constraint on |
The get_or_create idiom is not used in the tutorial, or am I missing something? Surely this would be something handled behind the scenes by SQLModel, else it is not creating a one-to-many relationship for us. Either way, it is clear I'll need to implement this with and without async to try to isolate whether that's really the issue at hand. |
The get_or_create idiom is not used in the tutorial, or am I missing something? The example
Yes, try to provide a minimal, complete example that can be run as-is. |
I'll work on that. Thanks for your assistance @byrman! |
First Check
Commit to Help
Example Code
Description
I'm following the SQLModel tutorial as I implement my own version. I have a model very similar to the above example (derived from the Hero/Team example given in the tutorial on how to implement One-To-Many relationships with SQLModel.
When I use this approach, it does write the required Team and Hero objects to my database. However, it does not check the Team table to ensure that the "team_to_assign" from the request object does not already exist. So, if I use the "create_heroes" function (in two separate commits) to create two Heroes who are on the same team, I get two entries for the same team in the Team table. This is not desirable. If the team already exists, the Hero being created should use the id that already exists for that team.
When I implement "sa_column_kwargs={"unique": True}" within the "name" Field of the Team table, I can no longer create a new Hero if they are to be connected to a Team that already exists. I get the error:
I was hoping that would somehow tell SQLModel to skip the insertion of a Team that already exists and get the appropriate Team id instead. Clearly it just stops it from happening. SQLModel doesn't appear to check that a Team already exists before inserting it into the Team table.
Am I missing something about how to handle this with SQLModel, or am I meant to employ my own logic to check the Team table prior to generating the Hero object to insert?
Thanks for your time!
Operating System
Linux
Operating System Details
No response
SQLModel Version
0.0.6
Python Version
3.10
Additional Context
Using async libraries:
SQLAlchemy = {extras = ["asyncio"], version = "^1.4.31"}
asyncpg = "^0.25.0"
The text was updated successfully, but these errors were encountered: