আমি কীভাবে আলেমবিক আপগ্রেড স্ক্রিপ্টে সন্নিবেশ এবং আপডেটগুলি সম্পাদন করব?


102

আলেম্বিক আপগ্রেড করার সময় আমার ডেটা পরিবর্তন করতে হবে।

আমার কাছে বর্তমানে প্রথম সংশোধনীতে একটি 'খেলোয়াড়' টেবিল রয়েছে:

def upgrade():
    op.create_table('player',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('name', sa.Unicode(length=200), nullable=False),
        sa.Column('position', sa.Unicode(length=200), nullable=True),
        sa.Column('team', sa.Unicode(length=100), nullable=True)
        sa.PrimaryKeyConstraint('id')
    )

আমি একটি 'দল' সারণি প্রবর্তন করতে চাই। আমি একটি দ্বিতীয় সংশোধন তৈরি করেছি:

def upgrade():
    op.create_table('teams',
        sa.Column('id', sa.Integer(), nullable=False),
        sa.Column('name', sa.String(length=80), nullable=False)
    )
    op.add_column('players', sa.Column('team_id', sa.Integer(), nullable=False))

আমি দ্বিতীয় স্থানান্তরটি নিম্নলিখিত ডেটা যুক্ত করতে চাই:

  1. জনগোষ্ঠীর দল সারণি:

    INSERT INTO teams (name) SELECT DISTINCT team FROM players;
    
  2. খেলোয়াড়.টিয়ামের উপর ভিত্তি করে প্লেয়ার্স.টিয়াম_আইডি আপডেট করুন:

    UPDATE players AS p JOIN teams AS t SET p.team_id = t.id WHERE p.team = t.name;
    

আমি কীভাবে আপগ্রেড স্ক্রিপ্টের ভিতরে সন্নিবেশ এবং আপডেটগুলি সম্পাদন করব?

উত্তর:


158

আপনি যা যা জিজ্ঞাসা করছেন তা হ'ল ডেটা মাইগ্রেশন , স্কিমা মাইগ্রেশনের বিপরীতে যা আলেম্বিক ডক্সে সর্বাধিক প্রচলিত।

এই উত্তরটি ধরে নিয়েছে যে আপনি আপনার মডেলগুলি সংজ্ঞায়িত করতে ঘোষক (ক্লাস-ম্যাপার-টেবিল বা মূলের বিপরীতে) ব্যবহার করছেন। এটি অন্যান্য ফর্মের সাথে খাপ খাইয়ে তুলনামূলকভাবে সহজ হওয়া উচিত।

নোট করুন যে আলেম্বিক কিছু প্রাথমিক তথ্য ফাংশন সরবরাহ করে: op.bulk_insert()এবং op.execute()। যদি অপারেশনগুলি মোটামুটি ন্যূনতম হয় তবে সেগুলি ব্যবহার করুন। যদি মাইগ্রেশনটির জন্য সম্পর্ক বা অন্যান্য জটিল ইন্টারঅ্যাকশন প্রয়োজন, আমি নীচে বর্ণিত হিসাবে মডেল এবং সেশনের পূর্ণ শক্তি ব্যবহার করতে পছন্দ করি।

নিম্নলিখিতটি মাইগ্রেশন স্ক্রিপ্টের একটি উদাহরণ যা কিছু ঘোষিত মডেল সেট আপ করে যা একটি সেশনে ডেটা ম্যানিপুলেট করার জন্য ব্যবহৃত হবে। মূল বিষয়গুলি হ'ল:

  1. আপনার প্রয়োজনীয় কলামগুলির সাথে আপনার প্রয়োজনীয় বুনিয়াদি মডেলগুলি সংজ্ঞায়িত করুন। আপনার প্রতিটি কলামের প্রয়োজন নেই, কেবলমাত্র প্রাথমিক কী এবং আপনি যেটি ব্যবহার করছেন সেগুলি।

  2. আপগ্রেড ফাংশনের মধ্যে, op.get_bind()বর্তমান সংযোগ পেতে ব্যবহার করুন এবং এটি দিয়ে একটি সেশন তৈরি করুন।

    • অথবা bind.execute()এসকিউএল কোয়েরিগুলি সরাসরি লিখতে এসকিউএএলএলচেমির নীচের স্তরটি ব্যবহার করুন। এটি সাধারণ মাইগ্রেশনগুলির জন্য দরকারী।
  3. আপনার অ্যাপ্লিকেশনটিতে যেমন আপনি সাধারণত মডেল এবং সেশন ব্যবহার করেন তেমন ব্যবহার করুন।

"""create teams table

Revision ID: 169ad57156f0
Revises: 29b4c2bfce6d
Create Date: 2014-06-25 09:00:06.784170
"""

revision = '169ad57156f0'
down_revision = '29b4c2bfce6d'

from alembic import op
import sqlalchemy as sa
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()


