วิธีลดความซับซ้อนในการโยกย้ายใน Django 1.7


92

มีคำถามที่คล้ายกันสำหรับ South อยู่แล้ว แต่ฉันได้เริ่มโครงการกับ Django 1.7 แล้วและฉันไม่ได้ใช้ South

ในระหว่างการพัฒนามีการสร้างการย้ายข้อมูลจำนวนมากขึ้นอย่างไรก็ตามซอฟต์แวร์ยังไม่ได้รับการคัดลอกและไม่มีฐานข้อมูลที่ต้องย้าย ดังนั้นฉันจึงต้องการรีเซ็ตการย้ายข้อมูลราวกับว่าโมเดลปัจจุบันของฉันเป็นโมเดลดั้งเดิมและสร้างฐานข้อมูลทั้งหมดขึ้นมาใหม่

วิธีที่แนะนำคืออะไร?

แก้ไข: ตั้งแต่ Django 1.8 มีคำสั่งใหม่ชื่อsquashmigrationsซึ่งช่วยแก้ปัญหาที่อธิบายไว้ที่นี่ได้มากหรือน้อย


การรีเซ็ตการย้ายข้อมูลหมายความว่าอย่างไร เลิกทำไหม
Ciro Santilli 郝海东冠状病六四事件法轮功

คำตอบ:


137

ฉันได้รับสิ่งนี้ ฉันเพิ่งค้นพบสิ่งนี้และมันดี

  • ขั้นแรกในการล้างตารางการย้ายข้อมูล:

    ./manage.py migrate --fake <app-name> zero
    
  • ลบapp-name/migrations/โฟลเดอร์หรือเนื้อหา

  • ทำการย้ายข้อมูล:

    ./manage.py makemigrations <app-name>
    
  • สุดท้ายจัดการการย้ายข้อมูลของคุณให้เรียบร้อยโดยไม่ต้องทำการเปลี่ยนแปลงฐานข้อมูลอื่น

    ./manage.py migrate --fake <app-name>
    

5
นี่คือคำตอบที่ดี การลบการย้ายข้อมูลไม่ได้เป็นการยกเลิกความเสียหายที่เกิดจากการย้ายข้อมูลที่ผิดพลาด วิธีนี้จะทำความสะอาดกระดานชนวนและช่วยให้คุณเริ่มต้นใหม่ได้
rogueleaderr

15
หากคุณอธิบายรายละเอียดเล็กน้อยนี่ควรเป็นคำตอบที่ยอมรับได้
tani-rokk

8
คำตอบหนึ่งบรรทัดที่ยอดเยี่ยมฉันไม่รู้ว่ามันทำอะไร
bischoffingston

13
zeroบรรทัดนี้ก็กลับโยกย้ายหนึ่งโดยหนึ่งจนกว่า สำหรับระบบ Django โยกย้าย<app-name> อยู่ในขณะนี้แอปใหม่และจะเริ่มต้นจาก makemigrations <app-name> ป้องกันไม่ให้ตารางถูกแก้ไขจริง ๆ การย้ายข้อมูลควรถูกทำเครื่องหมายว่ากลับรายการเท่านั้นและไม่ได้ใช้กับสคีมาจริง (เพิ่มคำอธิบายเล็กน้อยเพื่อความสมบูรณ์ @ tani-rokk, @Fabrizio)0001--fake
Mir Nazim

17
manage.py migrate --fake <app-name> zeroเพื่อล้างตารางการย้ายข้อมูลจากนั้นลบ <app-name> / migrations / โฟลเดอร์หรือเนื้อหา แล้วและในที่สุดก็ทำmanage.py makemigrations <app-name> manage.py migrate --fake <app-name>วิธีนี้จะทำให้การย้ายข้อมูลของคุณเป็นระเบียบเรียบร้อยโดยไม่ต้องเปลี่ยนแปลงฐานข้อมูลอื่น ๆ
doeke

36

ในการย้ายข้อมูลเวอร์ชัน Django 1.7 ฟังก์ชันการรีเซ็ตที่เคยอยู่ในภาคใต้ถูกยกเลิกเนื่องจากฟังก์ชันใหม่สำหรับการย้ายข้อมูลของคุณ นี่ควรจะเป็นวิธีที่ดีในการตรวจสอบจำนวนการย้ายข้อมูล

https://docs.djangoproject.com/en/dev/topics/migrations/#squashing-migrations

