

ํ์ฑ๋ ๊ด๊ณ์ ์ํด์
๊ด๊ณ๋ฅผ ๋งบ์ ํ
์ด๋ธ์ ์ ๊ทผ์ด ๊ฐ๋ฅํด์ง!
Reporter : Article = 1 : M

>>> 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']
>>> 
>>> 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']
>>> 

>>> 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']
>>> 
>>> r1
<Reporter: John Smith>
>>> r1.article_set.filter(headline__startswith='This')
<QuerySet [<Article: This is a test>]>
>>> 
>>> Article.objects.filter(reporter__first_name='John')
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
>>> 
>>> Article.objects.filter(reporter__first_name='John', reporter__last_name='Smith')
<QuerySet [<Article: John's second story>, <Article: This is a test>]>
>>> 
>>> 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>]>
>>> 
>>> 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
>>> 
>>> 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>
>>> 
>>> 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 []>
>>> 
ํผ์ ๋ชจ๋ธ์๋ค๊ฐ ManyToManyField์ธ ์์ฑ์ ๋ฃ์ด๋ ๋๊ณ 
์๋๋ฉด, ํ ํ์๋ค๊ฐ ManyToManyField์ธ ์์ฑ์ ๋ฃ์ด์
ํผ์์ ํ ํ ํ
์ด๋ธ ์ฌ์ด์ ๊ด๊ณ๋ฅผ ๋ํ๋ด๋ฉด ๋๋ค!
๊ทธ๋ฌ๋, ์ฅ๊ณ ์ "form"์ ์ด์ฉํ๋ค๋ฉด!
ํผ์๋ฅผ ์ ํํ๊ณ  ํ ํ์ ์ ํํ๋ ๊ฒ์ด ๋ ์์ฐ์ค๋ฝ๊ธฐ์!
ํผ์์๋ค๊ฐ ManyToManyField ์์ฑ์ ๋ฃ์ด์ ํ ํ์ ์ฐ๊ฒฐํด์ฃผ๋ ๊ฒ์ด ๋ ์ข์ผ๋น!

์์ฑ๋ ๋ฌผ๋ฆฌํ ์ด๋ธ ์๋์ ๊ฐ๋น

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
)