ORM🏹: 長いMany-to-one関係




形成された関係によって
リレーションシップを作成するテーブルにアクセスできます.


Reporter : Article = 1 : M

1.レポートから記事OKにアクセス



1-1. article_set

  • に「article set」が表示されていることを確認!
  • 「article set」はreporterからarticleにアクセスするコマンドです!
  • 記者と文章は1:N関係
  • 一人の記者は多くの文章を書くことができます.
  • だから私は文章の中でrepotter属性を作成して、それをrepotter(外部キー)に指さすようにして、
  • 一人の記者が複数の文章になることができます
  • 記者の立場に立って私の文章を見て誰がいるか知りたいのではないでしょうか.
  • だから張戈は記者のインスタンスがarticle setを検索することを許可します!
  • 返信インスタンスはarticle setで自分の文章を表示できます!複数なので「set」という言葉を使いましたが、
  • ではありません.
    >>> r1 = Reporter.objects.get(id=1)
    >>> r1
    <Reporter: John Smith>
    >>> 
    >>> dir(r1)
    ['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_check_column_name_clashes', '_check_constraints', '_check_field_name_clashes', '_check_fields', '_check_id_field', '_check_index_together', '_check_indexes', '_check_local_fields', '_check_long_column_names', '_check_m2m_through_same_relationship', '_check_managers', '_check_model', '_check_model_name_db_lookup_clashes', '_check_ordering', '_check_property_name_related_field_accessor_clashes', '_check_single_primary_key', '_check_swappable', '_check_unique_together', '_do_insert', '_do_update', '_get_FIELD_display', '_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', '_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_save_parents', '_save_table', '_set_pk_val', '_state', 
    'article_set', 
    'check', 'clean', 'clean_fields', 'date_error_message', 
    'delete',
    'email', 'first_name', 
    'from_db', 'full_clean', 'get_deferred_fields', 
    'id', 'last_name', 
    'objects', 'pk', 
    'prepare_database_save', 'refresh_from_db', 
    'save', 'save_base', 
    'serializable_value', 'unique_error_message', 'validate_unique']
    >>> 

    article setでできること

    >>> r1
    <Reporter: John Smith>
    >>> 
    >>> dir(r1.article_set)
    ['__call__', '__class__', '__class_getitem__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__slotnames__', '__str__', '__subclasshook__', '__weakref__', '_apply_rel_filters', '_constructor_args', '_db', '_get_queryset_methods', '_hints', '_insert', '_queryset_class', '_remove_prefetched_objects', '_set_creation_counter', '_update', 
    'add', 'aggregate', 'all', 'annotate', 
    'auto_created', 'bulk_create', 'bulk_update', 
    'check', 'complex_filter', 'contribute_to_class', 
    'core_filters', 'count', 
    'create', 'creation_counter', 'dates', 'datetimes', 
    'db', 'db_manager', 'deconstruct', 
    'defer', 'difference', 
    'distinct', 'do_not_call_in_templates', 
    'earliest', 'exclude', 
    'exists', 'explain', 'extra', 'field', 'filter', 
    'first', 
    'from_queryset', 
    'get', 'get_or_create', 'get_prefetch_queryset', 'get_queryset', 
    'in_bulk', 'instance', 'intersection', 'iterator', 
    'last', 'latest', 'model', 
    'name', 'none', 'only', 
    'order_by', 'prefetch_related', 
    'raw', 'reverse', 
    'select_for_update', 'select_related', 
    'set', 'union', 'update', 'update_or_create', 
    'use_in_migrations', 'using', 
    'values', 'values_list']
    >>> 

    2.記事から記者okを訪問



    2-1. reporter_id, reporter

  • 「記者id」、「記者」!!
  • >>> a1 = Article.objects.get(id=1)
    >>> dir(a1)
    ['DoesNotExist', 'MultipleObjectsReturned', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getstate__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_check_column_name_clashes', '_check_constraints', '_check_field_name_clashes', '_check_fields', '_check_id_field', '_check_index_together', '_check_indexes', '_check_local_fields', '_check_long_column_names', '_check_m2m_through_same_relationship', '_check_managers', '_check_model', '_check_model_name_db_lookup_clashes', '_check_ordering', '_check_property_name_related_field_accessor_clashes', '_check_single_primary_key', '_check_swappable', '_check_unique_together', '_do_insert', '_do_update', '_get_FIELD_display', '_get_next_or_previous_by_FIELD', '_get_next_or_previous_in_order', '_get_pk_val', '_get_unique_checks', '_meta', '_perform_date_checks', '_perform_unique_checks', '_save_parents', '_save_table', '_set_pk_val', '_state', 
    'check', 'clean', 'clean_fields', 'date_error_message', 
    'delete', 
    'from_db', 'full_clean', 
    'get_deferred_fields', 'get_next_by_pub_date', 'get_previous_by_pub_date', 
    'headline', 
    'id', 'objects', 'pk', 
    'prepare_database_save', 
    'pub_date', 
    'refresh_from_db', 
    'reporter', 'reporter_id', 
    'save', 'save_base', 
    'serializable_value', 'unique_error_message', 'validate_unique']
    >>> 

    3.filter:リレーショナルマネージャのフィールド入力

  • の二重下線で関係を区切ります!
  • 深さは無限大!!
  • >>> r1
    <Reporter: John Smith>
    >>> r1.article_set.filter(headline__startswith='This')
    <QuerySet [<Article: This is a test>]>
    >>> 

    3-1. exact match

    >>> Article.objects.filter(reporter__first_name='John')
    <QuerySet [<Article: John's second story>, <Article: This is a test>]>
    >>> 

    3-2. WHERE節におけるAND条件

    >>> Article.objects.filter(reporter__first_name='John', reporter__last_name='Smith')
    <QuerySet [<Article: John's second story>, <Article: This is a test>]>
    >>> 

    3-3. pkまたはリレーショナルオブジェクトとして表示

    >>> Article.objects.filter(reporter__pk=1)
    <QuerySet [<Article: John's second story>, <Article: This is a test>]>
    >>> 
    >>> Article.objects.filter(reporter=1)
    <QuerySet [<Article: John's second story>, <Article: This is a test>]>
    >>> 
    >>> Article.objects.filter(reporter=r1)
    <QuerySet [<Article: John's second story>, <Article: This is a test>]>
    >>> r1
    <Reporter: John Smith>
    >>> 
    >>> Article.objects.filter(reporter__in=[1,2]).distinct()
    <QuerySet [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]>
    >>> 
    >>> r1,r2
    (<Reporter: John Smith>, <Reporter: Paul Jones>)
    >>> 
    >>> Article.objects.filter(reporter__in=[r1,r2]).distinct()
    <QuerySet [<Article: John's second story>, <Article: Paul's story>, <Article: This is a test>]>
    >>>
    >>> Article.objects.filter(reporter__in=Reporter.objects.filter(first_name='John')).distinct()
    <QuerySet [<Article: John's second story>, <Article: This is a test>]>
    >>> 

    3-4. 逆クエリー

    >>> Reporter.ojbects.filter(article__pk=1)
    Traceback (most recent call last):
      File "<console>", line 1, in <module>
    AttributeError: type object 'Reporter' has no attribute 'ojbects'
    >>> 
    >>> 
    >>> Reporter.objects.filter(article__pk=1)
    <QuerySet [<Reporter: John Smith>]>
    >>> Reporter.objects.filter(article=1)
    <QuerySet [<Reporter: John Smith>]>
    >>> Reporter.objects.filter(article=a1)
    <QuerySet [<Reporter: John Smith>]>
    >>> Reporter.objects.filter(article__headline__startswith='This')
    <QuerySet [<Reporter: John Smith>]>
    >>> Reporter.objects.filter(article__headline__startswith='This').distinct()
    <QuerySet [<Reporter: John Smith>]>
    >>> Reporter.objects.filter(article__headline__startswith='This').count()
    1
    >>> Reporter.objects.filter(article__headline__startswith='This').distinct().count()
    1
    >>> 

    3-4. queries can go round in circles

    >>> Reporter.objects.filter(article__reporter__first_name__startswith='John')
    <QuerySet [<Reporter: John Smith>, <Reporter: John Smith>]>
    >>> Reporter.objects.filter(article__reporter__first_name__startswith='John').distinct()
    <QuerySet [<Reporter: John Smith>]>
    >>> Reporter.objects.filter(article__reporter=r1).distinct()
    <QuerySet [<Reporter: John Smith>]>
    >>> r1
    <Reporter: John Smith>
    >>> 

    3-5. JOINによる削除

    >>> Reporter.objects.filter(article__headline__startswith='This')
    <QuerySet [<Reporter: John Smith>]>
    >>> 
    >>> Reporter.objects.filter(article__headline__startswith='This').delete()
    (3, {'practice.Article': 2, 'practice.Reporter': 1})
    >>> 
    >>> Reporter.objects.filter(article__headline__startswith='This')
    <QuerySet []>
    >>> 

    参考にする。


    ピザと具はM:N関係


    ピザモデルにManyToManyFiledプロパティを追加できます.
    または、属性ManyToManyFiledをマッピングに追加します.
    ピザとトッピングテーブルの関係を表現すればいい!
    でも、将来「form」を使うなら!
    ピザとトッピングの方がナチュラルなので!
    ピザにManyToManyField属性を乗せて、Toppingに接続したほうがいいです!

    作成した物理テーブルの下に示すように

    私=M:Nなら

    class HappyPerson(models.Model):
        friends = models.ManyToManyField("self")
    CREATE TABLE "practice_happyperson" (
    "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT
    )
    
    CREATE TABLE "practice_happyperson_friends" (
    "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT, 
    "from_happyperson_id" integer NOT NULL REFERENCES 
    "practice_happyperson" ("id") DEFERRABLE INITIALLY DEFERRED, 
    "to_happyperson_id" integer NOT NULL REFERENCES 
    "practice_happyperson" ("id") DEFERRABLE INITIALLY DEFERRED
    )

    Reference

  • https://docs.djangoproject.com/en/3.1/topics/db/models/#many-to-one-relationships
  • https://docs.djangoproject.com/en/3.1/ref/models/fields/#manytomanyfield
  • https://docs.djangoproject.com/en/3.1/ref/models/relations/#related-objects-reference