หากคุณยังต้องการเริ่มต้นใหม่จริงๆฉันคิดว่าคุณยังคงทำได้โดยการล้างตารางการย้ายข้อมูลและลบการย้ายข้อมูลหลังจากนั้นคุณจะเรียกใช้makemigrationsอีกครั้ง


2
ฉันจะ "ลบการย้ายข้อมูล" ได้อย่างไรนอกเหนือจากการล้างตารางการย้ายข้อมูล ฉันจะลบทั้งโฟลเดอร์หรือแค่ไฟล์ 00X _ *. py?
Kit Fisto

ด้วย South คุณสามารถลบโฟลเดอร์การย้ายข้อมูลซึ่งจะสร้างขึ้นใหม่เมื่อคุณเรียกใช้ makemigrations อีกครั้ง ฉันคิดว่ามันใช้งานได้เหมือนกันสำหรับ Django 1.7
2557

4
เพียงแค่ทราบ ใน Django 1.7 หากคุณไม่ระมัดระวังให้ลบโฟลเดอร์การย้ายข้อมูลอาจทำให้เกิดข้อยกเว้นได้หากโมเดลของคุณเป็นลูกของคนอื่นraise KeyError("Migration %s dependencies reference nonexistent parent node %r" % (migration, parent))
Algorithmatic

โดยเฉพาะ./manage.py squashmigrations myapp 0004จะสควอชโยกย้ายทั้งหมดก่อนที่จะย้ายถิ่นในใบสมัครของคุณ0004 myappการดำเนินการนี้จะสร้างการย้ายข้อมูลแบบบีบอัดเพียงครั้งเดียว
Bryce Guinta

22

ฉันเพิ่งมีปัญหาเดียวกัน นี่คือวิธีแก้ปัญหาของฉัน

#!/bin/sh
echo "Starting ..."

echo ">> Deleting old migrations"
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc"  -delete


# Optional
echo ">> Deleting database"
find . -name "db.sqlite3" -delete

echo ">> Running manage.py makemigrations"
python manage.py makemigrations

echo ">> Running manage.py migrate"
python manage.py migrate

echo ">> Done"

findสั่ง: http://unixhelp.ed.ac.uk/CGI/man-cgi?find


13
สิ่งนี้จะลบข้อมูลไม่ใช่แค่การโยกย้าย
เตา

2
คุณควรลบไฟล์. pyc ด้วย
shalbafzadeh

7

สมมติว่านี่เป็นโครงสร้างโครงการของคุณ

project_root/
    app1/
        migrations/
    app2/
        migrations/
    ...
    manage.py
    remove_migrations.py

คุณสามารถเรียกใช้สคริปต์ remove_migrations.py จากตำแหน่งที่ระบุไว้ด้านบนเพื่อลบไฟล์การย้ายข้อมูลทั้งหมด

#remove_migrations.py
"""
Run this file from a Django =1.7 project root. 
Removes all migration files from all apps in a project.
""" 
from unipath import Path

this_file = Path(__file__).absolute()
current_dir = this_file.parent
dir_list = current_dir.listdir()

for paths in dir_list:
    migration_folder = paths.child('migrations')
    if migration_folder.exists():
        list_files = migration_folder.listdir()
        for files in list_files:
            split = files.components()
            if split[-1] != Path('__init__.py'):
                files.remove()

การลบด้วยตนเองอาจทำให้เหนื่อยหากคุณมีโครงการที่ซับซ้อน สิ่งนี้ช่วยฉันได้มาก การลบไฟล์การย้ายข้อมูลนั้นปลอดภัย ฉันทำสิ่งนี้เป็นครั้งที่สิบสองแล้วโดยไม่ประสบปัญหาใด ๆ ...

อย่างไรก็ตามเมื่อฉันลบโฟลเดอร์การย้ายข้อมูลmakemigrationsหรือmigrateไม่ได้สร้างโฟลเดอร์กลับมาให้ฉัน สคริปต์จะตรวจสอบให้แน่ใจว่าโฟลเดอร์การย้ายข้อมูล__init__.pyยังคงอยู่โดยจะลบเฉพาะไฟล์การย้ายข้อมูลเท่านั้น


คุณสามารถลบโฟลเดอร์การย้ายข้อมูลและสร้างใหม่โดยใช้init .py ที่ว่างเปล่า(เช่นtouch migrations/__init__.py)
เตา

