web-dev-qa-db-ja.com

Django-プロパティを外部キーとして使用します

アプリのデータベースにデータが入力され、外部データソースとの同期が維持されます。私の抽象モデルがありますDjango 2.2アプリのすべてのモデルは、次のように定義されています:

_class CommonModel(models.Model):
    # Auto-generated by Django, but included in this example for clarity.
  # id = models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
    Origin_SOURCEA = '1'
    Origin_SOURCEB = '2'
    Origin_CHOICES = [
        (Origin_SOURCEA, 'Source A'),
        (Origin_SOURCEB, 'Source B'),
    ]
    object_Origin = models.IntegerField(choices=Origin_CHOICES)
    object_id = models.IntegerField()

class A(CommonModel):
    some_stuff = models.CharField()

class B(CommonModel):
    other_stuff = models.IntegerField()
    to_a_fk = models.ForeignKey("myapp.A", on_delete=models.CASCADE)

class C(CommonModel):
    more_stuff = models.CharField()
    b_m2m = models.ManyToManyField("myapp.B")
_

_object_id_フィールド一意として設定することはできませんアプリで使用する各データソースには、_object_id = 1_のオブジェクトがある場合があるためです。したがって、フィールド_object_Origin_によって、オブジェクトのオリジンを追跡する必要があります。

残念ながら、DjangoのORMは複数の列の外部キーをサポートしていません。

問題

自動生成された主キーをデータベース(id)に保持しながら、外部キーと多対多の関係を_object_id_と_object_Origin_の両方のフィールドで発生させたい主キーの代わりにid

私が試したこと

私はこのようなことをすることを考えました:

_class CommonModel(models.Model):
    # Auto-generated by Django, but included in this example for clarity.
  # id = models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')
    Origin_SOURCEA = '1'
    Origin_SOURCEB = '2'
    Origin_CHOICES = [
        (Origin_SOURCEA, 'Source A'),
        (Origin_SOURCEB, 'Source B'),
    ]
    object_Origin = models.IntegerField(choices=Origin_CHOICES)
    object_id = models.IntegerField()

    def _get_composed_object_Origin_id(self):
        return f"{self.object_Origin}:{self.object_id}"
    composed_object_Origin_id = property(_get_composed_object_Origin_id)

class A(CommonModel):
    some_stuff = models.CharField()

class B(CommonModel):
    other_stuff = models.IntegerField()
    to_a_fk = models.ForeignKey("myapp.A", to_field="composed_object_Origin_id", on_delete=models.CASCADE)
_

しかしDjangoはそれについて不平を言う:

myapp.B.to_a_fk: (fields.E312) The to_field 'composed_object_Origin_id' doesn't exist on the related model 'myapp.A'.

Djangoは、データベースフィールドとして_to_field_に指定されたフィールドを除きます。ただし、新しいフィールドをCommonModelに追加する必要はありません。 _composed_object_type_id_は2つのnull不可フィールドを使用して構築されています...

8
Spacebrain

合成オブジェクトのオリジンIDを、saveで更新され、composed_object_Origin_idとして使用されるフィールド(to_field)にすることができます。

class CommonModel(models.Model):
    Origin_SOURCEA = "1"
    Origin_SOURCEB = "2"
    Origin_CHOICES = [
        (Origin_SOURCEA, "Source A"),
        (Origin_SOURCEB, "Source B"),
    ]
    object_Origin = models.IntegerField(choices=Origin_CHOICES)
    object_id = models.IntegerField()
    composed_object_Origin_id = models.CharField(max_length=100, unique=True)

    def save(self, **kwargs):
        self.composed_object_Origin_id = f"{self.object_Origin}:{self.object_id}"

        # Just in case you use `update_fields`, force inclusion of the composed object Origin ID.
        # NOTE: There's definitely a less error-prone way to write this `if` statement but you get
        # the Gist. e.g., this does not handle passing `update_fields=None`.
        if "update_fields" in kwargs:
            kwargs["update_fields"].append("composed_object_Origin_id")

        super().save(**kwargs)


class A(CommonModel):
    some_stuff = models.CharField(max_length=1)


class B(CommonModel):
    other_stuff = models.IntegerField()
    to_a_fk = models.ForeignKey(
        "myapp.A", to_field="composed_object_Origin_id", on_delete=models.CASCADE
    )
1
Cole