Миграции в 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 из 5 (всего 0 оценок)

captcha
Отмеченные звёздочкой поля ( * ) являются обязательными для заполнения.

Спасибо за ваш отзыв!

После нажатия кнопки "Отправить" ваше сообщение будет доставлено мне на почту.

Автор статьи

Артём Мальцев

Веб-разработчик, владеющий знаниями языка программирования Python, фреймворка Django, системы управления содержимым сайта Django CMS, платформы для создания интернет-магазина Django Shop и многих различных приложений, использующих эти технологии.

Права на использование материала, расположенного на этой странице https://vivazzi.pro/ru/it/migration-examples/:

Разрешается копировать материал с указанием её автора и ссылки на оригинал без использования параметра rel="nofollow" в теге <a>. Использование:

Автор статьи: Артём Мальцев
Ссылка на статью: <a href="https://vivazzi.pro/ru/it/migration-examples/">https://vivazzi.pro/ru/it/migration-examples/</a>

Больше: Правила использования сайта

Представляю вашему вниманию книгу, написанную моим близким другом Максимом Макуриным: Секреты эффективного управления ассортиментом.

Книга предназначается для широкого круга читателей и, по мнению автора, будет полезна специалистам отдела закупок и логистики, категорийным и финансовым менеджерам, менеджерам по продажам, аналитикам, руководителям и директорам, в компетенции которых принятие решений по управлению ассортиментом.

Комментарии: 0

Вы можете оставить комментарий как незарегистрированный пользователь.

Но зарегистрировавшись, вы сможете:

  • получать оповещения об ответах
  • просматривать свои комментарии
  • иметь возможность использовать все функции разработанных сервисов

Для комментирования от своего имени войдите или зарегистрируйтесь на сайте Vuspace

Отправить

На данный момент нет специального поиска, поэтому я предлагаю воспользоваться обычной поисковой системой, например, Google, добавив "vivazzi" после своего запроса.

Попробуйте

Выберите валюту для отображения денежных единиц