【问题标题】:Django - unavailable field of model while doing migrationDjango - 进行迁移时模型的不可用字段
【发布时间】:2017-12-08 00:07:48
【问题描述】:

也许我已经筋疲力尽,看不到简单的东西,但是在 Django 1.9.7 中,在进行迁移时我发现了一些奇怪的东西, 我正在寻找解释。

在通过apps(在 RunPython 操作中为 (django.db.migrations.state.StateApps) 获取模型类时,我有 AttributeError 用于存在的字段。

我的模特:

class Weight(models.Model):
    INF = 2**31-1

    minimum = models.PositiveIntegerField()
    maximum = models.PositiveIntegerField()
    carrier = models.ForeignKey(Carrier)

    class Meta:
        ordering = ['carrier__name', 'minimum']

在从RunPython 运行的迁移方法中,我有:

Weight = apps.get_model('calc.Weight')

然后有例外,但仅限于某些领域。

来自调试(由 RunPython 运行的内部方法):

>>> Weight.maximum                                                                                              
Traceback (most recent call last):                                                                                   
  File "<pudb command line>", line 1, in <module>                                                                    
AttributeError: type object 'Weight' has no attribute 'maximum'  


>>> Weight.minimum                                               
Traceback (most recent call last):                                                                                   
  File "<pudb command line>", line 1, in <module>                                                                    
AttributeError: type object 'Weight' has no attribute 'minimum'  

>>> Weight.INF                                                                                                  
Traceback (most recent call last):                                                                                   
  File "<pudb command line>", line 1, in <module>                                                                    
AttributeError: type object 'Weight' has no attribute 'INF'

但是:

>>> Weight.carrier                                                                                              
<django.db.models.fields.related_descriptors.ForwardManyToOneDescriptor object at 0x7f8dcca692d0>


>>> Weight._meta.fields
(<django.db.models.fields.AutoField: id>, <django.db.models.fields.PositiveIntegerField: minimum>,
<django.db.models.fields.PositiveIntegerField: maximum>, <django.db.models.fields.related.ForeignKey: carrier>)

type(Weight)
<class 'django.db.models.base.ModelBase'>

所以不知何故只有载体字段可用,为什么?

  • 语法和名称都可以,
  • 准备迁移(由 Django)也可以(包含所有字段)

--------

更新: 我的迁移文件是:

from __future__ import unicode_literals

from django.db import migrations, models
import django.db.models.deletion

def add_weights(app, *args):
    Carrier = app.get_model('calc.Carrier')
    Weight = app.get_model('calc.Weight')
    # import pudb;pu.db
    carrier_obj = Carrier.objects.get(name='MainCarrier')
    Weight.objects.create(carrier=carrier_obj, minimum=1, maximum=400)  # OK, yes it works within `create`
    Weight.objects.create(carrier=carrier_obj, minimum=401, maximum=800)  # OK
    Weight.objects.create(carrier=carrier_obj, minimum=800, maximum=Weight.INF) # here is AttributeError


class Migration(migrations.Migration):

    dependencies = [
        ('calc', '0012_auto_20170622_1310'),
    ]

    operations = [
        migrations.CreateModel(
            name='Weight',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('minimum', models.PositiveIntegerField()),
                ('maximum', models.PositiveIntegerField()),
                ('carrier', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='calc.Carrier')),
            ],
            options={
                'ordering': ['carrier__name', 'minimum'],
            },
        ),
        migrations.RunPython(add_weights)
    ]

顺便说一句:毕竟我可以将 INF 放在类主体之外,并且有解决方法,但是了解正在发生的事情对我来说更重要。

【问题讨论】:

  • 什么是重量范围?
  • 请显示失败的迁移。
  • 您是否在创建上次迁移后将这些字段添加到模型中?
  • @DanielRoseman:好点,但仍然 - 为什么一个字段可见,而另一个字段不可见?猜测 ForeignKey 比普通字段更早加载......但 INF 仍然只是一个简单的整数,它不是一个字段。我可以在定义/添加该模型时访问它吗?
  • 你有没有找到原因和解决方案?

标签: python django migration


【解决方案1】:

app.get_model(...) 调用将返回一个 django.db.models.base.ModelBase 实例,而不是您的 Weight 模型,这就是您看不到 INF 的原因。

使用替代名称导入它(这样它就不会影响您的 Weight 变量),您就可以使用它了:

  from myapp.models import Weight as WeightModel
  ...
  ...
  maximum = WeightModel.INF

【讨论】:

  • 当然是ModelBase,但是运行在python manage.py shell:from django.apps import apps,然后apps.get_model('calc.Weight').INF你会看到这个属性的值而不是AttributeError
  • 顺便说一句,ModelBase 是一个元类,而不是父类。
  • 如果您这样做,请记住warnings from the documentation。还提到了here
【解决方案2】:

仅供参考, 我通过放置非模型字段和自定义方法解决了我的问题 进入新类的定义

一般:

class MyModelInterface(object): ..
class MyModel(models.Model, MyModelInterface): ..

MyModelInterface 是模型的 mixin,但如果需要,我可以单独使用它。

我发现它是 Django 模型的一个好习惯, 所以在迁移等特殊需求中,我可以直接评估接口类。 此外,避免使用许多自定义方法、属性...

【讨论】:

  • Django 文档中是否对此有解释或警告?我没有找到任何相关的东西。我在迁移期间使用的一些 @property 装饰函数也遇到了类似的问题,并通过在 mixin 中实现它们来解决。
【解决方案3】:

我认为这个错误的原因是数据库变化和状态变化有不同的方面。文档说

一种高度专业化的操作,可让您混合和匹配操作的数据库(模式更改)和状态(自动检测器供电)方面。

它接受两个列表操作,当被要求应用状态时将使用状态列表,当被要求对数据库应用更改时将使用数据库列表。除非您非常确定自己知道自己在做什么,否则不要使用此操作。

https://docs.djangoproject.com/en/1.9/ref/migration-operations/#separatedatabaseandstate

该案例的正确更新如下;

operations = [
    migrations.SeparateDatabaseAndState(
        [
            migrations.CreateModel(
                name='Weight',
                fields=[
                    ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                    ('minimum', models.PositiveIntegerField()),
                    ('maximum', models.PositiveIntegerField()),
                    ('carrier', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='calc.Carrier')),
                ],
                options={
                    'ordering': ['carrier__name', 'minimum'],
                },
            )
        ],
        [
            migrations.RunPython(add_weights)
        ]
    )
]

但是,我会在单独的文件中进行这 2 次迁移,因为它们有不同的目的,并且将来恢复可能会很痛苦。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-02-20
    • 1970-01-01
    • 2021-08-06
    • 2016-04-20
    • 1970-01-01
    • 2021-10-06
    • 2016-02-10
    • 1970-01-01
    相关资源
    最近更新 更多