class Player(Base):
    __tablename__ = 'players'

    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String, nullable=False)
    team_name = sa.Column('team', sa.String, nullable=False)
    team_id = sa.Column(sa.Integer, sa.ForeignKey('teams.id'), nullable=False)

    team = orm.relationship('Team', backref='players')


class Team(Base):
    __tablename__ = 'teams'

    id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String, nullable=False, unique=True)


def upgrade():
    bind = op.get_bind()
    session = orm.Session(bind=bind)

    # create the teams table and the players.team_id column
    Team.__table__.create(bind)
    op.add_column('players', sa.Column('team_id', sa.ForeignKey('teams.id'), nullable=False)

    # create teams for each team name
    teams = {name: Team(name=name) for name in session.query(Player.team).distinct()}
    session.add_all(teams.values())

    # set player team based on team name
    for player in session.query(Player):
        player.team = teams[player.team_name]

    session.commit()

    # don't need team name now that team relationship is set
    op.drop_column('players', 'team')


def downgrade():
    bind = op.get_bind()
    session = orm.Session(bind=bind)

    # re-add the players.team column
    op.add_column('players', sa.Column('team', sa.String, nullable=False)

    # set players.team based on team relationship
    for player in session.query(Player):
        player.team_name = player.team.name

    session.commit()

    op.drop_column('players', 'team_id')
    op.drop_table('teams')

মাইগ্রেশন পৃথক মডেলগুলি সংজ্ঞায়িত করে কারণ আপনার কোডের মডেলগুলি ডাটাবেসের বর্তমান অবস্থার প্রতিনিধিত্ব করে , যখন মাইগ্রেশনগুলি পথের বিভিন্ন পদক্ষেপের প্রতিনিধিত্ব করে । আপনার ডাটাবেসটি সেই পথে কোনও রাজ্যেই থাকতে পারে, তাই মডেলগুলি এখনও ডাটাবেসের সাথে সিঙ্ক আপ করতে পারে না। আপনি যদি খুব যত্নবান না হন তবে সত্যিকারের মডেলগুলি সরাসরি ব্যবহারের ফলে নিখোঁজ কলাম, অবৈধ ডেটা ইত্যাদির সমস্যা দেখা দেবে এটি পরিস্কারে আপনি কী কলাম এবং মডেলগুলি ব্যবহার করবেন তা স্পষ্টভাবে জানিয়ে দেওয়া আরও পরিষ্কার।


12

আপনি নীচের উদাহরণ হিসাবে সরাসরি এসকিউএল দেখুন ( আলেম্বিক অপারেশন রেফারেন্স ) ব্যবহার করতে পারেন :

from alembic import op

# revision identifiers, used by Alembic.
revision = '1ce7873ac4ced2'
down_revision = '1cea0ac4ced2'
branch_labels = None
depends_on = None


def upgrade():
    # ### commands made by andrew ###
    op.execute('UPDATE STOCK SET IN_STOCK = -1 WHERE IN_STOCK IS NULL')
    # ### end Alembic commands ###


def downgrade():
    # ### commands auto generated by Alembic - please adjust! ###
    pass
    # ### end Alembic commands ###

যদি আমি সবসময় একটি বহিস্থিত ফাইল থেকে একটি এসকিউএল বিবৃতি পড়তে চেয়েছিলেন এবং তারপর এটা পাস op.executeমধ্যে upgrade()সেখানে দ্বারা ব্যবহার করা হবে একটি ডিফল্ট টেমপ্লেট প্রদান একটি উপায় alembic revisionকমান্ড (উত্পন্ন জন্য একটি ডিফল্ট শরীর .pyফাইল)?
কুইন্টিন

4
আমি @ কুইন্টিনকে চিনি না। এটি একটি আকর্ষণীয় ধারণা।
মার্টারলাক

7

আমি অফিসিয়াল ডকুমেন্টেশনে বিস্তারিত হিসাবে অ্যাড-হক টেবিল ব্যবহার করে এসকিউএএলএলকেমি কোর স্টেটমেন্টগুলি ব্যবহার করার পরামর্শ দিচ্ছি , কারণ এটি অজ্ঞেয়াদি এসকিউএল এবং পাইথোনিক লেখার ব্যবহারের অনুমতি দেয় এবং স্ব-অন্তর্ভুক্ত। এসকিউএলএলচেমি কোর মাইগ্রেশন স্ক্রিপ্টগুলির জন্য উভয় বিশ্বের সেরা।

ধারণাটির উদাহরণ এখানে:

from sqlalchemy.sql import table, column
from sqlalchemy import String
from alembic import op

account = table('account',
    column('name', String)
)
op.execute(
    account.update().\\
    where(account.c.name==op.inline_literal('account 1')).\\
        values({'name':op.inline_literal('account 2')})
        )

# If insert is required
from sqlalchemy.sql import insert
from sqlalchemy import orm

session = orm.Session(bind=bind)
bind = op.get_bind()

data = {
    "name": "John",
}
ret = session.execute(insert(account).values(data))
# for use in other insert calls
account_id = ret.lastrowid
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.