首页 > 解决方案 > 将大量模型从 Foreigner Table 更新为 Django Rest 中的 Current Table

问题描述

我在 Django 模型中有 3 个模型和一个抽象模型。

我想在 ScentData 中添加字段并将域从子域复制到 Scentdata。

# Abstract Model
class TimeStampedModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    created_at = models.DateTimeField(
        verbose_name='Create At',
        auto_now_add=True
    )
    is_deleted = models.BooleanField(default=False)
    modified = models.DateTimeField(auto_now=True)
    deleted = models.DateTimeField(null=True, blank=True)
    objects = NoDeleteManager()
    objects_with_deleted = models.Manager()
    class Meta:
        abstract = True
        ordering = ['created_at']
class Domain(TimeStampedModel):
    name = models.CharField(
        max_length=64,
        null=False,
        blank=False,
        unique=False,
        default=''
    )


class SubDomain(TimeStampedModel):
    name = models.CharField(
        max_length=64,
        null=False,
        blank=False,
        unique=False,
        default=''
    )
    domain = models.ForeignKey(
        'Domain',
        on_delete=models.PROTECT,
        related_name='subdomains'
    )


class ScentData(TimeStampedModel):
    name = models.CharField(
        max_length=64,
        blank=False,
        null=False,
        default=''
    )
    subdomain = models.ForeignKey(
        'SubDomain',
        on_delete=models.PROTECT,
        related_name='scentdata_subdomain'
    )

但现在我向ScentData模型添加了一个domain字段。

class ScentData(TimeStampedModel):
    name = models.CharField(
        max_length=64,
        blank=False,
        null=False,
        default=''
    )
    subdomain = models.ForeignKey(
        'SubDomain',
        on_delete=models.PROTECT,
        related_name='scentdata_subdomain'
    )
    domain = models.ForeignKey(
        'Domain',
        on_delete=models.PROTECT,
        related_name='scentdata_domain',
        null=True,
        blank=True
    )

    def set_domain(self):
        self.domain = self.subdomain.domain
        self.save()
        return self

我已经编写了ModelViewSetset_domain来在 ScentData 中运行函数,但我在Scentdata中有 200K 行,所以我的服务器无法处理这么长时间的更改。下面是我的 ViewSet。

class ScentDataViewSet(viewsets.ModelViewSet):
    queryset = ScentData.objects.all()

    @action(detail=False, methods=['GET'], url_path="reset_domain")
    def reset_domain(self, pk=None, **kwargs):
        scent_data = ScentData.objects.all()
        for scent_data_obj in scent_data:
            scent_data_obj.set_domain()
        return Response({"detail": "success"})

是否有任何技术可以更快地将移动到ScentData

标签: django-modelsdjango-rest-frameworkdjango-views

解决方案


您可以使用select_related和改进此过程bulk_update

updated_scent_data = []

scent_data = ScentData.objects.select_related('subdomain__domain').all()

for scent_data_obj in scent_data:
    scent_data_obj.domain = scent_data_obj.subdomain.domain
    updated_scent_data.append(scent_data_obj)

ScentData.objects.bulk_update(updated_scent_data, ['domain'])

select_related所以每次迭代scent_data都不必scent_data_obj为了得到subdomain.domain.

bulk_update更新ScentData一个数据库命中中的所有对象。


推荐阅读