SQLAlchemy ForeignKey и создание элементов - PullRequest
1 голос
/ 10 ноября 2019

Я пытаюсь лучше понять SQL Alchemy, чтобы начать использовать этот ORM с Flask. У меня есть две таблицы SQL. Между двумя таблицами существует много-одно отношение. Я пытаюсь найти способ, используя SQL Alchemy, чтобы добавить запись в дочернюю таблицу, используя первичный ключ, но используя другое поле в родительской таблице.

│   .dockerignore
│   .env
│   .env-template
│   .gitignore
│   docker-compose.yml
│   Dockerfile
│   manage.py
│   README.md
│   requirements.txt
├───app
│   │   config.py
│   │   routes.py
│   │   __init__.py
│   │
│   ├───sites
│   │       controller.py
│   │       interface.py
│   │       model.py
│   │       schema.py
│   │       service.py
│   │       __init__.py
│   │
│   └───devices
│           controller.py
│           interface.py
│           model.py
│           schema.py
│           service.py
│           __init__.py
├───config
│       gunicorn.py

app --> sites --> model.py

from sqlalchemy import Integer, Column, String
from app import db  # noqa
from .interface import SiteInterface


class Site(db.Model):  # type: ignore
    """Site"""

    __tablename__ = "sites"

    site_db_id = Column(Integer(), primary_key=True, autoincrement=True, nullable=False)
    dc_site_id = Column(Integer(), unique=True)
    dc_name = Column(String(100))

app --> sites --> interface.py

from mypy_extensions import TypedDict


class SiteInterface(TypedDict, total=False):
    site_id: int
    dc_site_id: int
    dc_name: str

app --> sites --> schema.py

from marshmallow import fields, Schema


class SiteSchema(Schema):
    """Site schema"""

    siteId = fields.Number(attribute="site_db_id")
    dcsiteId = fields.Number(attribute="dc_site_id")
    dcname = fields.String(attribute="dc_name")

app --> devices --> model.py

from sqlalchemy import Integer, Column, String, ForeignKey
from sqlalchemy.orm import relationship
from app import db  # noqa
from .interface import DeviceInterface

class Device(db.Model):  # type: ignore
    """Device"""

    __tablename__ = "devices"

    device_id = Column(Integer(), primary_key=True, autoincrement=True, nullable=False)
    hostname = Column(String(50), nullable=False)
    ip = Column(String(15), unique=True)
    site_db_id = Column(Integer, ForeignKey('sites.site_db_id'))
    sites = relationship("Site")

app --> devices --> interface.py

from mypy_extensions import TypedDict


class DeviceInterface(TypedDict, total=False):
    deviceId: int
    hostname: str
    ip: str
    sitedbId: int

app --> devices --> schema.py

from marshmallow import fields, Schema


class DeviceSchema(Schema):
    """Device schema"""

    deviceId = fields.Number(attribute="device_id")
    hostname = fields.String(attribute="hostname")
    ip = fields.String(attribute="ip")
    sitedbId = fields.Number(attribute="site_db_id")

Мне нужна помощь, чтобы найти способ добавить новое устройство и указать site_db_id, используя dc_site_id

Примерно так.

    @staticmethod
    def create(new_attrs: DeviceInterface) -> Device:
        new_device = Device(
            hostname=new_attrs["hostname"], ip=new_attrs["ip"],
            site_db_id=new_attrs["????"] *** select site_db_id FROM sites where dc_site_id=site_db_id ****
        )

        db.session.add(new_device)
        db.session.commit()

        return new_device

Заранее спасибо за помощь !!!

1 Ответ

0 голосов
/ 11 ноября 2019

Если я понимаю ваше требование, вы можете использовать двухэтапный подход: сначала выберите сайт с помощью dc_site_id, затем создайте новое устройство с найденным сайтом. Например, код может выглядеть следующим образом:

dc_site_id = new_attrs["dc_site_id "]
sitefound = Site.query.filter_by(dc_site_id = dc_site_id ).first_or_404()
new_device = Device(...,...., relatedsite = sitefound)

, где relatedsite - это обратная ссылка, которую вы добавляете в класс Site для ваших отношений.

devices= db.relationship('Device', backref='relatedsite', lazy=True)

Это было такподход для отношений один ко многим, которые я первоначально нашел в флеш-sqlalchemy manual :

class Person(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  name = db.Column(db.String(50), nullable=False)
  addresses = db.relationship('Address', backref='person', lazy=True)

class Address(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  email = db.Column(db.String(120), nullable=False)
  person_id = db.Column(db.Integer, db.ForeignKey('person.id'), 
     nullable=False)
...