2015-10-21 23 views
10

'daki geçişler ve verilerle nasıl eklenir Belgedeki konuya dokümanlar veya çevrimiçi başvuruda bulunamıyorum.Varolan ManyToManyField seçeneğine, django

Çok fazla var olan bir ilişkim var.

class Books(models.Model): 
    name = models.CharField(max_length=100) 

class Authors(models.Model): 
    name = models.CharField(max_length=100) 
    books = models.ManyToManyField(Books) 

Bu, geçişlere ve verilere sahiptir. Şimdi pek çok ilişkiye sahip olan tabloya bir tane daha fazla alan eklemek için opsiyon yoluyla kullanmam gerekiyor. Ben göçler çalıştırdığınızda

class Authorship(models.Model): 
    book = models.ForeignKey(Books) 
    author = models.ForeignKey(Authors) 
    ordering = models.PositiveIntegerField(default=1) 

class Authors(models.Model): 
    name = models.CharField(max_length=100) 
    books = models.ManyToManyField(Books, through=Authorship) 

, django Authorship modeli için taze göç yaratır. Authorship tablosuna ordering tablosunu ekleyerek ve Authors tablosunda books sütununu değiştirerek el ile geçiş dosyası oluşturmaya çalıştım ancak bazı geçiş sorunları alıyorum.

operations = [ 
    migrations.AddField(
     model_name='authorship', 
     name='ordering', 
     field=models.PositiveIntegerField(default=1), 
    ), 
    migrations.AlterField(
     model_name='authors', 
     name='books', 
     field=models.ManyToManyField(to='app_name.Books', through='app_name.Authorship'), 
    ), 
] 

geçirmek çalışıyor

, ben böylece hatalar etkilenir ve diğer şeyler vardır bahse KeyError: ('app_name', u'authorship') verir.

Hangi şeyler eksik? Bununla çalışmak için başka bir yaklaşım var mı?

cevap

8

Veri geçişleri yapmak zorunda kalmadan seçeneği kullanmanın bir yolu yok gibi görünüyor. Dolayısıyla veri taşıma yaklaşımına başvurmak zorunda kaldım, @ pista329'un cevabından bazı fikirler aldım ve aşağıdaki adımları kullanarak sorunu çözdüm.

  • oluştur Authorship modeli

    class Authorship(models.Model): 
        book = models.ForeignKey(Books) 
        author = models.ForeignKey(Authors) 
        ordering = models.PositiveIntegerField(default=1) 
    
  • orijinal ManyToManyField ilişkisini tutun, ancak eklemek başka alanını kullanarak tanımlanan modelde yukarıdaki model aracılığıyla gibidir:

    class Authors(models.Model): 
        name = models.CharField(max_length=100) 
        books = models.ManyToManyField(Books) 
        published_books = models.ManyToManyField(Books, through=Authorship, related_name='authors_lst') # different related name is needed. 
    
  • tüm verileri kopyalamak için veri taşıma ekle eski masadan yeni Authorship tablosuna. yeni alan published_books adında olduğu gibi

Bundan sonra Authors modeline books alan kaldırılabilir.

2

Göçler bazen dağınık olabilir.

m2m alanını değiştirerek değiştirmek isterseniz, Authors.books değiştirilen alanı Authors.book olarak yeniden adlandırmanızı öneririz. makemigrations tarafından sorulduğunda, kitaptan kitaba isim değiştirdiyseniz? [yN], "N" seçeneğini belirtin. Django, books öğesini silecek ve değiştirmek yerine book alanını oluşturacaktır.

class Authorship(models.Model): 
    book = models.ForeignKey("Books") 
    author = models.ForeignKey("Authors") 
    ordering = models.PositiveIntegerField(default=1) 

class Authors(models.Model): 
    name = models.CharField(max_length=100) 
    book = models.ManyToManyField("Books", through="Authorship") 

sen zaten books kullanmak books için book değiştirebilir ve yeniden adlandırma hakkında makemigrations sorusu için y geçiş sürecini tekrarlamak istiyorsanız

.

+0

Bu, veri geçişlerini gerektirecektir, aksi halde mevcut verileri kaybederim, hayır? – chhantyal

+0

Evet, ne zamandan beri alanını kaldıracaktır. Verileri kaybetmezseniz, 'kitapları' kaldırmayın, sadece 'kitap' ekleyin. Ardından, verileri "kitaplar" dan "SQL'e" aktarın. – pista329

9

Veri geçişi olmadan "geçiş" eklemenin bir yolu vardır. Bunu this @MatthewWilkes' answer numaralı telefondan yapmayı başardım.

Yani, veri modeline çevirmek için:

  1. sadece book ve author alanlarla Authorship modeli oluşturun. Önceden sahip olduğunuz otomatik olarak oluşturulmuş M2M tablosuyla aynı adı kullanmak için tablo adını belirtin. 'Geçiş' parametresini ekleyin.

    class Authorship(models.Model): 
        book = models.ForeignKey(Books) 
        author = models.ForeignKey(Authors) 
    
        class Meta: 
         db_table = 'app_name_authors_books' 
    
    class Authors(models.Model): 
        name = models.CharField(max_length=100) 
        books = models.ManyToManyField(Books, through=Authorship) 
    
  2. Geçiş oluştur, ancak henüz çalıştırma.

  3. Oluşturulan geçişi düzenleyin ve geçiş işlemlerini migrations. SeparateDatabaseAndState işlemine state_operations alanındaki tüm işlemlerle sarın (database_operations boş bırakılmış). Böyle bir şey ile sona erecek:

    operations = [ 
        migrations.SeparateDatabaseAndState(state_operations=[ 
         migrations.CreateModel(
          name='Authorship', 
          fields=[ 
           ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), 
           ('book', models.ForeignKey(to='app_name.Books')), 
          ], 
          options={ 
           'db_table': 'app_name_authors_books', 
          }, 
         ), 
         migrations.AlterField(
          model_name='authors', 
          name='books', 
          field=models.ManyToManyField(through='app_name.Authorship', to='app_name.Books'), 
         ), 
         migrations.AddField(
          model_name='authorship', 
          name='author', 
          field=models.ForeignKey(to='app_name.Author'), 
         ), 
        ]) 
    ] 
    
  4. Artık taşımayı yürütecek ve M2M masaya ekstra ordering alan ekleyin.

Düzenleme: Görünüşe göre, DB sütunu adları modelleri tanımlanmış tablolar gibi otomatik M2M tablolar için biraz farklı bir şekilde oluşturulur. (Django 1.9.3 kullanıyorum.) Anlatılan prosedüre sonra

, ben de elle twowords_id den two_words_id ise 2 kelime adıyla (two_words=models.ForeignKey(...)) ile bir alanın sütun isimlerini değiştirmek zorunda kaldı.

+1

Evet, bu yaklaşım işe yarıyor. sütun adı için, sadece önceki sütun adıyla eşleşen db_column kullandım. – User707

İlgili konular