iT邦幫忙

0

SQLalchemy orm

  • 分享至 

  • xImage

以下是我的 Model 模型

class LocationModel(DataBase):
    id: GUID = Column(GUID, primary_key=True, default=uuid.uuid4)
    name: str = Column(String(length=32), unique=True, nullable=False)
    
    member_come = relationship(
        'MemberComeModel',
        back_populates='location',
        uselist=True,
        cascade='all, delete',
        passive_deletes=True
    )
    
class MemberModel(DataBase):
    id: GUID = Column(GUID, primary_key=True, default=uuid.uuid4)
    name: str = Column(String(length=32), nullable=False)
    image: str = Column(String(length=64), nullable=True)
    
class MemberComeModel(DataBase):
    id: GUID = Column(GUID, primary_key=True, default=uuid.uuid4)
    member_id = Column(GUID, ForeignKey('Member.id', ondelete='CASCADE'))
    location_id = Column(GUID, ForeignKey('Location.id', ondelete='CASCADE'))
    
    member = relationship('MemberModel', back_populates='member_come', uselist=False)
    location = relationship('LocationModel', back_populates='member_come', uselist=False)

result 是我將資料拉出來後用 for 迴圈整理的程式碼後,我理想的結果。

async def get_data():
    query_set = await db.execute(select(MemberComeModel)).scalars().unique().all()
    result = defaultdict(list)
    for item in query_set:  # type: MemberComeModel
        result[item.location.id].append({
            'name': item.member.name,
            'image': item.member.image
        })
    print(result)

key 是 location id
value 是一個陣列
陣列裡面是 member name image 的值

{
    UUID('bca3b662-a294-4ab5-b48c-2c0e26f0f132'): [{'name': '名字1', 'image': '/static/member/25d1d594-0c55-4c64-b39d-31efeb4729ff/image.png'}, {'name': '名字2', 'image': '/static/member/e50818f1-67e9-4edf-ab0e-9573ecae955e/image.jpg'}], 
    UUID('a87483a5-d6e1-4221-ae0c-317f7f5c2333'): [{'name': '名字3', 'image': '/static/member/a7a496fa-b8e5-44e0-a769-641289cd469b/image.jpg'}]
}

我覺得 orm 可以直接將我想要的理想結果拿出來,而不是我在特別寫用 for 迴圈整理資料。

我覺得應該要用 group_by 還是 annotate 這類的解決問題。

但礙於我不熟 SQLalchemy 也不熟 SQL,只會用基本的用法。

想請教大家如何寫。

froce iT邦大師 1 級 ‧ 2022-08-30 09:40:47 檢舉
關鍵字:序列化
做完queryset之後利用SQLalchemy本身的序列化函式就能達成
sma739146 iT邦新手 5 級 ‧ 2022-08-30 20:26:45 檢舉
queryset 那行或許就可以拿到我要的資料結構了,並不需要再做其他事情,但我也不知道能不能。
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

2 個回答

0
I code so I am
iT邦高手 1 級 ‧ 2022-08-30 09:27:00

可使用下列查詢,輸出 Pandas DataFrame。

from sqlalchemy import create_engine
from sqlalchemy.orm import Session
import sqlalchemy as db
import pandas as pd
from model import *

engine = db.create_engine('sqlite:///data.db', echo=True) 
connection = engine.connect()
Base.metadata.create_all(engine)

query = db.select([MemberComeModel.id, MemberModel.name,
    LocationModel.name]).join(MemberModel).join(LocationModel)
ResultSet = connection.execute(query).fetchall()

# convert to Data Frame
df = pd.DataFrame(ResultSet)
df.columns = ResultSet[0].keys()
print(df)
sma739146 iT邦新手 5 級 ‧ 2022-08-30 20:11:05 檢舉

這個拿出來的結果是
[(UUID('be5502cf-5023-4cab-b936-729acdbfa849'), 'i', 'test'), (UUID('c89c1a16-a8cd-4e56-83f1-28ef92980097'), 'U', 'test'), (UUID('2c2c1cfd-a08e-49b9-9eb7-e107ae31c678'), 'U', 'test2')]
並不是我要的。

0
海綿寶寶
iT邦大神 1 級 ‧ 2022-08-30 09:35:12

你已經寫好了

