예시 마이그레이션 코드
from django.db import migrations, models
import django.db.models.deletion
import django_extensions.db.fields
class Migration(migrations.Migration):
"""
BEGIN;
--
-- Custom state/database change combination
--
CREATE TABLE IF NOT EXISTS finance_income_statement (
id BIGSERIAL,
transacted_at DATE NOT NULL,
created TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now(),
modified TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now(),
year INT NOT NULL,
month INT NOT NULL,
company_id BIGINT NULL,
evidence_type VARCHAR(50) NOT NULL,
account_subject_id BIGINT NULL,
amount_in_krw NUMERIC(20,2),
oversea_amount NUMERIC(20,2),
currency_code VARCHAR(10) DEFAULT 'KRW',
bank_transaction_id BIGINT NULL,
invoice_purchase_id BIGINT NULL,
invoice_sales_id BIGINT NULL,
card_purchase_id BIGINT NULL,
card_sales_id BIGINT NULL,
cash_purchase_id BIGINT NULL,
cash_sales_id BIGINT NULL,
delivery_order_id BIGINT NULL,
pg_id BIGINT NULL,
allra_pg_id BIGINT NULL,
PRIMARY KEY (year, id)
) PARTITION BY RANGE (year);
CREATE INDEX IF NOT EXISTS finance_inc_company_a61a79_idx ON finance_income_statement (company_id, account_subject_id, month);
CREATE TABLE IF NOT EXISTS finance_income_statement_2025
PARTITION OF finance_income_statement
FOR VALUES FROM (2025) TO (2026);
CREATE TABLE IF NOT EXISTS finance_income_statement_2026
PARTITION OF finance_income_statement
FOR VALUES FROM (2026) TO (2027);
CREATE TABLE IF NOT EXISTS finance_income_statement_2027
PARTITION OF finance_income_statement
FOR VALUES FROM (2027) TO (2028);
CREATE TABLE IF NOT EXISTS finance_income_statement_2028
PARTITION OF finance_income_statement
FOR VALUES FROM (2028) TO (2029);
CREATE TABLE IF NOT EXISTS finance_income_statement_2029
PARTITION OF finance_income_statement
FOR VALUES FROM (2029) TO (2030);
CREATE TABLE IF NOT EXISTS finance_income_statement_2030
PARTITION OF finance_income_statement
FOR VALUES FROM (2030) TO (2031);
COMMIT;
"""
dependencies = [
('accounting', '0014_taxinvoicepurchaseaccountsubjecthistory_and_more'),
('evidences', '0072_invoicepurchase_latest_origin_and_more'),
]
operations = [
migrations.SeparateDatabaseAndState(
database_operations=[
migrations.RunSQL(
"""
CREATE TABLE IF NOT EXISTS finance_income_statement (
id BIGSERIAL,
transacted_at DATE NOT NULL,
created TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now(),
modified TIMESTAMP WITHOUT TIME ZONE NOT NULL DEFAULT now(),
year INT NOT NULL,
month INT NOT NULL,
company_id BIGINT NULL,
evidence_type VARCHAR(50) NOT NULL,
account_subject_id BIGINT NULL,
amount_in_krw NUMERIC(20,2),
oversea_amount NUMERIC(20,2),
currency_code VARCHAR(10) DEFAULT 'KRW',
bank_transaction_id BIGINT NULL,
invoice_purchase_id BIGINT NULL,
invoice_sales_id BIGINT NULL,
card_purchase_id BIGINT NULL,
card_sales_id BIGINT NULL,
cash_purchase_id BIGINT NULL,
cash_sales_id BIGINT NULL,
delivery_order_id BIGINT NULL,
pg_id BIGINT NULL,
allra_pg_id BIGINT NULL,
PRIMARY KEY (year, id)
) PARTITION BY RANGE (year);
CREATE INDEX IF NOT EXISTS finance_inc_company_a61a79_idx ON finance_income_statement (company_id, account_subject_id, month);
""",
reverse_sql="DROP TABLE IF EXISTS finance_income_statement CASCADE;",
),
migrations.RunSQL(
"""
CREATE TABLE IF NOT EXISTS finance_income_statement_2025
PARTITION OF finance_income_statement
FOR VALUES FROM (2025) TO (2026);
"""
),
migrations.RunSQL(
"""
CREATE TABLE IF NOT EXISTS finance_income_statement_2026
PARTITION OF finance_income_statement
FOR VALUES FROM (2026) TO (2027);
"""
),
migrations.RunSQL(
"""
CREATE TABLE IF NOT EXISTS finance_income_statement_2027
PARTITION OF finance_income_statement
FOR VALUES FROM (2027) TO (2028);
"""
),
migrations.RunSQL(
"""
CREATE TABLE IF NOT EXISTS finance_income_statement_2028
PARTITION OF finance_income_statement
FOR VALUES FROM (2028) TO (2029);
"""
),
migrations.RunSQL(
"""
CREATE TABLE IF NOT EXISTS finance_income_statement_2029
PARTITION OF finance_income_statement
FOR VALUES FROM (2029) TO (2030);
"""
),
migrations.RunSQL(
"""
CREATE TABLE IF NOT EXISTS finance_income_statement_2030
PARTITION OF finance_income_statement
FOR VALUES FROM (2030) TO (2031);
"""
),
],
state_operations=[
migrations.CreateModel(
name='IncomeStatement',
fields=[
('id',
models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created',
django_extensions.db.fields.CreationDateTimeField(auto_now_add=True, verbose_name='created')),
('modified',
django_extensions.db.fields.ModificationDateTimeField(auto_now=True, verbose_name='modified')),
('year', models.IntegerField(help_text='거래 년도')),
('transacted_at', models.DateField(help_text='거래 일자')),
('month', models.IntegerField(help_text='거래 월')),
('evidence_type', models.CharField(
choices=[
('BANK_TX', '은행 입출금'),
('INVOICE_PURCHASE', '매입 세금계산서'),
('INVOICE_SALES', '매출 세금계산서'),
('CASH_PURCHASE', '매입 현금영수증'),
('CASH_SALES', '매출 현금영수증'),
('CARD_PURCHASE', '매입 신용카드'),
('CARD_SALES', '매출 신용카드'),
('DELIVERY_ORDER', '배달 주문'),
('PG_DAILY', 'PG 일일매출'),
('PG_RECONCILIATION', 'PG 결제정산'),
],
help_text='증빙 종류',
max_length=50,
)),
('amount_in_krw',
models.DecimalField(blank=True, decimal_places=2, help_text='거래 금액 (원화 기준)', max_digits=20,
null=True)),
('oversea_amount',
models.DecimalField(blank=True, decimal_places=2, help_text='해외 거래 금액', max_digits=20,
null=True)),
('currency_code', models.CharField(default='KRW', help_text='통화 코드', max_length=10)),
('account_subject', models.ForeignKey(
blank=True, null=True,
db_constraint=False,
help_text='계정과목',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='accounting.companyaccountsubject'
)),
('allra_pg', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='allra(쇼핑몰) 매출',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.allrapaymentgatewaydaily'
)),
('bank_transaction', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='계좌 입출금',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.banktransaction'
)),
('card_purchase', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='매입 신용카드',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.cardpurchase'
)),
('card_sales', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='매출 신용카드',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.cardsales'
)),
('cash_purchase', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='매입 현금영수증',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.cashpurchase'
)),
('cash_sales', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='매출 현금영수증',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.cashsales'
)),
('company', models.ForeignKey(
blank=True, null=True,
db_constraint=False,
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.company'
)),
('delivery_order', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='배달 주문',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.tilkodeliveryorder'
)),
('invoice_purchase', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='매입 세금계산서',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.invoicepurchase'
)),
('invoice_sales', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='매출 세금계산서',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.invoicesales'
)),
('pg', models.OneToOneField(
blank=True, null=True,
db_constraint=False,
help_text='PG 매출',
on_delete=django.db.models.deletion.DO_NOTHING,
related_name='income_statement',
to='evidences.pgreconciliation'
)),
],
options={
'verbose_name': '손익계산서',
'db_table': 'finance_income_statement',
'indexes': [models.Index(fields=['company', 'account_subject', 'month'], name='finance_inc_company_a61a79_idx')],
},
),
],
),
]