2013-01-19 19 views
15

Tôi có một mô hình bình-SQLAlchemy:Thêm chỉ số để mô hình SQLAlchemy sau khi tạo bảng

class MyModel(db.Model): 
__tablename__ = 'targets' 
id = db.Column(db.Integer, primary_key=True) 
url = db.Column(db.String(2048)) 

Bảng đã được tạo ra, và được sử dụng. Tôi muốn tạo chỉ mục trên thuộc tính url, vì vậy tôi chuyển chỉ mục = True thành:

url = db.Column(db.String(2048), index=True) 

Làm cách nào để chỉ mục này có hiệu lực mà không xóa và tạo lại bảng?

Trả lời

2

Xin lưu ý rằng đây là không chính xác và quá phức tạp câu trả lời

Cách đúng là sử dụng index.create như người ta nói here.


Trước hết hãy đảm bảo bạn có ảnh chụp nhanh mới nhất của cơ sở dữ liệu và có thể khôi phục cơ sở dữ liệu từ ảnh chụp nhanh này.

Đối với các dự án có kích thước trung bình và lớn (có thể bạn cần hỗ trợ nhiều phiên bản cùng một lúc và được cài đặt trên nhiều môi trường), đó là một phần của vòng đời quản lý cơ sở dữ liệu được gọi là "di chuyển cơ sở dữ liệu". Di chuyển DB bao gồm các thay đổi đối với lược đồ hiện có. SQLAlchemy không hỗ trợ di chuyển ra khỏi hộp.

Có hai SQLAlchemy tương thích các công cụ cơ sở dữ liệu di cư có sẵn:

Xem thêm thông tin và liên kết đến những công cụ này trong trang tài liệu SQLAlchemy: Altering Schemas through Migrations. Tuy nhiên, nếu bạn đang làm việc trên dự án nhỏ, tôi sẽ đề xuất để chạy ALTER TABLE DDL truy vấn từ tiện ích dòng lệnh cơ sở dữ liệu hoặc thông qua connection.execute() trong kịch bản lệnh python.

Trong ứng dụng sản xuất tôi đang làm việc ngay lúc này, chúng tôi chỉ hỗ trợ một phiên bản ứng dụng mới nhất.Đối với mỗi sự thay đổi giản đồ cơ sở dữ liệu chúng ta làm các bước sau:

  • làm một bản chụp của cơ sở dữ liệu sản xuất
  • tải ảnh chụp này trên môi trường phát triển
  • cập nhật mô-đun mô hình dữ liệu SQLAlchemy
  • chuẩn bị và chạy thay đổi truy vấn bảng và lưu truy vấn này cho sau
  • thực hiện các thay đổi khác có liên quan đến mã
  • chạy thử nghiệm trên môi trường dev
  • triển khai phiên bản mới nhất của mã để sản xuất
  • làm thay đổi bảng về sản xuất

Ngoài ra tôi đang sử dụng các thủ thuật sau đây để tạo ra tạo bảng/truy vấn chỉ số: tôi chỉ ứng dụng của tôi để thương hiệu cơ sở dữ liệu mới, cho phép ghi nhật ký truy vấn sqlalchemy và chạy metadata.create_all() - vì vậy trong nhật ký (hoặc STDOUT), tôi thấy truy vấn được tạo bởi sqlalchemy

Tùy thuộc vào hệ thống cơ sở dữ liệu bạn đang sử dụng truy vấn tạo chỉ mục. truy vấn Generic sẽ trông như thế này:

create index targets_i on targets(url); 
+0

xin lỗi, câu trả lời này là sai. ALTER TABLE không được sử dụng cho các chỉ mục. SQLAlchemy hỗ trợ "CREATE INDEX" rất trực tiếp bằng cách sử dụng 'Index.create()', cũng như với cấu trúc DDL 'CreateIndex' cho các tình huống kịch bản phức tạp hơn. Không cần phải lấy đầu ra "create_all()" hoặc bất cứ thứ gì như thế. – zzzeek

+0

Cảm ơn bạn đã chỉ ra. Tôi đồng ý - Tôi đã mô tả cách triển khai và hỗ trợ cách tiếp cận được đề cập trong câu hỏi. Và hoàn toàn quên đi 'index.create' dễ dàng và nhanh chóng. – vvladymyrov

6
+8