我覺得 orm 可以直接將我想要的結果拿出來,而不是我在用 for 迴圈去整理。

for item in query_set:  # type: MemberComeModel
        result[item.location.id].append({
            'name': item.member.name,
            'image': item.member.image
        })

這段裡的 「query_set」 就已經是 orm 的結果了
而「拿出來」的方式就是你寫的
item.location.id
item.member.name
item.member.image

看更多先前的回應...收起先前的回應...
sma739146 iT邦新手 5 級 ‧ 2022-08-30 09:39:03 檢舉

我的意思是我不想用 for 迴圈在整理資料,應該用 group_by 還是 annotate 就解決,query_set = orm 語法 = result。

我不明白你的「整理資料」指的是什麼
因為 query_set 的資料內容
和你「用 for 迴圈在整理資料」存進去的 result
一模一樣

sma739146 iT邦新手 5 級 ‧ 2022-08-30 09:52:16 檢舉

就是我 quset_set 那行寫完就是我要的result了,不用寫 for。

quset_set 那行寫完就是我要的result

不用寫 for 就已經是了

query_set 和 result 的差別只有
object 和 array 的差別
orm 就是 object
如果你就是需要/喜歡 array 的型式
就得把「orm 轉成 array 的型式」
或者「不要用 orm,直接從資料庫取得 array 型式的結果」

sma739146 iT邦新手 5 級 ‧ 2022-08-30 19:54:39 檢舉

query_set 拿出來是 MemberCome Model 還不是我要的資料結構。

sma739146 iT邦新手 5 級 ‧ 2022-08-30 19:55:20 檢舉

你是不是沒看到我 key 是 location.id? 這個是我從 MemberCome 拿出來的。

sma739146 iT邦新手 5 級 ‧ 2022-08-30 19:55:50 檢舉

我貼的 Model 是我簡化的資料結構,我還有其他欄位,我並不需要其他欄位的資料。

sma739146 iT邦新手 5 級 ‧ 2022-08-30 19:57:24 檢舉

這個 query_set 拿出來是這樣
[<database.models.member.MemberComeModel object at 0x000001D427DDCBB0>, <database.models.member.MemberComeModel object at 0x000001D427DE5A00>, <database.models.member.MemberComeModel object at 0x000001D427DE5B80>]

sma739146 iT邦新手 5 級 ‧ 2022-08-30 19:58:09 檢舉

再退一步我把這個 query_set 轉成 dict 是這樣
[{'id': UUID('be5502cf-5023-4cab-b936-729acdbfa849'), 'member_id': UUID('25d1d594-0c55-4c64-b39d-31efeb4729ff'), 'location_id': UUID('bca3b662-a294-4ab5-b48c-2c0e26f0f132')}, {'id': UUID('c89c1a16-a8cd-4e56-83f1-28ef92980097'), 'member_id': UUID('e50818f1-67e9-4edf-ab0e-9573ecae955e'), 'location_id': UUID('bca3b662-a294-4ab5-b48c-2c0e26f0f132')}, {'id': UUID('2c2c1cfd-a08e-49b9-9eb7-e107ae31c678'), 'member_id': UUID('a7a496fa-b8e5-44e0-a769-641289cd469b'), 'location_id': UUID('a87483a5-d6e1-4221-ae0c-317f7f5c2333')}]

抱歉
是我看不懂你的 query_set, result 和 MemberComeModel
期待真正高手來解答吧

sma739146 iT邦新手 5 級 ‧ 2022-08-31 00:10:02 檢舉

目前我用for就能解決了,只是我想知道sql語法是不是就能做好了,因為如果資料變很大量,sql做完給我比我用python速度還快。

我再看了一遍,終於懂了你的意思
我只找到這篇官網教學
試試看在 class MemberComeModel(DataBase) 裡加這段看看

__mapper_args__ = {
        'include_properties' :['location.id', 'member.name','member.image']
    }

我沒試過
所以不知道語法對不對

sma739146 iT邦新手 5 級 ‧ 2022-08-31 14:33:05 檢舉

謝謝您提供的教學,我也學到了,但是這個是拿出我想要的 field,也就是 MemberComeModel 想要的 field,最終拿出來會像這樣,[{'member_id': member.id, 'member_name': member.name, 'member_image': member.image}],這樣還是要整理資料。

我要發表回答

立即登入回答