6
  1. ลบไฟล์: delete_migrations.py (ในรูทของ prj):
import os

for root, dirs, files in os.walk(".", topdown=False):
  for name in files:
      if '/migrations' in root and name != '__init__.py':
          os.remove(os.path.join(root, name))
  1. DELETE FROM django_migrations Where app in ('app1', 'app2');

  2. ./manage.py makemigrations

  3. ./manage.py โยกย้าย - ปลอม

หรือคุณสามารถเขียนการย้ายข้อมูลจากทั้งหมดนี้


ฉันต้องระบุชื่อแอปเพื่อ./manage.py makemigrationsให้ทำงานได้ดังนี้./manage.py makemigrations orders alerts
Salami

4

ฉันลองใช้คำสั่งต่างๆและคำตอบบางคำก็ช่วยฉันได้ เฉพาะลำดับนี้ในกรณีของฉันเท่านั้นที่แก้ไขการอ้างอิงที่ไม่สมบูรณ์ในการย้ายข้อมูลใน MYAPP และล้างการย้ายข้อมูลที่ผ่านมาทั้งหมดโดยเริ่มจากศูนย์

ก่อนที่จะดำเนินการนี้ให้แน่ใจว่าฐานข้อมูลได้รับการซิงค์แล้ว (เช่นอย่าเพิ่มฟิลด์ Model ใหม่ที่นี่หรือเปลี่ยนตัวเลือก Meta)

