Cách dễ nhất để đổi tên một mô hình bằng Django / South?


141

Tôi đã tìm kiếm câu trả lời cho vấn đề này trên trang web của Nam, Google và SO, nhưng không thể tìm thấy một cách đơn giản để làm điều này.

Tôi muốn đổi tên một mô hình Django bằng cách sử dụng Nam. Nói rằng bạn có những điều sau đây:

class Foo(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Foo)

và bạn muốn chuyển đổi Foo thành Bar, cụ thể là

class Bar(models.Model):
    name = models.CharField()

class FooTwo(models.Model):
    name = models.CharField()
    foo = models.ForeignKey(Bar)

Để đơn giản, tôi chỉ cố gắng thay đổi tên từ Foothành Bar, nhưng bỏ qua foothành viên trong FooTwobây giờ.

Cách dễ nhất để làm điều này bằng cách sử dụng Nam là gì?

  1. Tôi có thể có thể thực hiện di chuyển dữ liệu, nhưng điều đó có vẻ khá liên quan.
  2. Viết một di chuyển tùy chỉnh, ví dụ db.rename_table('city_citystate', 'geo_citystate'), nhưng tôi không chắc cách sửa khóa ngoại trong trường hợp này.
  3. Một cách dễ dàng hơn mà bạn biết?

5
Xem thêm stackoverflow.com/questions/3235995/ Khăn để đổi tên trường mô hình thay vì mô hình .
Ốc cơ khí

Giải pháp tối ưu hóa cho Django> = 1.8 stackoverflow.com/questions/25091130/ cấp
Lập trình viên hóa học

Câu trả lời:


130

Để trả lời câu hỏi đầu tiên của bạn, việc đổi tên mô hình / bảng đơn giản là khá đơn giản. Chạy lệnh:

./manage.py schemamigration yourapp rename_foo_to_bar --empty

(Cập nhật 2: thử --autothay vì --emptyđể tránh cảnh báo bên dưới. Cảm ơn @KFB về mẹo này.)

Nếu bạn đang sử dụng phiên bản cũ hơn của miền nam, bạn sẽ cần startmigrationthay thế schemamigration.

Sau đó chỉnh sửa thủ công tệp di chuyển để trông như thế này:

class Migration(SchemaMigration):

    def forwards(self, orm):
        db.rename_table('yourapp_foo', 'yourapp_bar')


    def backwards(self, orm):
        db.rename_table('yourapp_bar','yourapp_foo')   

Bạn có thể thực hiện việc này đơn giản hơn bằng cách sử dụng db_tabletùy chọn Meta trong lớp mô hình của bạn. Nhưng mỗi khi bạn làm điều đó, bạn sẽ tăng trọng số kế thừa của cơ sở mã của bạn - việc có tên lớp khác với tên bảng làm cho mã của bạn khó hiểu và duy trì hơn. Tôi hoàn toàn ủng hộ việc thực hiện các phép tái cấu trúc đơn giản như thế này vì mục đích rõ ràng.

(cập nhật) Tôi vừa thử điều này trong sản xuất và nhận được một cảnh báo lạ khi tôi đi áp dụng di chuyển. Nó nói rằng:

The following content types are stale and need to be deleted:

    yourapp | foo

Any objects related to these content types by a foreign key will also
be deleted. Are you sure you want to delete these content types?
If you're unsure, answer 'no'.

Tôi trả lời "không" và mọi thứ dường như đều ổn.


3
Tôi đã có thể tránh thông báo lỗi mà Leopd bằng cách tạo di chuyển lược đồ bằng cách sử dụng --auto thay vì --empty. Sau đó tôi đã chỉnh sửa tệp di chuyển, thay đổi việc xóa / tạo các bảng thành một lệnh gọi db.rename_table (). Điều này dường như đã làm việc rất tốt.
KFB

4
Tôi đã sử dụng kỹ thuật này vào ngày 9/2/2011 mà không gặp bất kỳ lỗi nào. Có lẽ một phiên bản mới hơn của Nam đã giải quyết vấn đề với các lỗi.
Chip Tol

1
Cảm ơn đã cập nhật thông tin này! Câu trả lời của Jian dưới đây nói rằng điều quan trọng là phải giữ các cuộc gọi "send_create_signal", bạn có biết gì về điều đó không? Nếu bạn đồng ý, sẽ rất tuyệt nếu cập nhật di chuyển ví dụ của bạn.
mrooney

5
Coi chừng rằng điều này sẽ không đổi tên các chỉ mục trên bảng đó. Nếu bạn tạo một bảng mới trong tương lai có cùng tên với bảng cũ, bạn có thể gặp lỗi từ các tên chỉ mục va chạm. Chúng tôi đã sử dụng kỹ thuật này, nhưng từ giờ chúng tôi sẽ rõ ràng tạo bảng mới, di chuyển dữ liệu, sau đó xóa bảng cũ.
Jeremy Banks

3
Tên cột trong các bảng được tạo tự động, chẳng hạn như bảng M2M sang mô hình ban đầu, cũng không được di chuyển theo phương thức này.
spookylukey

