SQLAlchemy 2.0与外键和关联的问题

huangapple go评论104阅读模式
英文:

SQLAlchemy 2.0 issue with foreign keys and relationships

问题

我正在使用异步的Postgres会话,并遇到了在我的两个表之间插入和提取数据的问题。

顾客表是一个独立的表,与其他表没有关系。这个表会被另一个插入操作独立更新。

对于报价表,我需要能够插入具有相应顾客ID的报价(可以是唯一的顾客号码或顾客表中的id列)。在选择数据时,我希望连接到顾客表,并像下面这样提取嵌套数据。

预期的报价表中的JSON插入

  1. {
  2. "origin": "Ney York City",
  3. "destination": "Houston",
  4. "unique_account_number": "A9457HDA"
  5. }

从报价表的选择语句中预期的JSON

  1. {
  2. "origin": "string",
  3. "destination": "string",
  4. "customer": {
  5. "unique_account_number": "ABCD1234",
  6. "customer_name": "Customer LLC"
  7. }
  8. }

我如何通过使用ORM来实现这一点?

英文:

I am using async postgres session and running into an issue with inserting and pulling data between 2 of my tables.

The customers table is a stand alone table that doesnt have a relationship with other tables. THis table gets updated independently by another insert.

For the quotes table, I need to be able to insert the quote with the corresponding customer ID (either the unique customer number or the id column in the customer table). When selecting data, I want to join to the customers table and pull the data back nested like the below.

  1. class Customers(Base):
  2. __tablename__ = "customers"
  3. __table_args__ = (UniqueConstraint("unique_account_number"),)
  4. id = mapped_column(Integer, primary_key=True)
  5. customer_name: Mapped[str]
  6. unique_account_number: Mapped[str]
  7. updated_datetime = mapped_column(
  8. DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now
  9. )
  10. created_datetime = mapped_column(DateTime, default=datetime.datetime.now)
  11. class Quotes(Base):
  12. __tablename__ = "quotes"
  13. id = mapped_column(Integer, primary_key=True)
  14. origin: Mapped[str]
  15. destination: Mapped[str]
  16. customer = relationship(Customers, foreign_key[Customers.unique_account_number])
  17. updated_datetime = mapped_column(
  18. DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now
  19. )
  20. created_datetime = mapped_column(DateTime, default=datetime.datetime.now)

Expected json insert into the quotes table

  1. {
  2. "origin": "Ney York City",
  3. "destination": "Houston",
  4. "unique_account_number": "A9457HDA"
  5. }