rm -Rf MYAPP/migrations/*
python manage.py makemigrations --empty MYAPP
python manage.py makemigrations
python manage.py migrate --fake MYAPP 0002

โดยที่ 0002 คือหมายเลขการโอนย้ายที่ส่งคืนโดยคำสั่ง makemigrations สุดท้าย

ตอนนี้คุณสามารถเรียกใช้ makemigrations / migrate ได้ตามปกติเนื่องจากการย้ายข้อมูล 0002 ถูกเก็บไว้ แต่ไม่ปรากฏในฐานข้อมูลที่ซิงค์แล้ว


จากวิธีแก้ปัญหาทั้งหมดที่กล่าวมาข้างต้นมีเพียงวิธีนี้เท่านั้นที่ใช้ได้กับฉันโดยไม่มีข้อผิดพลาดและไม่ต้องลบฐานข้อมูล
Vivek Jha

3

หากคุณไม่สนใจเกี่ยวกับการย้ายข้อมูลก่อนหน้านี้เพียงแค่ลบการย้ายข้อมูลทั้งหมดในไดเร็กทอรี / ไดเร็กทอรี คุณจะเริ่มลำดับการย้ายข้อมูลตั้งแต่เริ่มต้นโดยใช้โมเดลปัจจุบันของคุณเป็นข้อมูลอ้างอิงราวกับว่าคุณได้เขียนโมเดลทั้งหมดแล้ว

ถ้าคุณไม่ไว้ใจฉันมากพอที่จะลบออกก็พยายามย้ายออกไปแทน


อะไรคือความสำคัญของการรักษาการโยกย้ายแบบเก่า? คำถามของฉันเกิดขึ้นเมื่อมีคนพยายามอัพเกรดจาก django 1.6 เป็น 1.8
Jay Modi

การย้ายข้อมูลเป็นเพียงการบันทึกการเปลี่ยนแปลงที่คุณทำกับฐานข้อมูล ฉันได้รับคำแนะนำของ vokiman มากกว่าหนึ่งครั้งเมื่อห่วงโซ่การอพยพของฉันหยุดทำงาน
Adam Starrh

1

วิธีง่ายๆคือ

ไปที่ทุกแอพและลบไฟล์การย้ายข้อมูล

จากนั้นไปที่ตาราง django-migrtaions ในฐานข้อมูลและตัดทอน (ลบรายการทั้งหมด)

หลังจากนั้นคุณสามารถสร้างการย้ายข้อมูลได้อีกครั้ง


1
ในขณะที่ลบไฟล์การย้ายข้อมูลตรวจสอบให้แน่ใจว่าคุณไม่ได้ลบไฟล์init
sprksh

สิ่งนี้ช่วยฉันได้จริงๆ ฉันลบการย้ายข้อมูลทั้งหมดทิ้งตารางจาก sqlite DB ของฉัน แต่ยังไม่สามารถทำการย้ายข้อมูลได้ ... อย่างไรก็ตามเมื่อฉันกู้คืนไฟล์_init_ .py (doh) ฉันก็สามารถทำการย้ายข้อมูลอีกครั้งและล่องเรือได้ @sprksh = ช่วยชีวิต!
twknab

0

cd เป็น src ไดเร็กทอรี cd /path/to/src

ลบไดเร็กทอรีการย้ายข้อมูล rm -rf your_app/migrations/

โปรดทราบว่าสิ่งนี้ควรทำสำหรับแต่ละแอปแยกกัน

โยกย้าย python3.3 manage.py migrate

หากคุณต้องการเริ่มต้นใหม่อีกครั้ง python3.3 manage.py makemigrations your_app


0

หากคุณอยู่ในโหมดการพัฒนาและต้องการรีเซ็ตทุกอย่าง (ฐานข้อมูลการย้ายข้อมูล ฯลฯ ) ฉันใช้สคริปต์นี้ตามคำตอบของ Abdelhamid Ba การดำเนินการนี้จะล้างตารางของฐานข้อมูล (Postgres) ลบไฟล์การย้ายข้อมูลทั้งหมดเรียกใช้การย้ายข้อมูลอีกครั้งและโหลดการติดตั้งเริ่มต้นของฉัน:

#!/usr/bin/env bash
echo "This will wipe out the database, delete migration files, make and apply migrations and load the intial fixtures."

while true; do
    read -p "Do you wish to continue?" yn
    case $yn in
        [Yy]* ) make install; break;;
        [Nn]* ) exit;;
        * ) echo "Please answer yes or no.";;
    esac
done

echo ">> Deleting old migrations"
find ../../src -path "*/migrations/*.py" -not -name "__init__.py" -delete

# Optional
echo ">> Deleting database"
psql -U db_user -d db_name -a -f ./reset-db.sql

echo ">> Running manage.py makemigrations and migrate"
./migrations.sh

echo ">> Loading initial fixtures"
./load_initial_fixtures.sh

echo ">> Done"

ไฟล์ reset-db.sql:

DO $$ DECLARE
    r RECORD;
BEGIN
    -- if the schema you operate on is not "current", you will want to
    -- replace current_schema() in query with 'schematodeletetablesfrom'
    -- *and* update the generate 'DROP...' accordingly.
    FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = current_schema()) LOOP
        EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';
    END LOOP;
END $$;

ไฟล์ migration.sh:

#!/usr/bin/env bash
cd ../../src
./manage.py makemigrations
./manage.py migrate

ไฟล์ load_initial_fixtures.sh:

#!/usr/bin/env bash
cd ../../src
./manage.py loaddata ~/path-to-fixture/fixture.json

อย่าลืมเปลี่ยนเส้นทางให้สอดคล้องกับแอปของคุณ โดยส่วนตัวฉันมีสคริปต์เหล่านี้ในโฟลเดอร์ชื่อ project_root / script / local และแหล่งที่มาของ django อยู่ใน project_root / src


0

หลังจากลบแต่ละโฟลเดอร์ "การย้ายข้อมูล" ในแอปของฉัน (ด้วยตนเอง) ฉันรัน:

./manage.py dbshell
delete from django_migrations;

จากนั้นฉันก็คิดว่าฉันสามารถทำได้./manage.py makemigrationsเพื่อสร้างมันขึ้นมาใหม่ทั้งหมด อย่างไรก็ตามไม่พบการเปลี่ยนแปลง จากนั้นฉันลองระบุทีละแอป: ./manage.py makemigrations foo, ./manage.py makemigrations bar. อย่างไรก็ตามสิ่งนี้ส่งผลให้เกิดการอ้างอิงแบบวงกลมที่ไม่สามารถแก้ไขได้

สุดท้ายฉันรันคำสั่ง makemigrations เดียวที่ระบุแอพทั้งหมดของฉัน (ไม่เรียงลำดับเฉพาะ):

./manage.py makemigrations foo bar bike orange banana etc

คราวนี้มันใช้งานได้ - การอ้างอิงแบบวงกลมได้รับการแก้ไขโดยอัตโนมัติ (สร้างไฟล์การย้ายข้อมูลเพิ่มเติมหากจำเป็น)

จากนั้นฉันก็สามารถทำงาน./manage.py migrate --fakeและกลับมาทำธุรกิจได้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.