66

Thực hiện các thay đổi trong models.pyvà sau đó chạy

./manage.py schemamigration --auto myapp

Khi bạn kiểm tra tệp di chuyển, bạn sẽ thấy rằng nó xóa một bảng và tạo một bảng mới

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Deleting model 'Foo'                                                                                                                      
        db.delete_table('myapp_foo')

        # Adding model 'Bar'                                                                                                                        
        db.create_table('myapp_bar', (
        ...
        ))
        db.send_create_signal('myapp', ['Bar'])

    def backwards(self, orm):
        ...

Đây không phải là những gì bạn muốn. Thay vào đó, hãy chỉnh sửa di chuyển sao cho giống như:

class Migration(SchemaMigration):

    def forwards(self, orm):
        # Renaming model from 'Foo' to 'Bar'                                                                                                                      
        db.rename_table('myapp_foo', 'myapp_bar')                                                                                                                        
        if not db.dry_run:
            orm['contenttypes.contenttype'].objects.filter(
                app_label='myapp', model='foo').update(model='bar')

    def backwards(self, orm):
        # Renaming model from 'Bar' to 'Foo'                                                                                                                      
        db.rename_table('myapp_bar', 'myapp_foo')                                                                                                                        
        if not db.dry_run:
            orm['contenttypes.contenttype'].objects.filter(app_label='myapp', model='bar').update(model='foo')

Trong trường hợp không có updatecâu lệnh, db.send_create_signalcuộc gọi sẽ tạo một cái mới ContentTypevới tên model mới. Nhưng nó tốt hơn để chỉ updatecác ContentTypebạn đã có trong trường hợp có các đối tượng cơ sở dữ liệu trỏ đến nó (ví dụ, qua GenericForeignKey).

Ngoài ra, nếu bạn đã đổi tên một số cột là khóa ngoại thành mô hình được đổi tên, đừng quên

db.rename_column(myapp_model, foo_id, bar_id)

2
Tôi gặp lỗi, KeyError: "Mô hình 'nội dung' từ ứng dụng 'nội dung' không có sẵn trong di chuyển này." Ngoài ra, tôi có một bảng django_content_type, nhưng không phải là một bảng nội dung. (Django 1.6)
Seth

2
@ Vì tôi đã giải quyết vấn đề này bằng cách cập nhật các mô hình ContentType trong một di chuyển dữ liệu riêng biệt và bằng cách thêm contenttypes.ContentTypemô hình vào các mô hình được đóng băng bằng cách sử dụng --frozencờ vào ./manage.py datamigration. Ví dụ : ./manage.py datamigration --frozen contenttypes myapp update_contenttypes. Sau đó chỉnh sửa myapp_migations / NNNN_update_contenttypes.py với mã cập nhật loại nội dung như được chỉ định ở trên.
Geoffrey Hing

@GeoffreyHing Tôi nghĩ rằng tham số này không bị đóng băng. south.readthedocs.io/en/latest/ormfreezing.html Nhưng cảm ơn bạn rất nhiều vì sự giúp đỡ của bạn, nó thực sự hữu ích.
ccsakuweb

5

Nam không thể tự làm điều đó - làm thế nào để biết nó Barđại diện cho những gì đã Footừng? Đây là loại điều tôi sẽ viết một di chuyển tùy chỉnh cho. Bạn có thể thay đổi ForeignKeymã của mình như bạn đã làm ở trên, và sau đó chỉ là trường hợp đổi tên các trường và bảng thích hợp, bạn có thể làm bất kỳ cách nào bạn muốn.

Cuối cùng, bạn có thực sự cần phải làm điều này? Tôi vẫn chưa cần đổi tên mô hình - tên mô hình chỉ là một chi tiết triển khai - đặc biệt được cung cấp verbose_nametùy chọn Meta.


7
Hoặc, đổi tên mô hình trong mã nhưng sử dụng db_tabletùy chọn Meta để giữ nguyên tên bảng cơ sở dữ liệu.
Daniel Roseman

@Daniel - Bạn có biết nếu db_tableđược sử dụng để lấy tên khóa ngoại?
Đaminh Rodger

tôi tin nó là Nếu bạn thay đổi tên mô hình và đặt db_table, mọi thứ sẽ vẫn hoạt động như mong đợi.
Davor Lucic

1
@DanielRoseman đây là giải pháp tốt nhất trong toàn bộ chủ đề!
tham gia

-1

Tôi đã làm theo giải pháp của Leopd ở trên. Nhưng, điều đó đã không thay đổi tên mô hình. Tôi đã thay đổi nó theo cách thủ công trong mã (cũng trong các mô hình liên quan trong đó mô hình này được gọi là FK). Và thực hiện một di chuyển về phía nam, nhưng với tùy chọn --fake. Điều này làm cho tên mô hình và tên bảng là giống nhau.

Chỉ cần nhận ra, trước tiên người ta có thể bắt đầu với việc thay đổi tên mô hình, sau đó chỉnh sửa tệp di chuyển trước khi áp dụng chúng. Sạch sẽ hơn nhiều.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.