2012-12-03 30 views
6

Tôi hiện có một cột có chứa đánh dấu HTML. Bên trong đánh dấu đó, có một dấu thời gian mà tôi muốn lưu trữ trong một cột mới (vì vậy tôi có thể truy vấn nó). Ý tưởng của tôi là phải làm như sau trong một sự chuyển đổi duy nhất:Sử dụng SQLAlchemy ORM bên trong một di cư Alembic: làm thế nào để tôi?

  1. Tạo mới, cột nullable cho dữ liệu
  2. Sử dụng ORM để kéo lại HTML tôi cần phải phân tích
  3. Đối với mỗi hàng
    1. phân tích cú pháp HTML để kéo ra dấu thời gian
    2. cập nhật các đối tượng ORM

Nhưng khi tôi cố gắng chạy di chuyển của tôi, nó dường như bị mắc kẹt trong một vòng lặp vô hạn. Đây là những gì tôi đã có cho đến nay:

def _extract_publication_date(html): 
    root = html5lib.parse(html, treebuilder='lxml', namespaceHTMLElements=False) 
    publication_date_string = root.xpath("//a/@data-datetime")[0] 
    return parse_date(publication_date) 


def _update_tip(tip): 
    tip.publication_date = _extract_publication_date(tip.rendered_html) 
    tip.save() 


def upgrade(): 
    op.add_column('tip', sa.Column('publication_date', sa.DateTime(timezone=True))) 
    tips = Tip.query.all() 
    map(tips, _update_tip) 


def downgrade(): 
    op.drop_column('tip', 'publication_date') 
+0

Làm thế nào để bạn biết nó bị kẹt trong một vòng lặp vô hạn? –

+1

Nếu 'Tip.query' không sử dụng cùng một phiên làm' op', thì sẽ có 2 giao dịch, với lệnh 'SELECT' đang chờ đợi lệnh' ALTER TABLE' thực hiện. Dù sao, tôi nghĩ rằng nó là sạch hơn để di chuyển phần ORM để kịch bản riêng của mình, để được chạy bằng tay sau khi 'nâng cấp alembic'. – sayap

+0

@ X-Istence Tôi không biết nó bị mắc kẹt trong một vòng lặp vô hạn. I ** DO ** biết rằng lệnh không bao giờ trả về. –

Trả lời

1

Tiếp tục từ các ý kiến, bạn có thể thử một cái gì đó như thế này:

import sqlalchemy as sa 


tip = sa.sql.table(
    'tip', 
    sa.sql.column('id', sa.Integer), 
    sa.sql.column('publication_date', sa.DateTime(timezone=True)), 
) 


def upgrade(): 
    mappings = [ 
     (x.id, _extract_publication_date(x.rendered_html)) 
     for x in Tip.query 
    ] 

    op.add_column('tip', sa.Column('publication_date', sa.DateTime(timezone=True))) 

    exp = sa.sql.case(value=tip.c.id, whens=(
     (op.inline_literal(id), op.inline_literal(publication_date)) 
     for id, publication_date in mappings.iteritems() 
    )) 

    op.execute(tip.update().values({'publication_date': exp})) 


def downgrade(): 
    op.drop_column('tip', 'publication_date') 
4

gì làm việc cho tôi là để có được một phiên bằng cách làm như sau:

connection = op.get_bind() 
Session = sa.orm.sessionmaker() 
session = Session(bind=connection) 
+0

Điều này * loại * làm việc cho tôi, mặc dù có lỗi nói rằng mô hình của tôi đã bị ràng buộc vào một phiên. – killthrush

4

Sau một chút thử nghiệm bằng cách sử dụng câu trả lời của @ velochy, tôi đã giải quyết trên mẫu như sau để sử dụng SqlAlchemy bên trong Alembic. Điều này làm việc tuyệt vời cho tôi và có thể có thể phục vụ như một giải pháp chung cho câu hỏi của OP:

from sqlalchemy.orm.session import Session 
from alembic import op 

def upgrade(): 
    # Attach a sqlalchemy Session to the env connection 
    session = Session(bind=op.get_bind()) 

    # Perform arbitrarily-complex ORM logic 
    instance1 = Model1(foo='bar') 
    instance2 = Model2(monkey='banana') 

    # Add models to Session so they're tracked 
    session.add(instance1) 
    session.add(instance2) 

def downgrade(): 
    # Attach a sqlalchemy Session to the env connection 
    session = Session(bind=op.get_bind()) 

    # Perform ORM logic in downgrade (e.g. clear tables) 
    session.query(Model2).delete() 
    session.query(Model1).delete() 

Cách tiếp cận này dường như xử lý các giao dịch đúng cách. Thường xuyên trong khi làm việc trên này, tôi sẽ tạo ra ngoại lệ DB và họ sẽ cuộn những thứ trở lại như mong đợi.

+1

Cần lưu ý rằng kỹ thuật này có thể không được thông báo nếu các mô hình của bạn thay đổi thường xuyên. Khi các mô hình thay đổi, nó có thể phá vỡ sự di chuyển cũ mà giả định các mô hình có một hình dạng nhất định. – killthrush

Các vấn đề liên quan