expected json from a select statement on the quotes table.

  1. {
  2. "origin": "string",
  3. "destination": "string",
  4. "customer": {
  5. "unique_account_number": "ABCD1234",
  6. "customer_name": "Customer LLC"
  7. }

How can I achieve this through using the ORM?

答案1

得分: 1

以下是代码的翻译部分:

  1. import sys
  2. import asyncio
  3. import datetime
  4. import json
  5. from sqlalchemy import MetaData, select, UniqueConstraint, Integer, DateTime
  6. from sqlalchemy.sql import update, func
  7. from sqlalchemy.orm import DeclarativeBase, mapped_column, Mapped, relationship, joinedload
  8. from sqlalchemy.ext.asyncio import AsyncAttrs, async_sessionmaker, AsyncSession, create_async_engine
  9. class Base(AsyncAttrs, DeclarativeBase):
  10. pass
  11. class Customers(Base):
  12. __tablename__ = "customers"
  13. __table_args__ = (UniqueConstraint("unique_account_number"),)
  14. id = mapped_column(Integer, primary_key=True)
  15. customer_name: Mapped[str]
  16. unique_account_number: Mapped[str]
  17. updated_datetime = mapped_column(
  18. DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now
  19. )
  20. created_datetime = mapped_column(DateTime, default=datetime.datetime.now)
  21. class Quotes(Base):
  22. __tablename__ = "quotes"
  23. id = mapped_column(Integer, primary_key=True)
  24. origin: Mapped[str]
  25. destination: Mapped[str]
  26. unique_account_number: Mapped[str]
  27. customer = relationship(Customers,
  28. primaryjoin="Quotes.unique_account_number==Customers.unique_account_number",
  29. uselist=False,
  30. foreign_keys=[Customers.unique_account_number])
  31. updated_datetime = mapped_column(
  32. DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now
  33. )
  34. created_datetime = mapped_column(DateTime, default=datetime.datetime.now)
  35. async def insert_objects(async_session: async_sessionmaker[AsyncSession]) -> None:
  36. async with async_session() as session:
  37. async with session.begin():
  38. session.add(Quotes(
  39. origin="New York City",
  40. destination="Houston",
  41. unique_account_number="A9457HDA"))
  42. session.add(Customers(
  43. customer_name="Customer LLC",
  44. unique_account_number="A9457HDA"))
  45. async def select_objects(async_session: async_sessionmaker[AsyncSession]) -> None:
  46. async with async_session() as session:
  47. async with session.begin():
  48. stmt = select(Quotes).options(joinedload(Quotes.customer))
  49. quotes = (await session.execute(stmt)).unique().scalars().all()
  50. return quotes
  51. def get_engine():
  52. username, password, db = sys.argv[1:4]
  53. return create_async_engine(
  54. f"postgresql+asyncpg://{username}:{password}@/{db}",
  55. echo=True,
  56. )
  57. def serialize_quote(quote):
  58. customer_dict = {attr: getattr(quote.customer, attr) for attr in ["unique_account_number", "customer_name"]}
  59. quote_dict = {attr: getattr(quote, attr) for attr in ["origin", "destination"]}
  60. quote_dict["customer"] = customer_dict
  61. return quote_dict
  62. async def async_main() -> None:
  63. engine = get_engine()
  64. async_session = async_sessionmaker(engine, expire_on_commit=False)
  65. async with engine.begin() as conn:
  66. await conn.run_sync(Base.metadata.create_all)
  67. await insert_objects(async_session)
  68. quotes = (await select_objects(async_session))
  69. print([json.dumps(serialize_quote(quote)) for quote in quotes])
  70. await engine.dispose()
  71. asyncio.run(async_main())

注意:代码中的注释和变量名称等信息未被翻译,只有代码的文本被翻译成中文。

英文:
  1. import sys
  2. import asyncio
  3. import datetime
  4. import json
  5. from sqlalchemy import MetaData, select, UniqueConstraint, Integer, DateTime
  6. from sqlalchemy.sql import update, func
  7. from sqlalchemy.orm import DeclarativeBase, mapped_column, Mapped, relationship, joinedload
  8. from sqlalchemy.ext.asyncio import AsyncAttrs, async_sessionmaker, AsyncSession, create_async_engine
  9. class Base(AsyncAttrs, DeclarativeBase):
  10. pass
  11. class Customers(Base):
  12. __tablename__ = "customers"
  13. __table_args__ = (UniqueConstraint("unique_account_number"),)
  14. id = mapped_column(Integer, primary_key=True)
  15. customer_name: Mapped[str]
  16. unique_account_number: Mapped[str]
  17. updated_datetime = mapped_column(
  18. DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now
  19. )
  20. created_datetime = mapped_column(DateTime, default=datetime.datetime.now)
  21. class Quotes(Base):
  22. __tablename__ = "quotes"
  23. id = mapped_column(Integer, primary_key=True)
  24. origin: Mapped[str]
  25. destination: Mapped[str]
  26. unique_account_number: Mapped[str]
  27. customer = relationship(Customers,
  28. primaryjoin="Quotes.unique_account_number==Customers.unique_account_number",
  29. uselist=False,
  30. foreign_keys=[Customers.unique_account_number])
  31. updated_datetime = mapped_column(
  32. DateTime, default=datetime.datetime.now, onupdate=datetime.datetime.now
  33. )
  34. created_datetime = mapped_column(DateTime, default=datetime.datetime.now)
  35. async def insert_objects(async_session: async_sessionmaker[AsyncSession]) -> None:
  36. async with async_session() as session:
  37. async with session.begin():
  38. session.add(Quotes(
  39. origin="Ney York City",
  40. destination="Houston",
  41. unique_account_number="A9457HDA"))
  42. session.add(Customers(
  43. customer_name="Customer LLC",
  44. unique_account_number="A9457HDA"))
  45. async def select_objects(async_session: async_sessionmaker[AsyncSession]) -> None:
  46. async with async_session() as session:
  47. async with session.begin():
  48. stmt = select(Quotes).options(joinedload(Quotes.customer))
  49. quotes = (await session.execute(stmt)).unique().scalars().all()
  50. return quotes
  51. def get_engine():
  52. username, password, db = sys.argv[1:4]
  53. return create_async_engine(
  54. f"postgresql+asyncpg://{username}:{password}@/{db}",
  55. echo=True,
  56. )
  57. def serialize_quote(quote):
  58. customer_dict = {attr: getattr(quote.customer, attr) for attr in ["unique_account_number", "customer_name"]}
  59. quote_dict = {attr: getattr(quote, attr) for attr in ["origin", "destination"]}
  60. quote_dict["customer"] = customer_dict
  61. return quote_dict
  62. async def async_main() -> None:
  63. engine = get_engine()
  64. async_session = async_sessionmaker(engine, expire_on_commit=False)
  65. async with engine.begin() as conn:
  66. await conn.run_sync(Base.metadata.create_all)
  67. await insert_objects(async_session)
  68. quotes = (await select_objects(async_session))
  69. print ([json.dumps(serialize_quote(quote)) for quote in quotes])
  70. await engine.dispose()
  71. asyncio.run(async_main())
  72. ``
  73. </details>

huangapple
  • 本文由 发表于 2023年6月29日 02:10:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76575716.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定