2010-02-08 14 views
30

मेरे पास एक Django एप्लिकेशन है जिसमें मैं एक विदेशी के लिए एक ManyToManyField में एक फ़ील्ड बदलना चाहता हूं। मैं अपने पुराने डेटा को संरक्षित करना चाहता हूं। इसके लिए अनुसरण करने के लिए सबसे सरल/सर्वोत्तम प्रक्रिया क्या है? यदि यह मायने रखता है, तो मैं अपने डेटाबेस बैक-एंड के रूप में sqlite3 का उपयोग करता हूं।कई लोगों को फ़ील्ड बदलने पर Django डेटा माइग्रेशन

यदि समस्या का मेरा सारांश स्पष्ट नहीं है, तो यहां एक उदाहरण है। मान लें कि मेरे पास दो मॉडल हैं:

class Author(models.Model): 
    author = models.CharField(max_length=100) 

class Book(models.Model): 
    author = models.ForeignKey(Author) 
    title = models.CharField(max_length=100) 

कहें कि मेरे डेटाबेस में बहुत सारे डेटा हैं। अब, मैं पुस्तक मॉडल को निम्नानुसार बदलना चाहता हूं:

class Book(models.Model): 
    author = models.ManyToManyField(Author) 
    title = models.CharField(max_length=100) 

मैं अपने सभी पूर्व डेटा "खोना" नहीं चाहता हूं।

इसे पूरा करने का सबसे अच्छा/सरल तरीका क्या है?

केन

+1

यदि यह पहले से स्पष्ट नहीं है, तो सुनिश्चित करें कि आप किसी भी माइग्रेशन की कोशिश करने से पहले अपना डेटा बैक अप लें। सौभाग्य से, एसक्लाइट की प्रतिलिपि बनाना 'cp' कमांड –

+0

के रूप में आसान है [दक्षिण] (http://south.aeracode.org/) देखें। – Zach

+0

अधिक विशेष रूप से ट्यूटोरियल के "डेटा माइग्रेशन" अनुभाग को देखें: http://south.aeracode.org/wiki/Tutorial3 वैसे भी अपने सभी माइग्रेशन के लिए दक्षिण का उपयोग करना एक अच्छी आदत है। –

उत्तर

40

मुझे पता है इस सवाल पुराना है और समय में डेटा माइग्रेशन के लिए सबसे अच्छा विकल्प दक्षिण उपयोग कर रहा था। अब Django का अपना migrate कमांड है, और प्रक्रिया थोड़ा अलग है।

मैंने इन मॉडलों को books नामक ऐप में जोड़ा है - तदनुसार समायोजित करें यदि यह आपका मामला नहीं है।

पहले, Book के क्षेत्र जोड़ सकते हैं और एक related_name कम से कम एक, या उन दोनों से (या वे संघर्ष करेंगे): अब

$ ./manage.py makemigrations 
Migrations for 'books': 
    0002_auto_20151222_1457.py: 
    - Add field authors to book 
    - Alter field author on book 

:

class Book(models.Model): 
    author = models.ForeignKey(Author, related_name='book') 
    authors = models.ManyToManyField(Author, related_name='books') 
    title = models.CharField(max_length=100) 

प्रवास उत्पन्न , डेटा के माइग्रेशन को पकड़ने के लिए एक खाली माइग्रेशन बनाएं:

./manage.py makemigrations books --empty 
    Migrations for 'books': 
0003_auto_20151222_1459.py: 

और इसमें निम्नलिखित सामग्री जोड़ें। यह समझने के लिए कि यह कैसे काम करता है, Data Migrations पर दस्तावेज़ देखें। माइग्रेशन निर्भरता को ओवरराइट न करने के लिए सावधान रहें।

# -*- coding: utf-8 -*- 
from __future__ import unicode_literals 

from django.db import models, migrations 


def make_many_authors(apps, schema_editor): 
    """ 
     Adds the Author object in Book.author to the 
     many-to-many relationship in Book.authors 
    """ 
    Book = apps.get_model('books', 'Book') 

    for book in Book.objects.all(): 
     book.authors.add(book.author) 


class Migration(migrations.Migration): 

    dependencies = [ 
     ('books', '0002_auto_20151222_1457'), 
    ] 

    operations = [ 
     migrations.RunPython(make_many_authors), 
    ] 

अब मॉडल से author क्षेत्र निकालेगा - यह इस तरह दिखना चाहिए:

class Book(models.Model): 
    authors = models.ManyToManyField(Author, related_name='books') 
    title = models.CharField(max_length=100) 

उस के लिए एक नया माइग्रेशन बनाएँ, और उन सभी को चलाने:

$ ./manage.py makemigrations 
Migrations for 'books': 
    0004_remove_book_author.py: 
    - Remove field author from book 

$ ./manage.py migrate 
Operations to perform: 
    Synchronize unmigrated apps: messages, staticfiles 
    Apply all migrations: admin, auth, sessions, books, contenttypes 
Synchronizing apps without migrations: 
    Creating tables... 
    Running deferred SQL... 
    Installing custom SQL... 
Running migrations: 
    Rendering model states... DONE 
    Applying books.0002_auto_20151222_1457... OK 
    Applying books.0003_auto_20151222_1459... OK 
    Applying books.0004_remove_book_author... OK 

और बस। पहले book.author पर उपलब्ध लेखक अब से प्राप्त क्वेरीसेट में होना चाहिए।

+1

बहुत अच्छा !!! यह दिलचस्प तरीका है ☺ –

+2

ग्रेट उत्तर, धन्यवाद! – Ward

+0

क्या आपको 'make_many_authors' में' book.save() 'नहीं करना है? –

2

शायद सबसे अच्छा और सबसे आसान काम आपको क्या करना चाहिए होगा:

एक अलग नाम के साथ कई क्षेत्र के लिए कई बनाएं कहना

authors = models.ManyToManyField(Author) 

एक छोटे से समारोह M2M मूल्यों के foreignkey मूल्यों कन्वर्ट करने के लिए लिखें:

def convert(): 
    books = Book.objects.all() 
    for book in books: 
     if book.author: 
      li = [book.author.id] 
      book.authors.append(li) 
      book.save() 

एक बार यह चलने के बाद, आप तालिका से लेखक फ़ील्ड को हटा सकते हैं और फिर माइग्रेशन चला सकते हैं।

+0

django में 1.10 मुझे एक 'एट्रिब्यूट एरर' मिलता है: 'ManyRelatedManager' ऑब्जेक्ट में कोई विशेषता नहीं है 'append'' मैंने हटा दिया .id और' book.authors = li' था और यह काम करता था। मेरा मानना ​​है कि आप 'book.authors.add (li)' भी कर सकते हैं और इससे इस मुद्दे को पूरा करना चाहिए। – hachacha

+0

आप वैसे भी मॉडल में जोड़ और सहेज सकते हैं। प्रश्न और उत्तर अधिक विशेष रूप से माइग्रेशन का ख्याल रखता है। – sprksh

संबंधित मुद्दे