Миграции в 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