How to do a one to one (1..1) relationship in SQLAlchemy and execute a query?

58 Views Asked by At

I am trying to create a Model using SQLAlchemy which has one specific column that is generated through a relationship of type 1..1. Which means "One Request has only one Description".

The way it is stored on SQL, is like this:

  • On REQUEST (Table TQB), there is one field called TQB_CODMSS with the Description code.
  • On DESCRIPTIONS (Table SYP), there is two fields, one called YP_CAMPO which takes the value TQB_CODMSS, and another one called YP_CHAVE, which takes the value TQB_CODMSS has on REQUEST table.

So, a SELECT for this would be something like:

-- List descriptions fro all REQUESTs.
-- Description is saved on SYP010 Table and the 1..1 relationship is done using TQB_CODMSS (Table Requests), YP_CHAVE and YP_CAMPO (Table Descriptions).

SELECT 
    -- Select the TEXT Column only.
    SYP.YP_TEXTO AS request_description
FROM
    TQB010 REQUESTS

-- On SYP: YP_CHAVE has the column from REQUESTs TQB_CODMSS, and YP_CAMPO has the code stored on TQB_CODMSS on REQUESTs Table.
LEFT JOIN SYP010 SYP ON SOLICITACOES_DE_SERVICO.TQB_CODMSS = SYP.YP_CHAVE;

-- TQB010.TQB_CODMSS --> Column Value goes to SYP010.YP_CHAVE
-- SYP010.YP_CAMPO = TQB010.TQB_CODMSS

It works, lists ALL descriptions for my requests.

What I want to do is to do this using SQLAlchemy, using it's One-to-One Syntax. Here is the things I am taking into consideration:

  • There is no Description Column on REQUESTs Table, so doing request_description: Mapped[str] = mapped_column("TQB_DESCSS", db_sql.String) will not work.
  • The relationship is made using only TQB_CODMSS field (Which is the code used as Primary Key for YP_CHAVE on SYP Table.)

I tried doing like this:

  1. First I Mapped the Models
from dataclasses import dataclass
from sqlalchemy.orm import relationship, Mapped, mapped_column
from sqlalchemy import ForeignKey
from db_context import db_sql


@dataclass
class Description(db_sql.Model):
    """
    Represents a description of a request for service.
    The relationship is done using the TQB_CODMSS field, which is the primary key of the SYP010 table (YP_CAMPO).
    """
    __tablename__ = 'SYP010'

    description_id: Mapped[str] = mapped_column(ForeignKey("YP_CHAVE"), db_sql.String, primary_key=True)
    description_relationship_field: Mapped[str] = mapped_column("YP_CAMPO", db_sql.String, nullable=False)
    description_text: Mapped[str] = mapped_column("YP_DESC", db_sql.String, nullable=False)


@dataclass
class RequestDescription(db_sql.Model):
    """
    Represents a request for service comment.
    It has a code value which serves as a primary key for the SYP010 table (YP_CHAVE).
    """
    __tablename__ = 'TQB010'

    request_description: Mapped[str] = relationship("Description", back_populates="RequestDescription")
    request_description_id: Mapped[str] = mapped_column("TQB_CODMSS", db_sql.String, primary_key=True)
  1. Secondly I tried executing and creating the query which would bring all descriptions of Requests:
    @staticmethod
    def get_descriptions():
        """
        List all descriptions of requests for service.
        It's the equivalent for the following SQL:

        -- Trago só a descrição da Solicitação de Serviço.
        -- A descrição da S.S. é salva na tabela SYP010 e vinculada pelo campo da S.S. TQB_CODMSS e o campo da SYP010 YP_CHAVE.

        SELECT
            SYP.YP_TEXTO AS solicitacao_descricao
        FROM
            TQB010 SOLICITACOES_DE_SERVICO

        -- Na SYP: YP_CHAVE é o código do TQB_CODMSS, e a YP_CAMPO contém o valor da COLUNA que ele vai puxar o código (TQB_CODMSS).
        LEFT JOIN SYP010 SYP ON SOLICITACOES_DE_SERVICO.TQB_CODMSS = SYP.YP_CHAVE;

        -- Resumindo:
        -- TQB010.TQB_CODMSS = SYP010.YP_CHAVE
        -- SYP010.YP_CAMPO = TQB010.TQB_CODMSS

        """

        # 1. Create the Query only.
        descriptions_list = RequestDescription.query(Solicitacao.solicitacao_descricao)

        # 2. Executes the Query.
        descriptions_list = descriptions_list.all()

        print("Descriptions: ", descriptions_list)

But as soon I start the server, I am getting some errors from SQL Alchemy, on the Models mapping:

description_id: Mapped[str] = mapped_column(ForeignKey("YP_CHAVE"), db_sql.String, primary_key=True)
sqlalchemy.exc.ArgumentError: 'SchemaItem' object, such as a 'Column' or a 'Constraint' expected, got <class 'sqlalchemy.sql.sqltypes.String'>

Can someone help me? Please.

My Project uses Marshmallow SQLAlchemy, SQLAlchemy and Flask SQLAlchemy. The objective is to map the descriptions and then make a route in Flask available for querying data using the model objects.

0

There are 0 best solutions below