django从递归模型创建对象

时间:2017-09-22 10:18:03

标签: django django-models django-rest-framework

我在创建具有递归关系的对象时遇到问题。因此,场景就在创建组织之后,将用户插入到刚刚创建的组织中。

# models.py
class Organization(models.Model):
    name = models.CharField(max_length=32)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    code = models.CharField(max_length=4, unique=True)
    photo_path = models.CharField(max_length=256, null=True)

    class Meta:
        db_table = 'organization'

    def __str__(self):
        return self.name


class OrganizationLevel(models.Model):
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        db_index=False
    )
    parent = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,
        db_index=False
    )
    name = models.CharField(max_length=48)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = 'organization_level'
        unique_together = ('name', 'organization')


class OrganizationUnit(models.Model):
    organization_level = models.ForeignKey(
        OrganizationLevel,
        on_delete=models.CASCADE,
        db_index=False
    )
    name = models.CharField(max_length=48)
    position = models.PointField(geography=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    parent = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,
        db_index=False
    )
    address = models.CharField(max_length=256)

    class Meta:
        db_table = 'organization_unit'
        unique_together = ('name', 'organization_level')

class User(models.Model):
    email = models.CharField(max_length=64)
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=64)
    token = models.CharField(max_length=32, null=True)
    tokenexp = models.DateTimeField(null=True)
    photo_path = models.CharField(max_length=256)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE
    )
    is_activated = models.BooleanField(default=False)
    code = models.CharField(max_length=32, null=True)
    name = models.CharField(max_length=64)
    birthdate = models.DateTimeField(null=True)
    sex = models.CharField(max_length=1)
    address = models.CharField(max_length=80)
    organization_unit = models.ForeignKey(
        OrganizationUnit,
        on_delete=models.CASCADE
    )

    class Meta:
        db_table = 'user'

所以从给定的模型来看,这里是流程:

  1. 创建组织
  2. 从组织实例创建组织级别实例
  3. 从组织级实例创建组织单位实例
  4. 我已经尝试过这样但却出错了

    org = Organization.objects.create(
                name=name,
                code=code.upper()
            )
            org.save()
    
            lvl = OrganizationLevel.objects.create(
                organization=org,
                parent=org.id,
                name="Level1"
            )
            lvl.save()
    
            unit = OrganizationUnit.objects.create(
                name="Unit Name",
                organization_level=lvl,
                parent=lvl.id
            )
            unit.save()
    

    无法分配" 6":" OrganizationLevel.parent"必须是" OrganizationLevel"实例

    什么是正确答案?

2 个答案:

答案 0 :(得分:1)

如果您更改了组织级别模型,该怎么办:

class OrganizationLevel(models.Model):
organization = models.ForeignKey(
    Organization,
    on_delete=models.CASCADE,
    db_index=False
)
parent = models.ForeignKey(
    'self',
    on_delete=models.CASCADE,
    db_index=False,
    blank=True, 
    null=True
)
name = models.CharField(max_length=48)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

class Meta:
    db_table = 'organization_level'
    unique_together = ('name', 'organization')

答案 1 :(得分:1)

对于递归关系(ForeignKey to self),外键需要接受null - 否则你将永远无法创建至少第一个实例(否则它将需要对另一个预先存在的记录的引用,这不能是创建时没有引用另一个预先存在的记录等 - 鸡和鸡蛋问题......),所以你想要:

class OrganizationLevel(models.Model):
    # ...
    parent = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,
        db_index=False,
        null=True,
        blank=True
    )

class OrganizationUnit(models.Model):
    # ...
    parent = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,
        db_index=False,
        null=True,
        blank=True
    )

创建第一个级别和单位时,请留下这些空白:

    lvl = OrganizationLevel.objects.create(
        organization=org,
        parent=None,
        name="Level1"
    )

    unit = OrganizationUnit.objects.create(
        name="Unit Name",
        organization_level=lvl,
    )

请注意,YourModel.objects.create() 在数据库中创建记录,因此您无需在此处为您的实例调用.save()

然后,当您想要添加子级别或子级单元时,您必须将父实例(不是它的id - 实例本身)作为parent参数传递或将父实例ID传递为parent_id参数(实际上对于任何ForeignKey都相同:您的传递' fieldname = related_instance'或' fieldname_id = related_instance_id)。