見出し画像

Django_models.ForeignObjectとは #230日目

ForeignObjectはForeignKeyの親クラスにもなっているもので、モデル同士で多対一の関係を作ります。特徴として、複数列でテーブル同士を関連づけることが可能です。

先にForeignObjectをフィールドに使ったモデルの記述方法を例示します。「TaskResult」というモデルに、task_idカラムでリレーションしています。

from django_celery_results.models import TaskResult

class Project(models.Model):
  name = models.CharField(max_length=255, blank=False)
  task_id = models.CharField(max_length=255, null=True)
  task_result = models.ForeignObject(TaskResult, null=True, from_fields=(
      'task_id',), to_fields=('task_id',), related_name='+', on_delete=models.DO_NOTHING)

ForeignObjectの場合は、ForeignKeyと違ってリレーションのためのカラムを定義しておかなければいけません(task_id)。ただ逆にいうとそこを自由に設定できます。

ソースコードを確認すると、ForeignObjectやForeignKeyはrelatedモジュールに記述されています。

[django/django/db/models/fields/related.py]


class ForeignObject(RelatedField):
    """
    Abstraction of the ForeignKey relation, supports multi-column relations.
    """

    # Field flags
    many_to_many = False
    many_to_one = True
    one_to_many = False
    one_to_one = False

    requires_unique_target = True
    related_accessor_class = ReverseManyToOneDescriptor
    forward_related_accessor_class = ForwardManyToOneDescriptor
    rel_class = ForeignObjectRel

    def __init__(
        self,
        to,
        on_delete,
        from_fields,
        to_fields,
        rel=None,
        related_name=None,
        related_query_name=None,
        limit_choices_to=None,
        parent_link=False,
        swappable=True,
        **kwargs,
    ):
 

~ 略 ~
[django/django/db/models/fields/related.py]


class ForeignKey(ForeignObject):
    """
    Provide a many-to-one relation by adding a column to the local model
    to hold the remote value.

    By default ForeignKey will target the pk of the remote model but this
    behavior can be changed by using the ``to_field`` argument.
    """

~ 略 ~

上記で示したProjectモデルに当てはめると、

・toに結合したいテーブルを指定(Projectモデルでは仮引数を省略)
  →TaskResult
・to_fieldに結合先のカラムをリストやタプルで指定
  →('task_id', )
・from_fieldに結合元 (記述してるモデル)のカラムをリストやタプルで指定
  →('task_id', )

to_fieldとfrom_fieldに指定したカラム同士が結びつくことになります。ここでは[None]と指定することも可能で、その場合はpk (primary key)を参照する形になります。


ただ、一見するとForeignKeyではなくForeignObjectを使う理由があまり見当たらず、どういうケースで使われているのか正確には理解できなかったです。

「TaskResult」に対して使われている事例を見たので、、参照先のデータベースがRedisだとForeignKeyが対応していないのかなと勝手に考えています。

ここまでお読みいただきありがとうございました!!

参考


この記事が気に入ったらサポートをしてみませんか?