Django模型继承-基于父实例创建子对象

Hom*_*lli 8 python django django-models

我正在使用 Django 4.0

我有以下型号:

class Parent(models.Model):
    # fields ommitted for the sake of brevity
    pass

class Child(Parent):
   child_only_field = models.CharField(max_length=64)
Run Code Online (Sandbox Code Playgroud)

代码

p = Parent.objects.create(**fields_dict)
c1 = Child.objects.create(child_only_field='Hello 123', p) # Obviously won't work
# c2 = ...
Run Code Online (Sandbox Code Playgroud)

有没有办法从父对象的实例创建子对象(无需手动“解包”父对象的字段)?

小智 5

如果您了解 Django 如何使用 implizit o2o 关系,这很容易。

class Parent(Model):
    # fields

# implizit o2o
class Child(Parent):
   child_only_field = models.CharField(max_length=64)

# explizit o2o
class Child_1(Parent):
  parent = models.OneToOneField(Parent)
  child_only_field = models.CharField(max_length=64)
Run Code Online (Sandbox Code Playgroud)

如何使用 Implizit o2o 关系保存或创建子项。

1.通过现有的父类对象保存子对象,不要在正常代码中使用它

parent = Parent.objects.get(pk=some_pk)
child = Child(child_only_field='Hello 123', pk=parent.pk)
child.save_base(raw=True) # important part of code
Run Code Online (Sandbox Code Playgroud)

Model.save_base- 仅保存子字段信息的内部方法。但父数据应该已经存在。

2.将创建的父级保存为子级。不要在正常代码中使用它

parent = Parent.objects.get(pk=some_pk)
parent.child_only_field = 'Hello 123'
parent.save_base(class=Child)
Run Code Online (Sandbox Code Playgroud)

Model.save_base方法保存整个继承链的信息。

3.正常保存创建的子进程。请在正常代码中使用它

child = Child(child_only_field='Hello 123', **fields_dict)
child.save()
Run Code Online (Sandbox Code Playgroud)

我特别不使用 DataManager。我可以说,这更多的是内部方法,而不是公共接口。

  1. 通过 DataManager 保存子项。

    child = Child.objects.create(child_only_field='你好123', **fields_dict)

    objects.create从我的回答中得出了第3点。你可以在 django.db.models.query.py 中看到它

我希望它有帮助。


meh*_*rh8 0

通过和将 的字段转换p为字典。model_to_dictp._meta.fields

from django.forms.models import model_to_dict

class Parent(models.Model):
    # fields ommitted for the sake of brevity

    def fields_dict(self):
        return model_to_dict(
            p,
            fields=[
                field.name
                for field in self._meta.fields
                if field.name in self.__dict__
                and field.name != self._meta.pk.name
            ]
        )

class Child(Parent):
   child_only_field = models.CharField(max_length=64)

p = Parent.objects.create(**fields_dict)

c1 = Child.objects.create(child_only_field='Hello 123', **p.fields_dict())
Run Code Online (Sandbox Code Playgroud)

也可以覆盖create方法。

from django.forms.models import model_to_dict

class MyManager(models.Manager):
    def create(self, *args, **kwargs):
        if 'parent_obj' in kwargs:
            parent_fields = parent_obj.fields_dict()
        return super().create(*args, **kwargs, **parent_fields)

class Parent(models.Model):
    # fields ommitted for the sake of brevity

    def fields_dict(self):
        return model_to_dict(
            p,
            fields=[
                field.name
                for field in self._meta.fields
                if field.name in self.__dict__
                and field.name != self._meta.pk.name
            ]
        )

class Child(Parent):
    objects = MyManager()

    child_only_field = models.CharField(max_length=64)
    

p = Parent.objects.create(**fields_dict)

c1 = Child.objects.create(child_only_field='Hello 123', parent_obj=p)

Run Code Online (Sandbox Code Playgroud)