Câu trả lời này không đưa ra ý tưởng từ nơi để lấy đối tượng chỉ mục này từ mã trong câu hỏi ban đầu. Thu thập dữ liệu thông qua các tài liệu để tìm thấy điều này là cẩn thận, và thành thật hầu như không hữu ích vì họ không chạm vào bằng cách sử dụng api khai báo (đang được sử dụng trong câu hỏi gốc). Đối với bất kỳ ai khác bối rối như tôi, và không muốn thu thập tài liệu và mã nguồn, hãy xem câu trả lời dưới đây của tôi. – brthornbury

15

Câu trả lời đầu hiện nay không giúp tôi khi tôi hạ cánh ở đây. Sau khi đọc tài liệu (và mã nguồn) tôi thấy điều này để làm việc, hy vọng nó sẽ giúp.

Cho lớp mô hình từ câu hỏi gốc.

class MyModel(db.Model): 
    __tablename__ = 'targets' 
    id = db.Column(db.Integer, primary_key=True) 
    url = db.Column(db.String(2048)) 

Bạn có thể không chỉ cần thêm index=True vì ngay cả khi bạn gọi db.Model.metadata.create_all() chỉ số sẽ không được tạo ra trên một bảng đã được tạo ra.

Thay vào đó, bạn cần phải tạo đối tượng độc lập Index và sau đó tạo đối tượng đó. Nó sẽ giống như thế này:

class MyModel(db.Model): 
    __tablename__ = 'targets' 
    id = db.Column(db.Integer, primary_key=True) 
    url = db.Column(db.String(2048)) 

mymodel_url_index = Index('mymodel_url_idx', MyModel.url) 

if __name__ == '__main__': 
    mymodel_url_index.create(bind=engine) 

Bây giờ nơi engine xuất phát từ sẽ được lên đến cấu hình SQLAlchemy của bạn, nhưng mã này nên truyền đạt ý chính về những gì cần phải xảy ra.

-1

Tôi không chắc liệu điều này có phù hợp với các phương pháp hay nhất hay không nhưng tôi thấy Alembic sẽ thông báo cho tôi về Chỉ mục trong __table_args__ nhưng không thực sự tạo cho tôi trong khi di chuyển. Tôi đã tạo tập lệnh nhỏ này có thể tạo các chỉ mục mới được tìm thấy trong thuộc tính __table_args__. Nó sử dụng Index.create() như đã đề cập ở trên, nhưng sẽ tạo ra các chỉ mục mới nếu chúng không tồn tại.

def create_indexes(db, drop_index=False): 
    """ 
    Creates all indexes on models in project if they do not exists already. Assumes all models 
    inherit from RequiredFields class, otherwise will need to adjust search for subclasses. If the index 
    exists SQLAlchemy throws an error and we assume everything is ok. 
    :param db: The app db object, acts as the engine param for the Index.create() 
    :param drop_index: specifies whether the indexes should be dropped or created 
    :return: 
    """ 
    from application.base_models import RequiredFields 
    from sqlalchemy import Index 
    from sqlalchemy.exc import ProgrammingError 
    for klass in RequiredFields.__subclasses__(): 
     if hasattr(klass, '__table_args__'): 
      for item in getattr(klass, '__table_args__'): 
       if isinstance(item, Index): 
        try: 
         if not drop_index: 
          item.create(db.engine) 
         else: 
          item.drop(db.engine) 
        except ProgrammingError: # If index exists, creation fails on error 
         pass 
    return 

Đây là lớp mẫu hiển thị các chỉ mục.

class MyModel(RequiredFields): 

    __table_args__ = (
     db.Index(...), 
     db.Index(...), 
    ) 
-3

Sử dụng bình di chuyển. Sau khi bạn thêm các chỉ số, chỉ cần sử dụng lệnh này:

python manage.py db migrate 

Tất cả mọi thứ hoạt động tốt

0

Nếu bạn đang sử dụng nồi cất rượu, bạn có thể tạo một sự chuyển đổi để làm điều này, và tránh thêm nó vào mô hình tại tất cả:

def upgrade(): 
    # ### commands auto generated by Alembic - please adjust! ### 
    op.create_index('table1_id', 'table1', ['id'], unique=True) 
    op.create_index('table2_id', 'table2', ['id'], unique=True) 
    # ### end Alembic commands ### 

def downgrade(): 
    # ### commands auto generated by Alembic - please adjust! ### 
    op.drop_index('table1_id', table_name='table1') 
    op.drop_index('table2_id', table_name='table2') 
    # ### end Alembic commands ### 
Các vấn đề liên quan