我有一个Django模型(称为BiomSearchJob
),它目前正在运行,我想添加一个新的多对多关系,以使系统更易于为用户定制。以前,用户可以在不指定一组TaxonomyLevelChoices
的情况下提交作业,但是为了向系统添加更多功能,用户现在应该能够选择他们自己的分类级别。
以下是模型:
class TaxonomyLevelChoice(models.Model):
taxon_level = models.CharField(
verbose_name="Taxonomy Chart Level", max_length=60)
taxon_level_proper_name = models.CharField(max_length=60)
def __unicode__(self):
return self.taxon_level_proper_name
class BiomSearchJob(models.Model):
...
# The new many-to-many relation
taxonomy_levels = models.ManyToManyField(
'TaxonomyLevelChoice', blank=False, max_length=3,
default=["phylum", "class", "genus"])
name = models.CharField(
null=False, blank=False, max_length=100, default="Unnamed Job",
validators=[alphanumeric_spaces])
...
目前,所有现有BiomSearchJobs
隐含地具有default=
项中列出的三个分类级别(用户无法选择),因此在数据库中都是相同的。运行migrate
后,我发现以前的作业没有立即拥有三个分类级别关系,它们只在调用job.taxonomy_levels.all()
时返回一个空集(如果job
是{的实例{ {1}})。
有没有办法追溯性地添加这种关系而无需手动浏览所有内容?理想情况下,只需运行BiomSearchJob
,我希望现有migrate
在BiomSearchJobs
属性中列出phylum
,class
和genus
。
答案 0 :(得分:8)
我认为您正在寻找数据迁移,这是一种允许仅对数据库进行数据更改的迁移。
您可以这样创建:
python manage.py makemigrations <your app> --name=retroactively_add_levels
然后将此代码插入刚刚创建的迁移文件中:
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations
def add_taxonomy_levels(apps, schema_editor):
BiomSearchJob = apps.get_model('<your app>', 'BiomSearchJob')
TaxonomyLevelChoice = apps.get_model('<your app>', 'TaxonomyLevelChoice')
for job in BiomSearchJob.objects.all():
for choice in TaxonomyLevelChoice.objects.filter(taxon_level_proper_name__in=["phylum", "class", "genus"]):
job.taxonomy_levels.add(choice)
class Migration(migrations.Migration):
dependencies = []
operations = [
migrations.RunPython(add_taxonomy_levels, reverse_code=migrations.RunPython.noop)
]
它几乎可以像SQL查询那样工作,但它可以利用Django ORM。
希望这有帮助。
答案 1 :(得分:3)
您的方法无法正常工作,因为您隐式想要对实例属性进行查询:Django无法猜测。
从Django's Doc开始,默认可以是一个函数,而
对于像映射到模型实例的ForeignKey这样的字段,默认值应该是它们引用的字段的值(除非设置了to_field,否则为pk)而不是模型实例。
所以....要么你传递PK(例如ID)数组,要么使用函数来获取查询集。
class TaxonomyLevelChoice(models.Model):
taxon_level = models.CharField(
verbose_name="Taxonomy Chart Level", max_length=60)
taxon_level_proper_name = models.CharField(max_length=60)
def __unicode__(self):
return self.taxon_level_proper_name
def get_default_taxonomy_levels():
...
return YourQuerySet
class BiomSearchJob(models.Model):
...
# The new many-to-many relation
taxonomy_levels = models.ManyToManyField(
'TaxonomyLevelChoice', blank=False, max_length=3,
default=get_taxonomy_levels_default)
name = models.CharField(
null=False, blank=False, max_length=100, default="Unnamed Job",
validators=[alphanumeric_spaces])
...
如果您在尚未创建TaxonomyLevelChoice
个实例之前进行迁移,我猜您会遇到迁移问题。
由于前面的句子,我会使用一些伪缓存方法,因为每次创建BiomSearchJob
时进行查询都不是一个可接受的解决方案。
我会这样做:
DEFAULT_TAXONOMY_LEVELS = None
def get_default_taxonomy_levels():
if DEFAULT_TAXONOMY_LEVELS:
return DEFAULT_TAXONOMY_LEVELS
...
DEFAULT_TAXONOMY_LEVELS = YourQuerySet
return YourQuerySet
编辑:由于问题是回溯主动设置多对多的默认值,我建议在现有实例上执行此命令,因为我认为迁移不会为您处理。