Миграции в Django. Примеры
19 февраля 2016 г. 4:59
Добавление внешнего ключа к существующей модели по типу один-ко-многим. Внешний ключ не должен быть пустым
Пусть у нас есть товар:
# models.py class Product(nodels.Model): product_name = models.CharField('Product Name', max_length=255) unit_price = models.DecimalField('Unit price'), decimal_places=0)
Наша задача добавить категорию для товара, причём товар не может быть без категории:
# models.py class Category(models.Model): title = models.CharField('Название', max_length=20) class Product(nodels.Model): category = models.ForeignKey(Category, verbose_name='Category', related_name='products') product_name = models.CharField('Product Name', max_length=255) unit_price = models.DecimalField('Unit price'), decimal_places=0)
Для выполнения задачи нужно сначала добавить category с null=True, blank=True к модели Product:
# models.py class Category(models.Model): title = models.CharField('Название', max_length=20) class Product(nodels.Model): category = models.ForeignKey(Category, verbose_name='Category', null=True, blank=True, related_name='products') product_name = models.CharField('Product Name', max_length=255) unit_price = models.DecimalField('Unit price'), decimal_places=0)
И выполнить команду makemigration.
Затем уберём из поля category параметры null=True, blank=True:
# models.py class Category(models.Model): title = models.CharField('Название', max_length=20) class Product(nodels.Model): category = models.ForeignKey(Category, verbose_name='Category', related_name='products') product_name = models.CharField('Product Name', max_length=255) unit_price = models.DecimalField('Unit price'), decimal_places=0)
И снова выполним makemigration, указывая, что мы сами обработаем null строки. В созданной миграции нужно добавить код, создающий категорию, которая будет записываться для наших товаров:
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations def set_category(apps, schema_editor): Category = apps.get_model('myshop', 'Category') category = Category(title='Food') category.save() Product = apps.get_model('myshop', 'Product') for product in Product.objects.all(): product.category = category product.save() class Migration(migrations.Migration): dependencies = [ ('myshop', '0003_auto_20160217_1721'), ] operations = [ migrations.RunPython(set_category), migrations.AlterField( model_name='product', name='category', field=models.ForeignKey(verbose_name='Category', to='myshop.Category'), ), ]
Добавление поля с атрибутом unique=True
Допустим, нам нужно добавить к модели поля slug и order, которые не должны быть пустыми. Причём slug должен иметь атрибут unique=True.
Сначала нужно добавить необходимые поля без unique=True:
class Project(models.Model): title = models.CharField('Название', max_length=255) slug = models.SlugField('Путь', max_length=80, help_text=slug_ht) order = models.PositiveIntegerField('Порядок', db_index=True)
Теперь вызываем makemigration. Django спросит нас, какими данными заполнить добавляемые поля существующих записей в базе данных. Пока можно заполнить произвольными данными:
You are trying to add a non-nullable field 'order' to project without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows) 2) Quit, and let me add a default in models.py Select an option: 1 Please enter the default value now, as valid Python The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now() >>> 0 You are trying to add a non-nullable field 'slug' to project without a default; we can't do that (the database needs something to populate existing rows). Please select a fix: 1) Provide a one-off default now (will be set on all existing rows) 2) Quit, and let me add a default in models.py Select an option: 1 Please enter the default value now, as valid Python The datetime and django.utils.timezone modules are available, so you can do e.g. timezone.now() >>> 'slug'
Теперь добавляем к полю slug атрибут unique=True:
class Project(models.Model): title = models.CharField('Название', max_length=255) slug = models.SlugField('Путь', max_length=80, unique=True, help_text=slug_ht) order = models.PositiveIntegerField('Порядок', db_index=True)
Вызываем makemigration, открываем созданную миграцию и добавляем свой код правки данных, например, так:
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations import cms.models.fields def generate_slug_and_order(apps, schema_editor): Project = apps.get_model('projects', 'Project') for i, obj in enumerate(Project.objects.all(), start=1): obj.slug = '{}_{}'.format(obj.slug, i) obj.order = i obj.save() class Migration(migrations.Migration): dependencies = [ ('projects', '0005_auto_20160328_1839'), ] operations = [ migrations.RunPython(generate_slug_and_order), migrations.AlterField( model_name='project', name='slug', field=models.SlugField(unique=True, max_length=80, verbose_name='\u041f\u0443\u0442\u044c'), ), ]
По необходимости теперь можно ручками завершить правку данных в админке, то что кодом было бы дольше.
Отдельные примеры
Задать порядок (order) для модели
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations import cms.models.fields def generate_order(apps, schema_editor): Project = apps.get_model('projects', 'Project') for i, obj in enumerate(Project.objects.all(), start=1): obj.order = i obj.save() class Migration(migrations.Migration): dependencies = [ ('projects', '0005_auto_20160328_1839'), ] operations = [ migrations.RunPython(generate_order), migrations.AlterField( model_name='project', name='order', field=models.PositiveIntegerField(verbose_name='\u041f\u043e\u0440\u044f\u0434\u043e\u043a', db_index=True), ), ]
Установить slug
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations from sb_core.utils.sb_utils import transliterate def set_slug(apps, schema_editor): Receipt = apps.get_model('products', 'Receipt') for obj in Receipt.objects.all(): obj.slug = transliterate(obj.title, is_slug=True) obj.save() class Migration(migrations.Migration): dependencies = [ ('products', '0007_receipt_slug'), ] operations = [ migrations.RunPython(set_slug), ]
Задать статус заказам
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations def paid(obj): return sum([payment.amount for payment in obj.payments.all()]) def is_fully_paid(obj): return paid(obj) >= obj.amount def set_status(apps, schema_editor): Order = apps.get_model('orders', 'Order') for obj in Order.objects.all(): if paid(obj) == 0: obj.status ='waiting_payment' elif is_fully_paid(obj): obj.status = 'fully_paid' else: obj.status = 'partially_paid' obj.save() class Migration(migrations.Migration): dependencies = [ ('orders', '0025_order_status'), ] operations = [ migrations.RunPython(set_status), ]
Убрать null=True
# -*- coding: utf-8 -*- from __future__ import unicode_literals from django.db import models, migrations def set_blank(apps, schema_editor): MyModel = apps.get_model('my_app', 'MyModel') for obj in MyModel.objects.all(): obj.content = obj.content or '' obj.template = obj.template or '' obj.title = obj.title or '' obj.save() class Migration(migrations.Migration): dependencies = [ ('my_app', '0007_auto_20160509_1225'), ] operations = [ migrations.RunPython(set_blank), migrations.AlterField( model_name='mymodel', name='content', field=models.TextField(default='', blank=True), preserve_default=False, ), migrations.AlterField( model_name='mymodel', name='template', field=models.CharField(default='', max_length=255, blank=True), preserve_default=False, ), migrations.AlterField( model_name='mymodel', name='title', field=models.CharField(default='', max_length=100, blank=True), preserve_default=False, ), ]
Похожие статьи:
Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.
Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.
Комментарии: 0