diff --git a/README.md b/README.md index 63edae4..0a5ee25 100644 --- a/README.md +++ b/README.md @@ -1,207 +1,213 @@ -### Django ORM cookbook - - -Django ORM cookbook is a set of recipes of how to do things with Django. -They take the form of about 50 questions of the form -`How to do X with Django ORM/Queryset`. - -We have a set of models which we use across the book for answering these questions. - -### The models - -You plan to write a set of models and an assoicated admin for UMSRA researchers. You come up with two apps `entities` and `events`. The models are - - -#### Events - - - from django.db import models - from django.utils.text import slugify - from entities.models import Hero, Villain - from django.contrib.auth.models import User - import uuid - - class Epic(models.Model): - name = models.CharField(max_length=255) - participating_heroes = models.ManyToManyField(Hero) - participating_villains = models.ManyToManyField(Villain) - - - class Event(models.Model): - id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) - epic = models.ForeignKey(Epic, on_delete=models.CASCADE) - details = models.TextField() - years_ago = models.PositiveIntegerField() - - - class EventHero(models.Model): - event = models.ForeignKey(Event, on_delete=models.CASCADE) - hero = models.ForeignKey(Hero, on_delete=models.CASCADE) - is_primary = models.BooleanField() - - - class EventVillain(models.Model): - event = models.ForeignKey(Event, on_delete=models.CASCADE) - hero = models.ForeignKey(Villain, on_delete=models.CASCADE) - is_primary = models.BooleanField() - - - class UserParent(models.Model): - user = models.OneToOneField( - User, - on_delete=models.CASCADE, - primary_key=True, - ) - father_name = models.CharField(max_length=100) - mother_name = models.CharField(max_length=100) - - class Article(models.Model): - headline = models.CharField(max_length=100) - pub_date = models.DateField() - reporter = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reporter') - slug = models.SlugField() - - def save(self, *args, **kwargs): - self.slug = slugify(self.headline) - super(Article, self).save(*args, **kwargs) - def __str__(self): - return self.headline - - class Meta: - ordering = ('headline',) - - class TempUser(models.Model): - first_name = models.CharField(max_length=100) - - class Meta: - managed = False - db_table = "temp_user" - - - class ColumnName(models.Model): - a = models.CharField(max_length=40,db_column='column1') - column2 = models.CharField(max_length=50) - - def __str__(self): - return self.a - - -#### Entities - - from django.db import models - - from django.conf import settings - - - class Category(models.Model): - name = models.CharField(max_length=100) - - class Meta: - verbose_name_plural = "Categories" - - def __str__(self): - return self.name - - - class Origin(models.Model): - name = models.CharField(max_length=100) - - def __str__(self): - return self.name - - - class Entity(models.Model): - GENDER_MALE = "Male" - GENDER_FEMALE = "Female" - GENDER_OTHERS = "Others/Unknown" - - name = models.CharField(max_length=100) - alternative_name = models.CharField( - max_length=100, null=True, blank=True - ) - - - category = models.ForeignKey(Category, on_delete=models.CASCADE) - origin = models.ForeignKey(Origin, on_delete=models.CASCADE) - gender = models.CharField( - max_length=100, - choices=( - (GENDER_MALE, GENDER_MALE), - (GENDER_FEMALE, GENDER_FEMALE), - (GENDER_OTHERS, GENDER_OTHERS), - ) - ) - description = models.TextField() - - added_by = models.ForeignKey(settings.AUTH_USER_MODEL, - null=True, blank=True, on_delete=models.SET_NULL) - added_on = models.DateField(auto_now=True) - - def __str__(self): - return self.name - - class Meta: - abstract = True - - - class Hero(Entity): - - class Meta: - verbose_name_plural = "Heroes" - - is_immortal = models.BooleanField(default=True) - - benevolence_factor = models.PositiveSmallIntegerField( - help_text="How benevolent this hero is?" - ) - arbitrariness_factor = models.PositiveSmallIntegerField( - help_text="How arbitrary this hero is?" - ) - - headshot = models.ImageField(null=True, blank=True, upload_to="hero_headshots/") - - # relationships - father = models.ForeignKey( - "self", related_name="children", null=True, blank=True, on_delete=models.SET_NULL - ) - mother = models.ForeignKey( - "self", related_name="+", null=True, blank=True, on_delete=models.SET_NULL - ) - spouse = models.ForeignKey( - "self", related_name="+", null=True, blank=True, on_delete=models.SET_NULL - ) - - - class HeroProxy(Hero): - - class Meta: - proxy = True - - class Villain(Entity): - is_immortal = models.BooleanField(default=False) - - malevolence_factor = models.PositiveSmallIntegerField( - help_text="How malevolent this villain is?" - ) - power_factor = models.PositiveSmallIntegerField( - help_text="How powerful this villain is?" +### 장고 ORM 요리책 + +(렌더링 된 문서: https://django-orm-cookbook-ko.readthedocs.io/en/latest/) + + +장고 ORM 요리책은 장고를 이용한 다양한 레시피(조리법)를 담은 책입니다. `장고 ORM/쿼리셋으로 ~을 하려면 어떻게 하나요?` 하는 50여 개의 질문과 답을 담고 있습니다. + +이 책에서는 전체 주제 공통으로 아래에서 설명하는 데이터 모델을 이용합니다. + + +### 실습용 모델 준비 + +여러분은 장고를 이용하여 UMSRA의 연구원들이 사용할 모델과 관리자 뷰(admin)를 제작하는 중입니다. 여러분은 프로젝트를 개체를 나타내는 `entities` 앱과 사건을 나타내는 `events` 앱 두 개로 나누어 작성하게 되었습니다. 그리고 각 앱의 모델을 다음과 같이 준비했습니다. (지금 자세히 보지 않아도 됩니다. 책을 보다가 필요할 때 참고해주세요.) + + +#### Events 앱의 모델 + +```python +from django.db import models +from django.utils.text import slugify +from entities.models import Hero, Villain +from django.contrib.auth.models import User +import uuid + + +class Epic(models.Model): + name = models.CharField(max_length=255) + participating_heroes = models.ManyToManyField(Hero) + participating_villains = models.ManyToManyField(Villain) + + +class Event(models.Model): + id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) + epic = models.ForeignKey(Epic, on_delete=models.CASCADE) + details = models.TextField() + years_ago = models.PositiveIntegerField() + + +class EventHero(models.Model): + event = models.ForeignKey(Event, on_delete=models.CASCADE) + hero = models.ForeignKey(Hero, on_delete=models.CASCADE) + is_primary = models.BooleanField() + + +class EventVillain(models.Model): + event = models.ForeignKey(Event, on_delete=models.CASCADE) + hero = models.ForeignKey(Villain, on_delete=models.CASCADE) + is_primary = models.BooleanField() + + +class UserParent(models.Model): + user = models.OneToOneField( + User, + on_delete=models.CASCADE, + primary_key=True, + ) + father_name = models.CharField(max_length=100) + mother_name = models.CharField(max_length=100) + + +class Article(models.Model): + headline = models.CharField(max_length=100) + pub_date = models.DateField() + reporter = models.ForeignKey(User, on_delete=models.CASCADE, related_name='reporter') + slug = models.SlugField() + + def save(self, *args, **kwargs): + self.slug = slugify(self.headline) + super(Article, self).save(*args, **kwargs) + def __str__(self): + return self.headline + + class Meta: + ordering = ('headline',) + + +class TempUser(models.Model): + first_name = models.CharField(max_length=100) + + class Meta: + managed = False + db_table = "temp_user" + + +class ColumnName(models.Model): + a = models.CharField(max_length=40,db_column='column1') + column2 = models.CharField(max_length=50) + + def __str__(self): + return self.a +``` + +#### Entities 앱의 모델 + +```python +from django.db import models + +from django.conf import settings + + +class Category(models.Model): + name = models.CharField(max_length=100) + + class Meta: + verbose_name_plural = "Categories" + + def __str__(self): + return self.name + + +class Origin(models.Model): + name = models.CharField(max_length=100) + + def __str__(self): + return self.name + + +class Entity(models.Model): + GENDER_MALE = "Male" + GENDER_FEMALE = "Female" + GENDER_OTHERS = "Others/Unknown" + + name = models.CharField(max_length=100) + alternative_name = models.CharField( + max_length=100, null=True, blank=True + ) + + category = models.ForeignKey(Category, on_delete=models.CASCADE) + origin = models.ForeignKey(Origin, on_delete=models.CASCADE) + gender = models.CharField( + max_length=100, + choices=( + (GENDER_MALE, GENDER_MALE), + (GENDER_FEMALE, GENDER_FEMALE), + (GENDER_OTHERS, GENDER_OTHERS), ) - is_unique = models.BooleanField(default=True) - count = models.PositiveSmallIntegerField(default=1) - - - class HeroAcquaintance(models.Model): - "Non family contacts of a Hero" - hero = models.OneToOneField(Hero, on_delete=models.CASCADE) - - friends = models.ManyToManyField(Hero, related_name="+") - detractors = models.ManyToManyField(Hero, related_name="+") - main_anatagonists = models.ManyToManyField(Villain, related_name="+") - - - class AllEntity(models.Model): - name = models.CharField(max_length=100) - - class Meta: - managed = False - db_table = "entities_entity" + ) + description = models.TextField() + + added_by = models.ForeignKey(settings.AUTH_USER_MODEL, + null=True, blank=True, on_delete=models.SET_NULL) + added_on = models.DateField(auto_now=True) + + def __str__(self): + return self.name + + class Meta: + abstract = True + + +class Hero(Entity): + + class Meta: + verbose_name_plural = "Heroes" + + is_immortal = models.BooleanField(default=True) + + benevolence_factor = models.PositiveSmallIntegerField( + help_text="How benevolent this hero is?" + ) + arbitrariness_factor = models.PositiveSmallIntegerField( + help_text="How arbitrary this hero is?" + ) + + headshot = models.ImageField(null=True, blank=True, upload_to="hero_headshots/") + + # relationships + father = models.ForeignKey( + "self", related_name="children", null=True, blank=True, on_delete=models.SET_NULL + ) + mother = models.ForeignKey( + "self", related_name="+", null=True, blank=True, on_delete=models.SET_NULL + ) + spouse = models.ForeignKey( + "self", related_name="+", null=True, blank=True, on_delete=models.SET_NULL + ) + + +class HeroProxy(Hero): + + class Meta: + proxy = True + + +class Villain(Entity): + is_immortal = models.BooleanField(default=False) + + malevolence_factor = models.PositiveSmallIntegerField( + help_text="How malevolent this villain is?" + ) + power_factor = models.PositiveSmallIntegerField( + help_text="How powerful this villain is?" + ) + is_unique = models.BooleanField(default=True) + count = models.PositiveSmallIntegerField(default=1) + + +class HeroAcquaintance(models.Model): + "Non family contacts of a Hero" + hero = models.OneToOneField(Hero, on_delete=models.CASCADE) + + friends = models.ManyToManyField(Hero, related_name="+") + detractors = models.ManyToManyField(Hero, related_name="+") + main_anatagonists = models.ManyToManyField(Villain, related_name="+") + + +class AllEntity(models.Model): + name = models.CharField(max_length=100) + + class Meta: + managed = False + db_table = "entities_entity" +``` diff --git a/docs/aggregation.rst b/docs/aggregation.rst index 51b5232..fbe3f07 100644 --- a/docs/aggregation.rst +++ b/docs/aggregation.rst @@ -1,7 +1,7 @@ -How to group records in Django ORM? -======================================== +기록된 항목의 집계를 구할 수 있나요? +================================================================== -Grouping of records in Django ORM can be done using aggregation functions like :code:`Max`, :code:`Min`, :code:`Avg`, :code:`Sum`. Django queries help to create, retrieve, update and delete objects. But sometimes we need to get aggregated values from the objects. We can get them by example shown below :: +장고 ORM을 이용해 항목을 생성·조회·갱신·삭제할 수 있지만, 때로는 항목들의 집계값을 구하고 싶을 때가 있습니다. 장고 ORM에는 SQL의 일반적인 집계 기능을 수행하는 :code:`Max`, :code:`Min`, :code:`Avg`, :code:`Sum` 등의 함수가 있습니다. 다음은 이 집계 함수를 이용하는 예입니다. :: >>> from django.db.models import Avg, Max, Min, Sum, Count >>> User.objects.all().aggregate(Avg('id')) diff --git a/docs/and_query.rst b/docs/and_query.rst index f597b50..63ccdf4 100644 --- a/docs/and_query.rst +++ b/docs/and_query.rst @@ -1,35 +1,29 @@ -How to do AND queries in Django ORM? -++++++++++++++++++++++++++++++++++++++++++++++++++ +AND 연산으로 여러 조건을 모두 만족하는 항목을 구하려면 어떻게 하나요? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: usertable.png -If you are using :code:`django.contrib.auth`, you will have a table called :code:`auth_user`. It will have fields as :code:`username`, :code:`first_name`, :code:`last_name` and more. +장고의 사용자 계정 관리 앱인 :code:`django.contrib.auth` 를 사용하면 데이터베이스에 :code:`auth_user` 라는 표가 생성됩니다. 이 표에는 :code:`username`, :code:`first_name`, :code:`last_name` 등의 열이 있습니다. +:code:`AND` 연산으로 여러 조건을 모두 만족하는 행을 구해야 하는 경우가 많습니다. 이름이 'R'로 시작하고 성이 'D'로 시작하는 모든 사용자를 구한다고 해 봅시다. -You would frequently need to want to perform AND operation, to find querysets which match multiple criteria. - -Say you want to find users with :code:`firstname` starting with 'R' AND :code:`last_name` starting with 'D'. - -Django provides three options. +장고에서는 다음 세 방법으로 구할 수 있습니다. - :code:`filter(, )` - :code:`queryset_1 & queryset_2` - :code:`filter(Q() & Q())` -The query in detail +질의문 살펴보기 ----------------------- - -Our SQL query for the above condition will look something like - -.. code-block:: sql +위 조건의 SQL 질의문은 다음과 같이 생성됩니다. :: SELECT username, first_name, last_name, email FROM auth_user WHERE first_name LIKE 'R%' AND last_name LIKE 'D%'; .. image:: sqluser_result2.png -The default way to combine multiple conditions in :code:`filter` is :code:`AND`, so you can just do. +장고 쿼리셋의 :code:`filter` 메서드에서 여러 조건을 결합하는 방법은 기본적으로 :code:`AND` 방식입니다. 따라서 다음과 같이 조건을 그냥 나열하면 됩니다. .. code-block:: python @@ -38,7 +32,7 @@ The default way to combine multiple conditions in :code:`filter` is :code:`AND`, last_name__startswith='D' ) -Alternatively, you can explicitly use the `&` operator on querysets. +하지만 `&` 연산자를 사용하여 쿼리셋을 명시적으로 결합할 수도 있습니다. .. code-block:: python @@ -48,7 +42,7 @@ Alternatively, you can explicitly use the `&` operator on querysets. last_name__startswith='D' ) -For complete customisability, you can use the :code:`Q` objects. +복잡한 질의를 수행할 수 있도록 도와주는 :code:`Q` 객체를 이용하여 조건을 명시해도 됩니다. .. code-block:: python @@ -61,7 +55,7 @@ For complete customisability, you can use the :code:`Q` objects. queryset_1 , , ]> -You can look at the generated query and verify that they are all same. +언제나 실제로 생성되는 SQL 질의문을 확인하여 검증하는 것이 도움이 됩니다. .. code-block:: ipython diff --git a/docs/asc_or_desc.rst b/docs/asc_or_desc.rst index e861ee4..f2738fc 100644 --- a/docs/asc_or_desc.rst +++ b/docs/asc_or_desc.rst @@ -1,24 +1,22 @@ -How to order a queryset in ascending or descending order? -============================================================= +쿼리셋을 오름차순/내림차순으로 정렬할 수 있나요? +====================================================================== -Ordering of the queryset can be achieved by :code:`order_by` method. We need to pass the field on which we need to Order (ascending/descending) the result. -Query looks like this +:code:`order_by` 메서드로 쿼리셋을 정렬할 수 있습니다. 기준 필드를 지정해 오름차순 혹은 내림차순으로 정렬할 수 있습니다. 다음 코드를 살펴보세요. .. code-block:: ipython - >>> User.objects.all().order_by('date_joined') # For ascending + >>> User.objects.all().order_by('date_joined') # 오름차순 , , , , , , , , , , , , ]> - >>> User.objects.all().order_by('-date_joined') # For descending; Not '-' sign in order_by method + >>> User.objects.all().order_by('-date_joined') # 내림차순 , , , , , , , , , , , , ]> -You can pass multiple fields to :code:`order_by` +기준 필드를 여러 개 지정할 수도 있습니다. .. code-block:: ipython User.objects.all().order_by('date_joined', '-last_login') -Looking at the SQL - +SQL 질의문은 다음과 같습니다. .. code-block:: sql diff --git a/docs/case_insensitive.rst b/docs/case_insensitive.rst index d28eb06..ee1b0b0 100644 --- a/docs/case_insensitive.rst +++ b/docs/case_insensitive.rst @@ -1,16 +1,16 @@ -How to order a queryset in case insensitive manner? +대문자·소문자를 구별하지 않고 정렬하려면 어떻게 하나요? ============================================================ .. image:: usertable2.png -Whenever we try to do :code:`order_by` with some string value, the ordering happens alphabetically and w.r.t case. Like +:code:`order_by` 메서드로 쿼리셋을 정렬할 때, 텍스트 필드를 기준으로 하면 알파벳의 대문자·소문자를 구분하여 정렬이 수행됩니다. 다음 예에서 보듯, 대문자에 소문자보다 높은 우선순위가 부여됩니다. .. code-block:: ipython >>> User.objects.all().order_by('username').values_list('username', flat=True) -If we want to order queryset in case insensitive manner, we can do like this . :: +텍스트 필드에서 대문자·소문자를 구별하지 않고 정렬하려면 다음과 같이 :code:`Lower` 를 사용하면 됩니다. .. code-block:: ipython @@ -18,10 +18,10 @@ If we want to order queryset in case insensitive manner, we can do like this . : >>> User.objects.all().order_by(Lower('username')).values_list('username', flat=True) -Alternatively, you can annotate with :code:`Lower` and then order on annotated field. +:code:`annotate` 메서드로 :code:`Lower` 를 적용한 열을 준비하고, 그 열을 기준으로 정렬하는 방법도 가능합니다. .. code-block:: python User.objects.annotate( - uname=Lower('username') - ).order_by('uname').values_list('username', flat=True) + lower_name=Lower('username') + ).order_by('lower_name').values_list('username', flat=True) diff --git a/docs/column_name.rst b/docs/column_name.rst index b2bf19c..d267cc7 100644 --- a/docs/column_name.rst +++ b/docs/column_name.rst @@ -1,7 +1,7 @@ -How to specify the column name for model field? -===================================================== +모델 필드의 데이터베이스 열 이름을 지정할 수 있나요? +============================================================================= -Naming of a column in the model can be achieved py passing a :code:`db_column` parameter with some name. If we don't pass this parameter django creates a column with the field name which we give. :: +모델 필드가 가리키는 데이터베이스의 열 이름을 지정하려면 필드 인스턴스의 초기화 매개변수 :code:`db_column` 에 원하는 이름을 전달하면 됩니다. 이 매개변수에 인자를 전달하지 않으면 필드 이름과 동일한 이름이 사용됩니다. :: class ColumnName(models.Model): a = models.CharField(max_length=40,db_column='column1') @@ -12,4 +12,4 @@ Naming of a column in the model can be achieved py passing a :code:`db_column` p .. image:: db_column.png -Above we can :code:`db_column` has higher priority over :code:`field name`. First column is named as column1 but not as a. +위 예에서 보듯, :code:`db_column` 으로 지정한 이름이 필드 이름보다 우선순위가 높습니다. 첫 번째 열의 이름이 a가 아니라 column1로 지어졌습니다. diff --git a/docs/conf.py b/docs/conf.py index e8005df..d3ec77b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -134,14 +134,15 @@ # Latex figure (float) alignment # # 'figure_align': 'htbp', + 'extraclassoptions': 'openany,oneside' } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'DjangoORMCookbook.tex', 'Django ORM Cookbook Documentation', - 'Agiliq', 'manual'), + (master_doc, 'DjangoORMCookbook.tex', '장고 ORM 요리책', + 'Agiliq/8퍼센트', 'manual'), ] diff --git a/docs/copy.rst b/docs/copy.rst index f643c06..a3bbfbf 100644 --- a/docs/copy.rst +++ b/docs/copy.rst @@ -1,9 +1,9 @@ -How to copy or clone an existing model object? +기존에 저장된 행을 복사해 새로 저장하는 방법은 무엇인가요? ======================================================================== -There is no built-in method for copying model instances, it is possible to create new instance with all fields values copied. +장고 ORM에는 모델 인스턴스를 복사하는 내장 메서드가 없습니다. 하지만 모든 필드의 값을 복사하여 새 인스턴스를 만들고 새로 저장하는 것은 어렵지 않습니다. -If an instance is saved with instance's :code:`pk` set to :code:`None`, the instance is used to create a new record in the DB. That means every field other than the :code:`PK` is copied. +모델 인스턴스를 저장할 때, :code:`pk` 필드 값이 :code:`None` 으로 지정되어 있으면 데이터베이스에 새 행으로 저장됩니다. :code:`pk` 외의 모든 필드 값은 그대로 복제됩니다. .. code-block:: ipython diff --git a/docs/database_view.rst b/docs/database_view.rst index 10423fe..a62977d 100644 --- a/docs/database_view.rst +++ b/docs/database_view.rst @@ -1,22 +1,25 @@ -How to add a model for a database view? -=============================================== +데이터베이스 뷰에 대응하는 모델을 정의할 수 있나요? +========================================================================== -A database view is a searchable object in a database that is defined by a query. Though a view doesn’t store data, some refer to a views as “virtual tables,” you can query a view like you can a table. A view can combine data from two or more table, using joins, and also just contain a subset of information. This makes them convenient to abstract, or hide, complicated queries. +데이터베이스 뷰는 데이터베이스 내에서 조회할 수 있도록 질의문으로 정의된 객체입니다. 뷰가 데이터를 물리적으로 저장하는 것은 아니지만, 실제 표와 같이 조회할 수 있기 때문에 '가상 표'라고 불리기도 합니다. 뷰는 여러 표를 결합(JOIN)한 정보를 보여줄 수도 있고, 한 표의 부분 집합만을 보여줄 수도 있습니다. 이를 활용하면 복잡한 질의문을 감추고 필요한 정보를 쉽게 조회하는 인터페이스를 만들 수 있습니다. -In our SqliteStuio we can see 26 tables and no views. +다음 스크린샷은 데이터베이스를 SQLiteStudio라는 프로그램으로 열어 본 모습입니다. 표가 26개 있고, 뷰는 없습니다. .. image:: before_view.png -Lets create a simple view. :: +SQL 질의문을 실행하여 간단한 뷰를 생성하겠습니다. - create view temp_user as - select id, first_name from auth_user; +.. code-block:: sql -After the view is created, we can see 26 tables and 1 view. + create view temp_user as + select id, first_name + from auth_user; + +뷰가 생성되어 표 26개와 뷰 1개가 있습니다. .. image:: after_view.png -We can create its related model in our app, by :code:`managed = False` and :code:`db_table="temp_user"` :: +장고 앱에서는 모델을 정의할 때 메타(:code:`Meta`) 클래스에 :code:`managed = False`, :code:`db_table="temp_user"` 와 같이 옵션을 설정하여 뷰를 가리키는 모델로 사용할 수 있습니다. :: class TempUser(models.Model): first_name = models.CharField(max_length=100) @@ -25,14 +28,16 @@ We can create its related model in our app, by :code:`managed = False` and :code managed = False db_table = "temp_user" - // We can query the newly created view similar to what we do for any table. + >>> # 실제 표와 마찬가지로 뷰를 조회할 수 있습니다. >>> TempUser.objects.all().values() - // You cannot insert new reord in a view. + >>> # 그러나 뷰에 기록은 하지 못합니다. >>> TempUser.objects.create(first_name='Radhika', id=15) Traceback (most recent call last): ... django.db.utils.OperationalError: cannot modify temp_user because it is a view -For view having union operation refer to : +union 연산이 있는 뷰는 아래 주소의 문서(Django Admin Cookbook)를 참고하세요. + http://books.agiliq.com/projects/django-admin-cookbook/en/latest/database_view.html?highlight=view + diff --git a/docs/datetime.rst b/docs/datetime.rst index fb291fc..7ed8d9b 100644 --- a/docs/datetime.rst +++ b/docs/datetime.rst @@ -1,8 +1,9 @@ -How to convert string to datetime and store in database? -============================================================ +시간 정보를 다른 양식으로 변환하여 데이터베이스에 저장하려면 어떻게 해야 하나요? +============================================================================================= -We can convert a date-string and store it in the database using django in many ways. Few of them are discussed below. -Lets say we have a date-string as "2018-03-11" we can not directly store it to our date field, so we can use some dateparser or python library for it. :: +장고에서 시간을 나타내는 텍스트를 다른 양식의 텍스트로 변환하여 데이터베이스에 저장하는 방법은 여러 가지가 있습니다. 몇 가지만 소개하겠습니다. + +"2018-03-11"이라는 시간 텍스트가 있는데, 이 양식으로는 데이터베이스에 저장할 수 없다고 가정합시다. 아래와 같이 장고의 dateparser 모듈이나 파이썬 표준 라이브러리를 이용하여 날짜 양식을 변환할 수 있습니다. :: >>> user = User.objects.get(id=1) >>> date_str = "2018-03-11" diff --git a/docs/distinct.rst b/docs/distinct.rst index 7d339b1..8a73f93 100644 --- a/docs/distinct.rst +++ b/docs/distinct.rst @@ -1,9 +1,9 @@ -How to find distinct field values from queryset? +쿼리셋에서 고유한 필드 값을 가진 항목은 어떻게 구하나요? ======================================================================== .. image:: usertable2.png -You want to find users whose names have not been repeated. You can do this like this +이름이 다른 사용자와 겹치지 않은 사용자를 찾는다고 합시다. 다음과 같이 구할 수 있습니다. .. code-block:: python @@ -14,6 +14,5 @@ You want to find users whose names have not been repeated. You can do this like ).filter(name_count=1) records = User.objects.filter(first_name__in=[item['first_name'] for item in distinct]) -This is different from :code:`User.objects.distinct("first_name").all()`, which will pull up the first record when it encounters a distinct :code:`first_name`. - +한편, :code:`User.objects.distinct("first_name").all()` 와 같은 코드는 고유한 :code:`first_name` 을 가진 사용자별로 첫번째 사용자를 구하는 코드입니다. 위 코드와는 실행 결과가 다릅니다. diff --git a/docs/duplicate.rst b/docs/duplicate.rst index 30575c3..5cc3f61 100644 --- a/docs/duplicate.rst +++ b/docs/duplicate.rst @@ -1,11 +1,9 @@ -Find rows which have duplicate field values -============================================== +특정 열의 값이 동일한 항목은 어떻게 찾나요? +========================================================== .. image:: usertable2.png -Say you want all users whose :code:`first_name` matches another user. - -You can find duplicate records using the technique below. +:code:`first_name` 이 서로 동일한 사용자들을 구한다고 합시다. 특정 열에서 중복된 값을 찾을 때는 아래와 같이 :code:`Count` 를 구한 뒤 중복 수를 기준으로 골라내면 됩니다. .. code-block:: python @@ -15,7 +13,8 @@ You can find duplicate records using the technique below. >>> duplicates -If you need to fill all the records, you can do +위와 같이 중복 값을 구했으면, 이 값을 가진 항목을 아래와 같이 구할 수 있습니다. + .. code-block:: python diff --git a/docs/existing_database.rst b/docs/existing_database.rst index 88ff10d..566d2b9 100644 --- a/docs/existing_database.rst +++ b/docs/existing_database.rst @@ -1,12 +1,12 @@ -How to convert existing databases to Django models? -===================================================== +기존 데이터베이스를 장고 모델로 옮길 수 있나요? +================================================================================ -Django comes with a utility called :code:`inspectdb` that can create models by introspecting an existing database. You can view the output by running this command :: +장고에는 기존 데이터베이스를 분석하여 그에 맞는 모델을 생성해주는 :code:`inspectdb` 명령이 있습니다. 셸에서 다음 명령을 실행하여 결과를 확인할 수 있습니다. :: $ python manage.py inspectdb -Befor running this you will have to configure your database in the :code:`settings.py` file. The result will be a file containing a model for each table. You may want to save that file :: +이 명령을 실행하려면 먼저 :code:`settings.py` 파일에 분석하려는 데이터베이스의 접속 정보를 설정해 두어야 합니다. 출력 결과는 생성된 모델의 파이썬 코드입니다. 코드를 파이썬 모듈 파일로 저장하려면 다음과 같이 셸의 스트림 리디렉션 기능을 이용합니다. :: $ python manage.py inspectdb > models.py -The output file will be saved to your current directory. Move that file to the correct app and you have a good starting point for further customizations. +위 명령을 실행하면 분석된 모델이 파이썬 모듈 파일로 현재 디렉토리에 저장될 것입니다. 이 파일을 앱의 올바른 위치로 옮긴 뒤, 적절히 수정하여 사용하면 됩니다. diff --git a/docs/f_query.rst b/docs/f_query.rst index fae9eca..fa8057d 100644 --- a/docs/f_query.rst +++ b/docs/f_query.rst @@ -1,12 +1,12 @@ -How to filter a queryset with criteria based on comparing their field values +필드의 값을 서로 비교하여 항목을 선택할 수 있나요? ============================================================================== -Django ORM makes it easy to filter based on fixed values. -To get all :code:`User` objects with :code:`first_name` starting with :code:`'R'`, -you can do :code:`User.objects.filter(first_name__startswith='R')`. +장고 ORM에서 필드를 고정 값과 비교하여 항목을 선택하는 것은 간단합니다. 예를 들어, 이름(:code:`first_name`) 이 :code:`'R'` 로 시작하는 :code:`User` 모델의 행을 구하려면 +:code:`User.objects.filter(first_name__startswith='R')` 와 같이 코드를 작성하면 됩니다. -What if you want to compare the first_name and last name? -You can use the :code:`F` object. Create some users first. +그런데 필드와 필드를 서로 비교할 수도 있을까요? 예를 들어, 이름(:code:`first_name`) 을 성(:code:`last_name`) 과 비교하여 선택하는 것이죠. 이럴 때 :code:`F` 객체를 사용합니다. + +실습을 위해 :code:`User` 모델의 항목을 몇 개 생성합시다. .. code-block:: ipython @@ -16,16 +16,15 @@ You can use the :code:`F` object. Create some users first. In [28]: User.objects.create_user(email="guido@example.com", username="Guido", first_name="Guido", last_name="Guido") Out[28]: -Now you can find the users where :code:`first_name==last_name` +실습 데이터가 준비되었으면, 다음 코드로 이름과 성이 동일한 사용자를 구해 봅시다. + .. code-block:: ipython In [29]: User.objects.filter(last_name=F("first_name")) Out[29]: ]> -:code:`F` also works with calculated field using annotate. What if we wanted users whose first and last names have same letter? - -You can set the first letter from a string using :code:`Substr("first_name", 1, 1)`, so we do. +:code:`F` 객체는 annotate 메서드로 계산해 둔 필드를 가리킬 때도 사용할 수 있습니다. 예를 들어, 이름의 첫 글자와 성의 첫 글자가 동일한 사용자를 구하고 싶다면 :code:`Substr("first_name", 1, 1)` 를 사용할 수 있습니다. .. code-block:: ipython @@ -35,4 +34,5 @@ You can set the first letter from a string using :code:`Substr("first_name", 1, In [46]: User.objects.annotate(first=Substr("first_name", 1, 1), last=Substr("last_name", 1, 1)).filter(first=F("last")) Out[46]: , ]> -:code:`F` can also be used with :code:`__gt`, :code:`__lt` and other expressions. +:code:`F` 객체에 :code:`__gt`, :code:`__lt` 등의 룩업(lookup)을 적용하는 것 또한 가능합니다. + diff --git a/docs/filefield.rst b/docs/filefield.rst index b73dc17..3e4ad65 100644 --- a/docs/filefield.rst +++ b/docs/filefield.rst @@ -1,9 +1,7 @@ -How to filter FileField without any file? -++++++++++++++++++++++++++++++++++++++++++++++ +FileField에 파일이 들어있지 않은 행은 어떻게 구할 수 있나요? +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -A :code:`FileField` or :code:`ImageField` stores the path of the file or image. At the DB level they are same as a :code:`CharField`. - -So to find FileField without any file we can query as under. +장고의 :code:`FileField` 와 :code:`ImageField` 는 파일과 이미지 파일의 경로를 저장합니다. 이것은 응용 수준에서의 구별이고, 데이터베이스 수준에서는 모두 :code:`CharField` 와 동일한 방식으로 저장됩니다. 파일이 없는 행을 구하려면 다음 코드를 실행하면 됩니다. .. code-block:: python diff --git a/docs/func_expressions.rst b/docs/func_expressions.rst index dcf4ae0..e569114 100644 --- a/docs/func_expressions.rst +++ b/docs/func_expressions.rst @@ -1,14 +1,13 @@ -How to use arbitrary database functions in querysets? -======================================================================== +장고가 지원하지 않는 데이터베이스 함수를 사용할 수 있나요? +========================================================================== -Django comes with functions like :code:`Lower`, :code:`Coalesce` and :code:`Max`, but it can't support all database functions, expecially ones which are database specific. +장고에는 :code:`Lower`, :code:`Coalesce`, :code:`Max` 등의 데이터베이스 함수가 포함되어 있습니다. 하지만 장고가 데이터베이스가 지원하는 모든 함수를 제공하는 것은 아닙니다. 특히, 특정 데이터베이스 시스템의 전용 함수들은 제공되지 않습니다. -Django provides :code:`Func` which allows using arbitrary database functions, even if Django doesn't provide them. +장고가 제공하지 않는 데이터베이스 함수를 실행하기 위해서는 장고의 :code:`Func` 객체를 사용하면 됩니다. +PostgreSQL에는 :code:`fuzzystrmatch` 확장 기능이 있습니다. 이 확장에는 텍스트 데이터의 유사도를 측정하기 위한 함수가 여러 가지 포함되어 있습니다. PostgreSQL 데이터베이스 셸에서 :code:`create extension fuzzystrmatch` 를 실행하여 이 확장을 설치하고 아래의 실습을 진행해 주세요. -Postgres has :code:`fuzzystrmatch`, which provides several functions to determine similarities. Install the extension in your postgres DB with :code:`create extension fuzzystrmatch` - -We will use the :code:`levenshtein` function. Lets first create some Hero objects. +레벤슈타인 치환 거리 알고리즘을 구현한 :code:`levenshtein` 함수를 이용해 보겠습니다. 실습에 사용할 Hero 모델의 항목을 여러 개 생성합시다. .. code-block:: python @@ -18,7 +17,7 @@ We will use the :code:`levenshtein` function. Lets first create some Hero object Hero.objects.create(name="Xeus", description="A greek God", benevolence_factor=80, category_id=12, origin_id=1) Hero.objects.create(name="Poseidon", description="A greek God", benevolence_factor=80, category_id=12, origin_id=1) -We want to find out the :code:`Hero` objects which have :code:`name` similar to Zeus. You can do +이제 :code:`name` 이 'Zeus' 와 비슷한 :code:`Hero` 항목들을 구해 봅시다. .. code-block:: python @@ -26,7 +25,7 @@ We want to find out the :code:`Hero` objects which have :code:`name` similar to Hero.objects.annotate(like_zeus=Func(F('name'), function='levenshtein', template="%(function)s(%(expressions)s, 'Zeus')")) -The :code:`like_zeus=Func(F('name'), function='levenshtein', template="%(function)s(%(expressions)s, 'Zeus')")` took two arguments which allowed the database representation, viz, :code:`function` and :code:`template`. If you need to reuse the function, you can define a class like this. +:code:`like_zeus=Func(F('name'), function='levenshtein', template="%(function)s(%(expressions)s, 'Zeus')")` 코드에서 :code:`Func` 객체를 세 개의 인자로 초기화하였습니다. 첫 번째 인자는 함수에 적용할 열, 두 번째 인자는 데이터베이스에서 실행할 함수의 이름, 세 번째 인자는 함수를 실행할 SQL 질의문의 템플릿입니다. 이 함수를 여러 번 재사용할 계획이라면 다음과 같이 클래스를 확장하여 정의해 두면 편리합니다. .. code-block:: python @@ -34,9 +33,9 @@ The :code:`like_zeus=Func(F('name'), function='levenshtein', template="%(functio function='levenshtein' template="%(function)s(%(expressions)s, 'Zeus')" -And then use :code:`Hero.objects.annotate(like_zeus=LevenshteinLikeZeus(F("name")))` +이제 :code:`Hero.objects.annotate(like_zeus=LevenshteinLikeZeus(F("name")))` 와 같이 클래스를 이용할 수 있습니다. -You can then filter on this annotated field like this. +이렇게 구한 레벤슈타인 거리를 기준으로 이름이 비슷한 항목을 선별할 수 있습니다. .. code-block:: ipython diff --git a/docs/generic_models.rst b/docs/generic_models.rst index 8703e5b..612b481 100644 --- a/docs/generic_models.rst +++ b/docs/generic_models.rst @@ -1,8 +1,7 @@ -How to create a generic model which can be related to any kind of entity? (Eg. a Category or a Comment?) -============================================================================================================= +분류·댓글처럼 아무 모델이나 가리킬 수 있는 범용 모델을 정의할 수 있나요? +============================================================================================================ - -You have models like this. +다음 모델을 봐 주세요. .. code-block:: python @@ -26,13 +25,11 @@ You have models like this. # ... -:code:`Category` can be applied is a `generic` model. You prbably want to be able to apply categories to objects form any model class. -You can do it like this - +여기서 :code:`Category` 모델은 범용 모델로 고쳐 정의할 수 있습니다. 다른 모델에도 분류를 적용하고 싶을 테니까요. 다음과 같이 수정하면 됩니다. .. code-block:: python - from django.contrib.contenttypes.fields import GenericForeignKey + from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation from django.contrib.contenttypes.models import ContentType # ... @@ -54,12 +51,9 @@ You can do it like this flex_category = GenericRelation(FlexCategory, related_query_name='flex_category') # ... +수정한 코드에서는 :code:`FlexCategory` 모델에 외래 키 필드(:code:`ForeignKey`) 하나와 양의 정수 필드(:code:`PositiveIntegerField`) 하나를 정의하여 범용 외래 키 필드(:code:`GenericForeignKey`)를 사용할 수 있도록 하였습니다. 그리고 분류를 이용할 모델에 범용 관계 필드(:code:`GenericRelation`)를 추가했습니다. -What did we do, we added we added a :code:`GenericForeignKey` fields on :code:`FlexCategory` using one :code:`ForeignKey` and one :code:`PositiveIntegerField`, then -added a :code:`GenericRelation` on the models you want to categorize. - - -At the database level it looks like this: +:code:`FlexCategory` 모델의 데이터베이스 스키마는 다음과 같이 정의됩니다. .. code-block @@ -71,24 +65,23 @@ At the database level it looks like this: content_type_id | integer | not null -You can categorize a :code:`Hero` like this. - +:code:`Hero` 모델의 항목을 분류할 때는 다음과 같이 합니다. .. code-block:: python + hero = Hero.objects.create(name='Hades') FlexCategory.objects.create(content_object=hero, name="mythic") -And then get a :code:`Hero` categorised as 'ghost' like this +'ghost'로 분류된 :code:`Hero` 를 구하려면 다음과 같이 조회합니다. .. code-block:: python - FlexCategory.objects.create(content_object=hero, name="ghost") + Hero.objects.filter(flex_category__name='ghost') -This gives us this sql. +위의 ORM 코드가 생성하는 SQL 질의문은 아래와 같습니다. .. code-block:: sql - SELECT "entities_hero"."name" FROM "entities_hero" INNER JOIN "entities_flexcategory" ON ("entities_hero"."id" = "entities_flexcategory"."object_id" diff --git a/docs/index.rst b/docs/index.rst index 0f9d3ff..333f652 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -1,11 +1,11 @@ -Django ORM Cookbook +장고 ORM 요리책 +++++++++++++++++++++++ -Django ORM Cookbook is a book about doing things with Django ORM and Django models. -Django is a “MTV” (Model-Template-View) framework – This book provides a deep dive into the :code:`M` part. +『장고 ORM 요리책(Django ORM Cookbook)』은 장고의 ORM(객체 관계 매핑) 기능과 모델 기능을 활용하는 다양한 레시피(조리법)를 담은 책입니다. 장고는 모델-템플릿-뷰(MTV) 프레임워크입니다. 이 책은 그 가운데 '모델'에 대해 상세히 다룹니다. + +이 책은 "장고 ORM/쿼리셋/모델으로 ~을 하는 방법은 무엇인가요?"와 같은 질문 50여 개와 그 답을 담고 있습니다. -They take the form of about 50 questions of the form :code:`How to do X with Django ORM/Queryset/Models`. .. image:: BookCover.jpg @@ -14,8 +14,9 @@ They take the form of about 50 questions of the form :code:`How to do X with Dja introduction -Querying and Filtering -=============================================== + +정보를 조회하고 필요한 항목을 선별하는 방법 +=============================================================== .. toctree:: :maxdepth: 1 @@ -40,8 +41,8 @@ Querying and Filtering func_expressions -Creating, Updating and Deleting things -=============================================== +항목을 생성·갱신·삭제하는 방법 +=================================================================== .. toctree:: :maxdepth: 1 @@ -56,8 +57,8 @@ Creating, Updating and Deleting things datetime -Ordering things -======================== +조회 결과를 정렬하는 방법 +================================================================ .. toctree:: :maxdepth: 1 @@ -70,8 +71,8 @@ Ordering things order_by_annotated_field -Database Modelling -============================================== +모델을 정의하는 방법 +=============================================================== .. toctree:: :maxdepth: 1 @@ -94,7 +95,7 @@ Database Modelling -Testing +장고 ORM 코드를 테스트하는 방법 =============================================== .. toctree:: :maxdepth: 1 @@ -104,9 +105,12 @@ Testing keepdb refresh_from_db -Indices and tables -================== + + +찾아보기 / 표 +=============================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` + diff --git a/docs/introduction.rst b/docs/introduction.rst index 0296691..d394453 100644 --- a/docs/introduction.rst +++ b/docs/introduction.rst @@ -1,18 +1,17 @@ -Introduction ------------------ +이 책의 소개 +-------------------------- -Django ORM is one of the key pillars of Django. It provides abstractions to work with databases, in a mostly database agnostic way. +장고 ORM은 장고의 핵심 구성요소 가운데 하나로, 데이터베이스 시스템을 직접 다루지 않고도 데이터베이스를 활용할 수 있도록 하는 편리하고도 강력한 인터페이스입니다. "간단한 것을 쉽게, 어려운 것을 가능하게" 해 주는 고마운 기능이죠. -Django ORM combines ease of use with powerful abstractions. It keeps "Simple things easy and hard things possible". +이 책은 여러 가지 예제로 문제 상황을 직접 다뤄보며 장고 ORM을 익히도록 합니다. 여러분의 장고 ORM의 이해도를 높여 줄 50여 개의 질문을 준비했습니다. -In this book, we will learn Django ORM by doing things with it. We will ask about 50 questions about Django ORM, and get a deeper understanding of the ORM. - -How to read this book. +이 책을 읽는 방법 +++++++++++++++++++++++++ -Each chapter in the book is question. The questions are grouped in related chapters. You can read the book in eaither of two ways. +이 책의 각 장은 각각 질문을 하나씩 다룹니다. 비슷한 주제를 다루는 장들은 서로 모아 두었습니다. 이 책을 읽는 방법은 크게 두 가지가 있습니다. + +1. 특정한 질문에 관한 답을 찾는다면 그 질문을 다루는 장과 그와 연결된 장을 함께 읽으세요. +2. 장고 ORM과 모델 계층에 대한 이해도를 높이고 싶다면 책을 처음부터 차례대로 읽으세요. -1. If you are looking to get answers to specific questions, read that chapter and other chapters in that group. -2. If you are need to get a deeper understanding of Django ORM and models layer, read the chapters from start to the end. diff --git a/docs/join.rst b/docs/join.rst index 5919d5c..031c8bc 100644 --- a/docs/join.rst +++ b/docs/join.rst @@ -1,7 +1,7 @@ -How to perform join operations in django ORM? -====================================================== +두 모델을 결합(JOIN)하려면 어떻게 하나요? +======================================================== -A SQL Join statement is used to combine data or rows from two or more tables based on a common field between them. Join can be carried out in many ways. Some are shown below. :: +SQL에서는 JOIN 문을 이용해 동일한 값을 가진 열을 기준으로 두 표를 결합할 수 있습니다. 결합 연산은 여러 가지 방법으로 수행할 수 있습니다. 다음은 장고에서 이를 수행하는 몇 가지 예입니다. :: >>> a1 = Article.objects.select_related('reporter') // Using select_related >>> a1 @@ -12,4 +12,4 @@ A SQL Join statement is used to combine data or rows from two or more tables bas >>> a2 , , , , ]> >>> print(a2.query) - SELECT "events_article"."id", "events_article"."headline", "events_article"."pub_date", "events_article"."reporter_id", "events_article"."slug" FROM "events_article" INNER JOIN "auth_user" ON ("events_article"."reporter_id" = "auth_user"."id") WHERE "auth_user"."username" = John ORDER BY "events_article"."headline" ASC \ No newline at end of file + SELECT "events_article"."id", "events_article"."headline", "events_article"."pub_date", "events_article"."reporter_id", "events_article"."slug" FROM "events_article" INNER JOIN "auth_user" ON ("events_article"."reporter_id" = "auth_user"."id") WHERE "auth_user"."username" = John ORDER BY "events_article"."headline" ASC diff --git a/docs/keepdb.rst b/docs/keepdb.rst index 65ec809..8018d9b 100644 --- a/docs/keepdb.rst +++ b/docs/keepdb.rst @@ -1,15 +1,11 @@ -How to speed tests by reusing database between test runs? -================================================================ +데이터베이스를 재사용하여 테스트 실행 속도를 높일 수 있나요? +============================================================================================ -When we execute the command :code:`python manage.py test`, a new db is created everytime. This doesn't matter much if we don't have many migrations. - -But when we have many migrations, it takes a long time to recreate the database between the test runs. To avoid such situations, we may reuse the old database. - -You can prevent the test databases from being destroyed by adding the :code:`--keepdb` flag to the test command. This will preserve the test database between runs. If the database does not exist, it will first be created. If any migrations have been added since the last test run, -they will be applied in order to keep it up to date. +:code:`python manage.py test` 명령을 실행할 때마다 데이터베이스가 새로 생성됩니다. 이것은 마이그레이션이 많지 않을 때는 문제가 되지 않습니다. 하지만 마이그레이션이 많아질수록 테스트 실행 시 데이터베이스 재생성에 많은 시간을 소요하게 됩니다. 이런 상황을 피하기 위해 이전에 생성된 데이터베이스를 재사용할 수 있습니다. +테스트 명령에 :code:`--keepdb` 플래그를 추가하여 데이터베이스가 삭제되는 것을 방지하고 테스트 실행 간 데이터베이스를 유지할 수 있습니다. +데이터베이스가 존재하지 않으면 데이터베이스를 새로 생성합니다. 마지막 테스트 실행 이후 마이그레이션이 추가되었으면 최신 상태를 유지하기 위해 마이그레이션을 수행합니다. .. code-block:: bash $ python manage.py test --keepdb - diff --git a/docs/many_to_many.rst b/docs/many_to_many.rst index 4fcacd1..2dfcfb0 100644 --- a/docs/many_to_many.rst +++ b/docs/many_to_many.rst @@ -1,13 +1,11 @@ -How to model many to many relationships? -=============================================== +다대다 관계는 어떻게 나타내나요? +=================================================== -A many-to-many relationship refers to a relationship between tables in a database when a parent row in one table contains several child rows in the second table, and vice versa. +다대다 관계란 한 표의 항목이 다른 표의 항목 여러 개를 가리킬 수 있고, 반대로 다른 표의 항목이 그 표의 항목을 여러 개 가리킬 수도 있는 관계입니다. -Just to make it more interactive, we will talk about a twitter app. By just using few fields and ManyToMany field we can make a simple twitter app. +실제로 실행 가능한 예로, 트위터 앱을 다뤄 보겠습니다. 필드 몇 개와 :code:`ManyToMany` 필드만 있으면 간단한 트위터 앱을 만들 수 있습니다. -We basically have 3 basic things in Twitter, tweets, followers, favourite/unfavourite. - -We have two models to make everything work. We are inheriting django's auth_user.:: +트위터의 핵심 기능으로 '트윗', '팔로우', '마음에 들어요'가 있습니다. 아래의 두 모델로 그 핵심 기능을 모두 구현할 수 있습니다. :code:`User` 모델은 장고의 사용자 인증 모델을 확장하여 정의했습니다. :: class User(AbstractUser): tweet = models.ManyToManyField(Tweet, blank=True) @@ -16,47 +14,48 @@ We have two models to make everything work. We are inheriting django's auth_user class Tweet(models.Model): tweet = models.TextField() - favourite = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='user_favourite') + favorite = models.ManyToManyField(settings.AUTH_USER_MODEL, blank=True, related_name='user_favorite') def __unicode__(self): return self.tweet -What will the above model be able to do ? :: - - 1) User will able to follow/unfollow other users. - 2) User will able to see tweets made by other users whom user is following. - 3) User is able to favorite/unfavorite tweets. - - -Few operations using ManyToManyfield which can be done are: :: - - >>> t1 = Tweet(tweet="I am happy today") - >>> t1.save() - >>> t2 = Tweet(tweet="This is my second Tweet") - >>> t2.save() - >>> u1 = User(username='johny1', first_name='Johny', last_name='Smith', email='johny@example.com') - >>> u1.save() - >>> u2 = User(username='johny1', first_name='Johny', last_name='Smith', email='johny@example.com') - >>> u2.save() - >>> u3 = User(username='someuser', first_name='Some', last_name='User', email='some@example.com') - >>> u3.save() - -We have created few tweets and few users, that didn't involve any use of M2M field so far. Lets continue linking them in next step. :: - - >>> u2.tweet.add(t1) - >>> u2.save() - >>> u2.tweet.add(t2) - >>> u2.save() - // User can follow other users. - >>> u2.follow.add(u1) - >>> u2.save() - // Tweets are linked to the users. Users have folloewd each other. Now we can make users do favourite/unfavourite of the tweets. - >>> t1.favourite.add(u1) - >>> t1.save() - >>> t1.favourite.add(u3) - >>> t1.save() - // For removing any users vote - >>> t1.favourite.remove(u1) - >>> t1.save() - -Working example can be found in the repo: https://github.com/yashrastogi16/simpletwitter +이 모델로 할 수 있는 일은 다음과 같습니다. :: + + 1) 사용자가 다른 사용자를 '팔로우' 및 취소할 수 있습니다. + 2) 사용자가 팔로우하는 다른 사용자가 작성한 트윗을 볼 수 있습니다. + 3) 사용자가 트윗에 '마음에 들어요' 및 취소할 수 있습니다. + +:code:`ManyToMany` 필드로 수행할 수 있는 연산을 몇 가지 살펴볼 텐데, 그 전에 항목을 몇 개 생성해 둡시다. + +>>> t1 = Tweet(tweet="I am happy today") +>>> t1.save() +>>> t2 = Tweet(tweet="This is my second Tweet") +>>> t2.save() +>>> u1 = User(username='johny1', first_name='Johny', last_name='Smith', email='johny@example.com') +>>> u1.save() +>>> u2 = User(username='johny1', first_name='Johny', last_name='Smith', email='johny@example.com') +>>> u2.save() +>>> u3 = User(username='someuser', first_name='Some', last_name='User', email='some@example.com') +>>> u3.save() + +생성한 항목들을 :code:`ManyToMany` 필드로 연결해 봅시다. :: + +>>> u2.tweet.add(t1) +>>> u2.save() +>>> u2.tweet.add(t2) +>>> u2.save() +>>> # 사용자가 다른 사용자를 '팔로우' 할 수 있습니다. +>>> u2.follow.add(u1) +>>> u2.save() +>>> # 트윗이 사용자에 연결되어 있습니다. 사용자들이 트윗에 마음에 들어요 및 취소를 할 수 있습니다. +>>> t1.favorite.add(u1) +>>> t1.save() +>>> t1.favorite.add(u3) +>>> t1.save() +>>> # '마음에 들어요' 취소하기 +>>> t1.favorite.remove(u1) +>>> t1.save() + +완전히 동작하는 예제는 다음 저장소에서 확인해 주세요. + +https://github.com/yashrastogi16/simpletwitter diff --git a/docs/multiple_databases.rst b/docs/multiple_databases.rst index 2f8b046..41836f7 100644 --- a/docs/multiple_databases.rst +++ b/docs/multiple_databases.rst @@ -1,7 +1,7 @@ -How to add multiple databases to the django application ? -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +장고 프로젝트 하나에서 여러 개의 데이터베이스를 사용할 수 있나요? +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -The configuration of database related stuff is mostly done in :code:`settings.py` file. So to add multiple database to our django project we need add them in :code:`DATABASES` dictionary. :: +데이터베이스의 접속에 관련된 설정은 대부분 :code:`settings.py` 파일에서 이루어집니다. 장고 프로젝트에 여러 개의 데이터베이스를 추가하려면 해당 파일의 :code:`DATABASES` 사전에 등록하면 됩니다. :: DATABASE_ROUTERS = ['path.to.DemoRouter'] DATABASE_APPS_MAPPING = {'user_data': 'users_db', @@ -26,16 +26,15 @@ The configuration of database related stuff is mostly done in :code:`settings.py } } -With multiple databases it will be good to talk about :code:`Database Router`. The default routing scheme ensures that if a database isn’t specified, all queries fall back to the default database. :code:`Database Router` defaults to :code:`[]`. :: +여러 개의 데이터베이스를 함께 사용하려면 데이터베이스 중계기(database router)에 대해 알아야 합니다. 장고의 기본 중계 설정은 데이터베이스를 특정하지 않은 경우 기본(default) 데이터베이스로 중계하는 것입니다. :code:`DATABASE_ROUTERS` 설정의 기본값은 :code:`[]` 입니다. 중계기는 다음과 같이 정의할 수 있습니다. :: class DemoRouter: """ - A router to control all database operations on models in the - user application. + user_data 앱의 모델에서 수행되는 모든 데이터베이스 연산을 제어하는 중계기 """ def db_for_read(self, model, **hints): """ - Attempts to read user models go to users_db. + user_data 앱의 모델을 조회하는 경우 users_db로 중계한다. """ if model._meta.app_label == 'user_data': return 'users_db' @@ -43,7 +42,7 @@ With multiple databases it will be good to talk about :code:`Database Router`. T def db_for_write(self, model, **hints): """ - Attempts to write user models go to users_db. + user_data 앱의 모델을 기록하는 경우 users_db로 중계한다. """ if model._meta.app_label == 'user_data': return 'users_db' @@ -51,7 +50,7 @@ With multiple databases it will be good to talk about :code:`Database Router`. T def allow_relation(self, obj1, obj2, **hints): """ - Allow relations if a model in the user app is involved. + user_data 앱의 모델과 관련된 관계 접근을 허용한다. """ if obj1._meta.app_label == 'user_data' or \ obj2._meta.app_label == 'user_data': @@ -60,15 +59,14 @@ With multiple databases it will be good to talk about :code:`Database Router`. T def allow_migrate(self, db, app_label, model_name=None, **hints): """ - Make sure the auth app only appears in the 'users_db' - database. + user_data 앱의 모델에 대응하는 표가 users_db 데이터베이스에만 생성되도록 한다. """ if app_label == 'user_data': return db == 'users_db' return None -Respective models would be modified as :: +중계기를 위와 같이 설정해 두었으면, 모델이 서로 다른 데이터베이스를 사용하도록 다음과 같이 정의할 수 있습니다. :: class User(models.Model): username = models.Charfield(ax_length=100) @@ -82,6 +80,6 @@ Respective models would be modified as :: class Meta: app_label = 'customer_data' -Few helpful commands while working with multiple databases. :: +여러 개의 데이터베이스를 관리할 때 사용하는 마이그레이션 명령도 알아두세요. :: $ ./manage.py migrate --database=users_db diff --git a/docs/multiple_objects.rst b/docs/multiple_objects.rst index 2158675..c8b29bc 100644 --- a/docs/multiple_objects.rst +++ b/docs/multiple_objects.rst @@ -1,10 +1,10 @@ -How to create multiple objects in one shot? -++++++++++++++++++++++++++++++++++++++++++++++++++ +여러 개의 행을 한번에 생성하는 방법이 있나요? +=================================================================== -There are conditions when we want to save multiple objects in one go. Say we want to add multiple categories at once and we don't want to make many queries to the database. -We can use :code:`bulk_create` for creating multiple objects in one shot. +여러 개의 신규 객체를 한꺼번에 저장하고 싶은 경우가 있습니다. 예를 들어, 여러 개의 분류 항목을 단번에 생성하되, 데이터베이스에 질의를 여러 번 수행하지 않아야 한다고 합시다. +:code:`bulk_create` 메서드를 이용하면 여러 개의 신규 객체를 한 번에 저장할 수 있습니다. -Here is an example. +다음 예를 살펴보세요. .. code-block:: ipython @@ -19,4 +19,4 @@ Here is an example. >>> Category.objects.all().count() 5 -:code:`bulk_create` takes a list of unsaved objects. +:code:`bulk_create` 메서드는 저장되지 않은 객체들을 담은 리스트를 인자로 전달받습니다. diff --git a/docs/notequal_query.rst b/docs/notequal_query.rst index 444d8ba..3640610 100644 --- a/docs/notequal_query.rst +++ b/docs/notequal_query.rst @@ -1,38 +1,34 @@ -How to do a NOT query in Django queryset? +NOT 연산으로 조건을 부정하려면 어떻게 하나요? ++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: usertable.png -If you are using :code:`django.contrib.auth`, you will have a table called :code:`auth_user`. It will have fields as :code:`username`, :code:`first_name`, :code:`last_name` and more. +장고의 사용자 계정 관리 앱인 :code:`django.contrib.auth` 를 사용하면 데이터베이스에 :code:`auth_user` 라는 표가 생성됩니다. 이 표에는 :code:`username`, :code:`first_name`, :code:`last_name` 등의 열이 있습니다. -Say you want to fetch all users with id NOT < 5. You need a NOT operation. +id < 5 라는 조건을 만족하지 않는 모든 사용자를 구해 봅시다. 이를 수행하려면 NOT 연산이 필요합니다. -Django provides two options. +장고에서는 다음 두 방법으로 구할 수 있습니다. - :code:`exclude()` - :code:`filter(~Q())` -The query in detail ------------------------ +질의문 살펴보기 +----------------------- -Our SQL query for the above condition will look something like :: +위 조건의 SQL 질의문은 다음과 같이 생성됩니다. :: SELECT id, username, first_name, last_name, email FROM auth_user WHERE NOT id < 5; .. image:: sqluser_notquery.png -Method 1 using exclude - -.. code-block - - +exclude 메서드를 이용하는 방법은 다음과 같습니다. :: >>> queryset = User.objects.exclude(id__lt=5) >>> queryset , , , , , ]> -Method 2 using Q() method :: +Q 객체를 이용하는 방법은 다음과 같습니다. :: >>> from django.db.models import Q >>> queryset = User.objects.filter(~Q(id__lt=5)) diff --git a/docs/null_vs_blank.rst b/docs/null_vs_blank.rst index 54bdac2..92dd0e5 100644 --- a/docs/null_vs_blank.rst +++ b/docs/null_vs_blank.rst @@ -1,19 +1,20 @@ -What is the difference between :code:`null=True` and :code:`blank=True`? -=============================================================================== +:code:`null=True` 와 :code:`blank=True` 의 차이가 무엇인가요? +==================================================================================================== -The default value of both :code:`null` and :code:`blank` is :code:`False`. Both of these values work at field level i.e., whether we want to keep a field null or blank. +:code:`null` 과 :code:`blank` 는 둘 다 기본값이 :code:`False` 입니다. 이 두 설정은 모두 필드(열) 수준에서 동작합니다. 즉, 필드(열)를 비워두는 것을 허용할 것인지를 설정합니다. -:code:`null=True` will set the field's value to NULL i.e., no data. It is basically for the databases column value. :: +:code:`null=True` 는 필드의 값이 NULL(정보 없음)로 저장되는 것을 허용합니다. 결국 데이터베이스 열에 관한 설정입니다. :: date = models.DateTimeField(null=True) -:code:`blank=True` determines whether the field will be required in forms. This includes the admin and your own custom forms. :: +:code:`blank=True` 는 필드가 폼(입력 양식)에서 빈 채로 저장되는 것을 허용합니다. 장고 관리자(admin) 및 직접 정의한 폼에도 반영됩니다. :: - title = models.CharField(blank=True) // title can be kept blank. In the database ("") will be stored. + title = models.CharField(blank=True) # 폼에서 비워둘 수 있음. 데이터베이스에는 ''이 저장됨. -:code:`null=True` :code:`blank=True` This means that the field is optional in all circumstances. :: +:code:`null=True` 와 :code:`blank=True` 를 모두 지정하면 어떤 조건으로든 값을 비워둘 수 있음을 의미합니다. :: epic = models.ForeignKey(null=True, blank=True) - // The exception is CharFields() and TextFields(), which in Django are never saved as NULL. Blank values are stored in the DB as an empty string (''). + # 단, CharFields()와 TextFields()에서는 예외입니다. + # 장고는 이 경우 NULL을 저장하지 않으며, 빈 값을 빈 문자열('')로 저장합니다. -Also there is a special case, when you need to accept NULL values for a :code:`BooleanField`, use :code:`NullBooleanField`. \ No newline at end of file +또 하나 예외적인 경우가 있습니다. 불리언 필드(:code:`BooleanField`)에 NULL을 입력할 수 있도록 하려면 :code:`null=True` 를 설정하는 것이 아니라, 널 불리언 필드(:code:`NullBooleanField`)를 사용해야 합니다. \ No newline at end of file diff --git a/docs/numqueries.rst b/docs/numqueries.rst index f8a3590..5e78baf 100644 --- a/docs/numqueries.rst +++ b/docs/numqueries.rst @@ -1,12 +1,14 @@ -How to assert that a function used a fixed number of queries? -======================================================================== +질의 횟수가 고정된 횟수만큼만 일어나는지 확인할 수 있을까요? +======================================================================================= -We can count number of queries for testing by using :code:`assertNumQueries()` method. :: +장고 단위 테스트 클래스의 :code:`assertNumQueries()` 메서드를 사용하여 데이터베이스에 발생하는 질의 횟수를 검증할 수 있습니다. - def test_number_of_queries(self): - User.objects.create(username='testuser1', first_name='Test', last_name='user1') - # Above ORM create will run only one query. - self.assertNumQueries(1) - User.objects.filter(username='testuser').update(username='test1user') - # One more query added. - self.assertNumQueries(2) +.. code-block:: python + + def test_number_of_queries(self): + User.objects.create(username='testuser1', first_name='Test', last_name='user1') + # 위 ORM 명령으로 질의 횟수가 1 번 일어나야 한다. + self.assertNumQueries(1) + User.objects.filter(username='testuser').update(username='test1user') + # 질의 횟수가 한 번 증가해야 한다. + self.assertNumQueries(2) diff --git a/docs/one_to_many.rst b/docs/one_to_many.rst index 263d6f7..643f3f6 100644 --- a/docs/one_to_many.rst +++ b/docs/one_to_many.rst @@ -1,8 +1,11 @@ -How to model one to many relationships? -=============================================== +일대다 관계는 어떻게 나타내나요? +=================================================== -In relational databases, a one-to-many relationship occurs when a parent record in one table can potentially reference several child records in another table. In a one-to-many relationship, the parent is not required to have child records; therefore, the one-to-many relationship allows zero child records, a single child record or multiple child records. -To define a many-to-one relationship, use `ForeignKey`.:: +일대다 관계란 한 표의 상위 항목이 다른 표의 여러 하위 항목에서 참조되는 관계입니다. 일대다 관계에서 상위 항목이 반드시 하위 항목을 가진다는 보장은 없습니다. 상위 항목은 하위 항목을 0개, 1개, 여러 개 가질 수 있습니다. + +장고 모델에서 일대다 관계를 정의할 때는 :code:`ForeignKey` 필드를 사용합니다. + +.. code-block:: python class Article(models.Model): headline = models.CharField(max_length=100) @@ -15,27 +18,27 @@ To define a many-to-one relationship, use `ForeignKey`.:: class Meta: ordering = ('headline',) - >>> u1 = User(username='johny1', first_name='Johny', last_name='Smith', email='johny@example.com') - >>> u1.save() - >>> u2 = User(username='alien', first_name='Alien', last_name='Mars', email='alien@example.com') - >>> u2.save() - >>> from datetime import date - >>> a1 = Article(headline="This is a test", pub_date=date(2018, 3, 6), reporter=u1) - >>> a1.save() - >>> a1.reporter.id - 13 - >>> a1.reporter - - -If you try to assign an object before saving it you will encounter a ValueError :: - - >>> u3 = User(username='someuser', first_name='Some', last_name='User', email='some@example.com') - >>> Article.objects.create(headline="This is a test", pub_date=date(2018, 3, 7), reporter=u1) - Traceback (most recent call last): - ... - ValueError: save() prohibited to prevent data loss due to unsaved related object 'reporter'. - >>> Article.objects.create(headline="This is a test", pub_date=date(2018, 3, 7), reporter=u1) - >>> Article.objects.filter(reporter=u1) - , ]> - -The above queryset shows User u1 with multiple :code:`Articles`. Hence One to Many. +>>> u1 = User(username='johny1', first_name='Johny', last_name='Smith', email='johny@example.com') +>>> u1.save() +>>> u2 = User(username='alien', first_name='Alien', last_name='Mars', email='alien@example.com') +>>> u2.save() +>>> from datetime import date +>>> a1 = Article(headline="This is a test", pub_date=date(2018, 3, 6), reporter=u1) +>>> a1.save() +>>> a1.reporter.id +13 +>>> a1.reporter + + +상위 객체를 데이터베이스에 저장하지 않은 채로 하위 객체에 할당하려 하면 :code:`ValueError` 예외가 발생합니다. + +>>> u3 = User(username='someuser', first_name='Some', last_name='User', email='some@example.com') +>>> Article.objects.create(headline="This is a test", pub_date=date(2018, 3, 7), reporter=u3) +Traceback (most recent call last): +... +ValueError: save() prohibited to prevent data loss due to unsaved related object 'reporter'. +>>> Article.objects.create(headline="This is a test", pub_date=date(2018, 3, 7), reporter=u1) +>>> Article.objects.filter(reporter=u1) +, ]> + +위 코드에서 구한 쿼리셋을 보면, u1 하나에 여러 개의 :code:`Article` 이 연결되어 있음(일대다 관계)을 확인할 수 있습니다. diff --git a/docs/one_to_one.rst b/docs/one_to_one.rst index d33a16f..c2a5584 100644 --- a/docs/one_to_one.rst +++ b/docs/one_to_one.rst @@ -1,9 +1,11 @@ -How to model one to one relationships? -=============================================== +일대일 관계는 어떻게 나타내나요? +=================================================== -One-to-one relationships occur when there is exactly one record in the first table that corresponds to one record in the related table. -Here we have an example where we know that each individual can have only one Biological parents i.e., Mother and Father. -We already have auth user model with us, we will add a new model UserParent as described below. :: +일대일 관계란 두 표에서 각 항목이 서로 다른 표의 항목 단 하나와 연결되는 관계입니다. 우리가 쉽게 이해할 수 있는 예를 들자면, 우리들 각자는 생부와 생모를 각각 하나씩만 가질 수 있습니다. + +다음 예는 장고의 사용자 인증 모델에 :code:`UserParent` 모델을 일대일 관계로 연결해서 각 사용자마다 사용자의 부모를 기록할 수 있도록 합니다. + +.. code-block:: python from django.contrib.auth.models import User @@ -16,19 +18,18 @@ We already have auth user model with us, we will add a new model UserParent as d father_name = models.CharField(max_length=100) mother_name = models.CharField(max_length=100) - >>> u1 = User.objects.get(first_name='Ritesh', last_name='Deshmukh') - >>> u2 = User.objects.get(first_name='Sohan', last_name='Upadhyay') - >>> p1 = UserParent(user=u1, father_name='Vilasrao Deshmukh', mother_name='Vaishali Deshmukh') - >>> p1.save() - >>> p1.user.first_name - 'Ritesh' - >>> p2 = UserParent(user=u2, father_name='Mr R S Upadhyay', mother_name='Mrs S K Upadhyay') - >>> p2.save() - >>> p2.user.last_name - 'Upadhyay' +>>> u1 = User.objects.get(first_name='Ritesh', last_name='Deshmukh') +>>> u2 = User.objects.get(first_name='Sohan', last_name='Upadhyay') +>>> p1 = UserParent(user=u1, father_name='Vilasrao Deshmukh', mother_name='Vaishali Deshmukh') +>>> p1.save() +>>> p1.user.first_name +'Ritesh' +>>> p2 = UserParent(user=u2, father_name='Mr R S Upadhyay', mother_name='Mrs S K Upadhyay') +>>> p2.save() +>>> p2.user.last_name +'Upadhyay' -The on_delete method is used to tell Django what to do with model instances that depend on the model instance you delete. (e.g. a ForeignKey relationship). The on_delete=models.CASCADE tells Django to cascade the deleting effect i.e. continue deleting the dependent models as well. :: +on_delete 메서드는 그 필드에 연결된 항목이 삭제될 때 그 항목을 가리키는 항목들을 어떻게 처리해야 할지 설정합니다. 예를 들어, :code:`on_delete=models.CASCADE` (하위 삭제)는 연결된 항목이 삭제될 때 해당 항목을 함께 삭제하도록 합니다. 따라서, 아래의 코드를 실행하면 :code:`User` 모델의 항목(u2) 뿐 아니라 :code:`UserParent` 의 항목(p2)도 함께 삭제됩니다. :: - >>> u2.delete() +>>> u2.delete() -Will also delete the related record of :code:`UserParent`. diff --git a/docs/or_query.rst b/docs/or_query.rst index fb6f47e..585251d 100644 --- a/docs/or_query.rst +++ b/docs/or_query.rst @@ -1,27 +1,28 @@ -How to do OR queries in Django ORM? -++++++++++++++++++++++++++++++++++++++++++++++++++ +OR 연산으로 일부 조건을 하나라도 만족하는 항목을 구하려면 어떻게 하나요? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .. image:: usertable.png -If you are using :code:`django.contrib.auth`, you will have a table called :code:`auth_user`. It will have fields as :code:`username`, :code:`first_name`, :code:`last_name` and more. +장고의 사용자 계정 관리 앱인 :code:`django.contrib.auth` 를 사용하면 데이터베이스에 :code:`auth_user` 라는 표가 생성됩니다. 이 표에는 :code:`username`, :code:`first_name`, :code:`last_name` 등의 열이 있습니다. -A common requirement is performing :code:`OR` filtering with two ore more conditions. Say you want find all users with firstname starting with 'R' and last_name starting with 'D'. +:code:`OR` 연산으로 여러 조건 중 하나라도 만족하는 행을 구해야 하는 경우가 많습니다. 이름이 'R'로 시작하거나 성이 'D'로 시작하는 모든 사용자를 구한다고 해 봅시다. -Django provides two options. +장고에서는 다음 두 방법으로 구할 수 있습니다. - :code:`queryset_1 | queryset_2` -- :code:`filter(Q()|Q()` +- :code:`filter(Q()|Q())` -The query in detail + +질의문 살펴보기 ----------------------- -The SQL query for the above condition will look something like :: +위 조건의 SQL 질의문은 다음과 같이 생성됩니다. :: SELECT username, first_name, last_name, email FROM auth_user WHERE first_name LIKE 'R%' OR last_name LIKE 'D%'; .. image:: sqluser_result1.png -Similarly our ORM query would look like +장고 ORM 코드도 비슷합니다. .. code-block:: python @@ -33,7 +34,7 @@ Similarly our ORM query would look like queryset , , , , ]> -You can also look at the generated query. +장고 ORM이 생성하는 SQL 질의문도 한 번 확인해 봅시다. .. code-block:: python @@ -44,14 +45,14 @@ You can also look at the generated query. "auth_user"."is_active", "auth_user"."date_joined" FROM "auth_user" WHERE ("auth_user"."first_name"::text LIKE R% OR "auth_user"."last_name"::text LIKE D%)' -Alternatively, you can use the :code:`Q` objects. +:code:`Q` 객체를 이용하는 방법도 가능합니다. .. code-block:: python from django.db.models import Q qs = User.objects.filter(Q(first_name__startswith='R')|Q(last_name__startswith='D')) -If you look at the generated query, the result is exactly the same +두 방법 모두 생성되는 SQL 질의문은 완전히 동일합니다. .. code-block:: ipython diff --git a/docs/order_by_annotated_field.rst b/docs/order_by_annotated_field.rst index db2a4cc..9e8f6ed 100644 --- a/docs/order_by_annotated_field.rst +++ b/docs/order_by_annotated_field.rst @@ -1,7 +1,7 @@ -How to order on an annotated field? -========================================== +계산 필드를 기준으로 정렬할 수 있나요? +========================================================================== -You have two models, :code:`Category` and :code:`Hero`. +:code:`Category` 모델과 :code:`Hero` 모델이 있습니다. .. code-block:: python @@ -15,7 +15,7 @@ You have two models, :code:`Category` and :code:`Hero`. category = models.ForeignKey(Category, on_delete=models.CASCADE) -You want to get the :code:`Category`, ordered by number of :code:`Hero` in them. You can do this. +:code:`Category` 항목들을 각 :code:`Category` 항목에 속한 :code:`Hero` 항목의 개수에 따라 정렬하고 싶다면, 다음과 같이 :code:`annotate` 메서드로 계산 필드를 준비하여 기준으로 삼을 수 있습니다. .. code-block:: python @@ -24,5 +24,3 @@ You want to get the :code:`Category`, ordered by number of :code:`Hero` in them. ).order_by( "-hero_count" ) - - diff --git a/docs/order_by_related_model.rst b/docs/order_by_related_model.rst index 42471d3..a3b0d81 100644 --- a/docs/order_by_related_model.rst +++ b/docs/order_by_related_model.rst @@ -1,8 +1,7 @@ -How to order on a field from a related model (with a foreign key)? -======================================================================== +외래 키로 연결된 다른 표의 열을 기준으로 정렬할 수 있나요? +========================================================================== - -You have two models, :code:`Category` and :code:`Hero`. +:code:`Category` 모델과 :code:`Hero` 모델이 다음과 같이 외래 키(ForeignKey)로 연결되어 있습니다. .. code-block:: python @@ -15,7 +14,8 @@ You have two models, :code:`Category` and :code:`Hero`. name = models.CharField(max_length=100) category = models.ForeignKey(Category, on_delete=models.CASCADE) -You want to order :code:`Hero` by category and inside each category by the :code:`Hero` name. You can do. +아래 코드는 :code:`Hero` 모델의 쿼리셋을 category 필드 순으로 정렬하되, category가 같은 항목은 (:code:`Hero` 의) name 필드 순으로 정렬합니다. + .. code-block:: python @@ -23,9 +23,9 @@ You want to order :code:`Hero` by category and inside each category by the :code 'category__name', 'name' ) -Note the double underscore(:code:`__` ) in :code:`'category__name'`. Using the double undertscore, you can order on a field from a related model. +:code:`'category__name'` 인자에 이중 밑줄 기호(:code:`__` )를 사용한 것을 봐 주세요. 이중 밑줄 기호로 연결된 모델의 필드를 가리킬 수 있습니다. -If you look at the SQL. +SQL 질의문은 다음과 같이 생성됩니다. .. code-block:: sql @@ -36,3 +36,4 @@ If you look at the SQL. INNER JOIN "entities_category" ON ("entities_hero"."category_id" = "entities_category"."id") ORDER BY "entities_category"."name" ASC, "entities_hero"."name" ASC + diff --git a/docs/order_by_two.rst b/docs/order_by_two.rst index 25d2ddb..c6af4df 100644 --- a/docs/order_by_two.rst +++ b/docs/order_by_two.rst @@ -1,12 +1,11 @@ -How to order on two fields -======================================================================== +여러 개의 필드를 기준으로 정렬하는 방법이 있나요? +=============================================================================== -:code:`order_by` on querysets can take one or more attribute names, allowing you to order on two or more fields. +쿼리셋의 :code:`order_by` 메서드에 여러 개의 정렬 기준 필드를 인자로 전달할 수 있습니다. 그러면 여러 개의 필드를 기준으로 정렬이 수행됩니다. -..code-block:: ipython +.. code-block:: ipython In [5]: from django.contrib.auth.models import User In [6]: User.objects.all().order_by("is_active", "-last_login", "first_name") Out[6]: , , ]> - diff --git a/docs/pdf_build.sh b/docs/pdf_build.sh new file mode 100755 index 0000000..1bf1eeb --- /dev/null +++ b/docs/pdf_build.sh @@ -0,0 +1,6 @@ +sphinx-build -b latex . _build/latex +sed -i '' 's/\[T1\]{fontenc}/{kotex}/g' ./_build/latex/DjangoORMCookbook.tex +sed -i '' 's/{babel}/\[english\]{babel}/g' ./_build/latex/DjangoORMCookbook.tex +sed -i '' '/BookCover/d' ./_build/latex/DjangoORMCookbook.tex + +cd ./_build/latex/ && make all-pdf && cd - diff --git a/docs/query.rst b/docs/query.rst index 7a2e3f9..e3d4488 100644 --- a/docs/query.rst +++ b/docs/query.rst @@ -1,10 +1,9 @@ -How to find the query associated with a queryset? -++++++++++++++++++++++++++++++++++++++++++++++++++ +장고 ORM이 실행하는 실제 SQL 질의문을 확인할 수 있나요? +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Sometime you want to know how a Django ORM makes our queries execute or what is the corresponding SQL of the code you are writing. This is very strightforward. Youn can get :code:`str` of any :code:`queryset.query` to get the sql. +장고 ORM이 실행하는 질의문 또는 우리가 작성한 코드에 대응하는 SQL 질의문이 무엇인지 확인하고 싶을 때가 있습니다. SQL 질의문을 구하고 싶은 :code:`queryset.query` 의 :code:`str` 을 확인하면 됩니다. 간단하죠? -You have a model called :code:`Event`. For getting all records, you will write something like -:code:`Event.objects.all()`, then do :code:`str(queryset.query)` +:code:`Event` 라는 모델이 있을 때, 이 모델의 모든 행을 데이터베이스에서 읽어오려면 :code:`Event.objects.all()` 과 같은 코드를 작성하면 됩니다. 이렇게 구한 쿼리셋의 :code:`str(queryset.query)` 를 확인하여 SQL 질의문을 살펴봅시다. .. code-block:: python @@ -16,7 +15,7 @@ You have a model called :code:`Event`. For getting all records, you will write s .. image:: sql_query.png -Example 2 +두 번째 예제 .. code-block:: python diff --git a/docs/query_relatedtool.rst b/docs/query_relatedtool.rst index 150b086..e8e5dd0 100644 --- a/docs/query_relatedtool.rst +++ b/docs/query_relatedtool.rst @@ -1,9 +1,9 @@ -How to use :code:`Q` objects for complex queries? -================================================== +Q 객체를 이용해 복잡한 질의를 수행하는 방법은 무엇인가요? +==================================================================== -In previous chapters we used :code:`Q` objects for :code:`OR` and :code:`AND` and :code:`NOT` operations. :code:`Q` objects provides you complete control over the where clause of the query. +앞선 몇 개의 장에서 :code:`Q` 객체를 이용해 :code:`OR` 연산, :code:`AND` 연산, :code:`NOT` 연산을 수행해 보았습니다. :code:`Q` 객체를 이용하면 SQL 질의문의 WHERE 절에 해당하는 기능을 온전히 활용할 수 있습니다. -If you want to :code:`OR` your conditions. +조건식에서 :code:`OR` 연산을 수행하려면 다음과 같이 합니다. .. code-block:: ipython @@ -14,7 +14,7 @@ If you want to :code:`OR` your conditions. >>> queryset , , , , ]> -If you want to :code:`AND` your conditions. +조건식에서 :code:`AND` 연산을 수행하려면 다음과 같이 합니다. .. code-block:: ipython @@ -24,7 +24,7 @@ If you want to :code:`AND` your conditions. >>> queryset , , ]> -If you want to find all users whose :code:`first_name` starts with 'R', but not if the :code:`last_name` has 'Z' +이름(:code:`first_name`)이 'R'로 시작하되, 성(:code:`last_name`)에 'Z'가 포함되지 않은 사용자를 모두 구하려면 다음과 같이 조건을 작성하면 됩니다. .. code-block:: ipython @@ -32,8 +32,7 @@ If you want to find all users whose :code:`first_name` starts with 'R', but not Q(first_name__startswith='R') & ~Q(last_name__startswith='Z') ) - -If you look at the generated query, you would see +위 코드로 생성되는 질의문은 다음과 같습니다. .. code-block:: sql @@ -52,4 +51,4 @@ If you look at the generated query, you would see WHERE ("auth_user"."first_name"::text LIKE R% AND NOT ("auth_user"."last_name"::text LIKE Z%)) -You can combine the Q objects in more complex ways to generate complex queries. +Q 객체를 이용하면 이보다 더 복잡한 조건의 질의도 문제 없이 지시할 수 있습니다. diff --git a/docs/random.rst b/docs/random.rst index 37f7d62..1fb0a2b 100644 --- a/docs/random.rst +++ b/docs/random.rst @@ -1,7 +1,7 @@ -How to efficiently select a random object from a model? -======================================================================== +항목을 무작위로 뽑고 싶습니다. 효율적인 방법이 있을까요? +============================================================================================ -Your :code:`category` models is like this. +:code:`Category` 모델을 아래와 같이 정의했다고 합시다. .. code-block:: python @@ -15,16 +15,16 @@ Your :code:`category` models is like this. return self.name -You want to get a random Category. We will look at few alternate ways to do this. +저장된 :code:`Category` 항목 가운데 하나를 무작위로 구해야 합니다. 두 가지 방법을 살펴보겠습니다. -The most straightforward way, you can :code:`order_by` random and fetch the first record. It would look something like this. +먼저 살펴볼 방법은 정직하고 이해하기 쉽습니다. :code:`order_by` 메서드로 항목들을 정렬할 때, 정렬 기준을 '무작위'로 지정하는 것입니다. 데이터를 무작위로 정렬하여 첫 번째 항목을 가져오면 무작위 항목을 구할 수 있습니다. 코드로 작성해 봅시다. .. code-block:: python def get_random(): return Category.objects.order_by("?").first() -Note: :code:`order_by('?')` queries may be expensive and slow, depending on the database backend you’re using. To test other methods, we need to insert one million records in :code:`Category` table. Go to your db like with :code:`python manage.py dbshell` and run this. +주의: 사용하는 데이터베이스 시스템에 따라 :code:`order_by('?')` 의 실행 비용이 비싸고 성능이 느릴 수 있습니다. 뒤이어 살펴볼 다른 방법과의 비교를 위해 :code:`Category` 표에 1백만 개의 항목을 추가해 두겠습니다. 명령행 인터페이스에서 :code:`python manage.py dbshell` 를 실행하여 데이터베이스 셸을 열고, 아래 질의문을 실행하시면 실습에 필요한 항목을 준비할 수 있습니다. .. code-block:: sql @@ -33,10 +33,9 @@ Note: :code:`order_by('?')` queries may be expensive and slow, depending on the (SELECT Md5(Random() :: text) AS descr FROM generate_series(1, 1000000)); -You don't need to understand the full details of the sql above, it creates one million numbers and :code:`md5-s` them to generate the name, then inserts it in the DB. +위 SQL 질의문을 자세히 이해할 필요는 없습니다. (1부터 1백만까지의 수열을 생성하고 난수에 MD5 해시를 적용한 값을 생성하여 데이터베이스에 저장합니다.) -Now, instead of sorting the whole table, you can get the max id, -generate a random number in range [1, max_id], and filter that. You are assuming that there have been no deletions. +두 번째 방법은 전체 표를 정렬하는 대신 저장된 항목의 마지막 ID를 이용하는 것입니다. 표에서 ID의 최대값을 구하고, 1과 마지막 ID 사이의 난수를 하나 생성합니다. ID가 이 난수와 동일한 항목을 구하면 됩니다. .. code-block:: python @@ -58,7 +57,7 @@ generate a random number in range [1, max_id], and filter that. You are assuming In [6]: get_random2() Out[6]: -If your models has deletions, you can slightly modify the functions, to loop until you get a valid :code:`Category`. +이 방법은 항목을 삭제하거나 해서 ID가 중간에 비어있는 경우에는 쓸 수 없습니다. 그런 경우에는 유효한 값이 나올 때까지 반복하도록 하면 됩니다. 다음은 그 방식으로 위의 함수를 수정한 것입니다. .. code-block:: python @@ -77,7 +76,7 @@ If your models has deletions, you can slightly modify the functions, to loop unt In [10]: get_random3() Out[10]: -Unless your model has a lot of deletions, the :code:`while True:` loop return quickly. Lets use :code:`timeit` to see the differences. +삭제된 항목이 많지 않다면 위의 무한반복 구문 :code:`while True:` 는 금방 종료될 것입니다. 그러면 파이썬의 :code:`timeit` 을 이용해 두 방법의 성능 차이를 확인해 봅시다. .. code-block:: python @@ -87,6 +86,5 @@ Unless your model has a lot of deletions, the :code:`while True:` loop return qu In [15]: timeit.timeit(get_random, number=100) Out[15]: 56.92513192095794 -:code:`get_random3` is about 283 time faster than :code:`get_random`. :code:`get_random` is the most generic way, but the technique in :code:`get_random3` will work unless you change changed the default way Django generates the id - autoincrementing integers, or there have been too many deletions. - +:code:`get_random3` 이 :code:`get_random` 보다 283배 빠르게 실행되었습니다. 단, :code:`get_random` 은 언제나 이용할 수 있는 반면에, :code:`get_random3` 의 방법은 장고의 기본 ID 생성 방식(auto increment, 자동 증가)을 재정의한 경우나 삭제된 항목이 너무 많을 때에는 사용하기가 어려울 수 있습니다. diff --git a/docs/refresh_from_db.rst b/docs/refresh_from_db.rst index f39ae78..7bc39b9 100644 --- a/docs/refresh_from_db.rst +++ b/docs/refresh_from_db.rst @@ -1,14 +1,14 @@ -How to reload a model object from the database? +모델 객체를 데이터베이스에서 다시 읽어들일 수 있나요? ======================================================================== -Models can be reloaded from the databse using :code:`refresh_from_db()` method. THis proves helpful during testing. For example. :: +``refresh_from_db()`` 메서드를 사용하여 데이터베이스에서 모델을 다시 읽어들일 수 있습니다. 값을 갱신하는 테스트를 작성할 때 유용한 기능입니다. 다음 예를 살펴보세요. :: class TestORM(TestCase): def test_update_result(self): userobject = User.objects.create(username='testuser', first_name='Test', last_name='user') User.objects.filter(username='testuser').update(username='test1user') - # At this point userobject.val is still testuser, but the value in the database - # was updated to test1user. The object's updated value needs to be reloaded - # from the database. + # 이 때, userobject 인스턴스의 username은 'testuser' 입니다. + # 그러나 데이터베이스에서는 'test1user'로 수정되었습니다. + # 모델 인스턴스의 속성이 데이터베이스와 맞지 않으므로 다시 읽어들입니다. userobject.refresh_from_db() self.assertEqual(userobject.username, 'test1user') diff --git a/docs/second_largest.rst b/docs/second_largest.rst index c97576e..8fb451a 100644 --- a/docs/second_largest.rst +++ b/docs/second_largest.rst @@ -1,13 +1,13 @@ -How to find second largest record using Django ORM ? +두번째로 큰 항목은 어떻게 구하죠? ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -You would across situations when you want to find second highest user depending on their age or salary. +어떤 필드를 기준으로 데이터를 정렬했을 때, 두 번째 항목을 구해야 하는 경우가 있습니다. 예컨대, 나이·급여 등이 두번째로 많은 사용자를 찾아야 하는 경우가 있겠죠. -Though the ORM gives the flexibility of finding :code:`first()`, :code:`last()` item from the queryset but not nth item. You can do it using the slice operator. +장고 ORM에서 첫번째 항목은 :code:`first()` 메서드로, 마지막 항목은 :code:`last()` 메서드로 구할 수 있습니다. 하지만 N번째 항목을 구하는 메서드는 제공되지 않습니다. 그 대신, 파이썬의 인덱싱 연산을 이용할 수 있습니다. .. image:: usertable.png -We can find Nth records from the query by using slice operator. +아래 코드와 같이, 인덱싱 연산으로 정렬된 데이터의 N번째 항목을 구할 수 있습니다. .. code-block:: python @@ -19,8 +19,7 @@ We can find Nth records from the query by using slice operator. 'Sohan' -:code:`User.objects.order_by('-last_login')[2]` only pulls up the required object from db using :code:`LIMIT ... OFFSET`. If you look at the generated sql, you would see something like this. - +:code:`User.objects.order_by('-last_login')[2]` 와 같이 쿼리셋에 인덱스 연산을 지시할 때, 장고 ORM은 데이터베이스에서 전체 데이터를 가져온 뒤 인덱싱하는 것이 아니라, :code:`LIMIT ... OFFSET` SQL 구문을 이용해 필요한 데이터만 읽어 옵니다. 실제로 생성되는 SQL 질의문을 살펴봅시다. .. code-block:: sql diff --git a/docs/select_some_fields.rst b/docs/select_some_fields.rst index 1165f4d..6510a4f 100644 --- a/docs/select_some_fields.rst +++ b/docs/select_some_fields.rst @@ -1,16 +1,16 @@ -How to select some fields only in a queryset? -++++++++++++++++++++++++++++++++++++++++++++++++++ +필요한 열만 골라 조회하려면 어떻게 하나요? +============================================================================= .. image:: usertable.png -The :code:`auth_user` model has a number of fields in it. But sometimes, you do not need to use all the fields. In such situations, we can query only desired fields. +:code:`auth_user` 모델에는 여러 개의 필드가 정의되어 있습니다. 그런데 이 필드가 전부 다 필요하지 않을 때도 있죠. 그럴 때 필요한 열만을 데이터베이스에서 읽어오는 방법을 알아 봅시다. -Django provides two ways to do this +장고는 두 가지 방법을 제공합니다. -- `values` and `values_list` methods on queryset. -- `only_method` +- 쿼리셋의 :code:`values` 메서드와 :code:`values_list` 메서드 +- :code:`only` 메서드 -Say, we want to get :code:`first_name` and :code:`last_name` of all the users whose name starts with **R**. You do not want the fetch the other fields to reduce the work the DB has to do. +이름이 R로 시작하는 모든 사용자의 이름(:code:`first_name`)과 성(:code:`last_name`)을 구해 봅시다. 데이터베이스 시스템의 부하를 줄이기 위해 그 외의 열은 가져오지 않겠습니다. .. code-block:: python @@ -19,16 +19,16 @@ Say, we want to get :code:`first_name` and :code:`last_name` of all the users wh ).values('first_name', 'last_name') >> from datetime import date >>> a1 = Article.objects.create(headline="todays market report", pub_date=date(2018, 3, 6), reporter=u1) >>> a1.save() - // slug here is auto-generated, we haven't created it in the above create method. + # 슬러그는 자동으로 생성됩니다. create 메서드를 따로 정의한 게 아닙니다. >>> a1.slug 'todays-market-report' -Slug is useful because: - | it's human friendly (eg. /blog/ instead of /1/). - | it's good SEO to create consistency in title, heading and URL. +슬러그의 장점: + | 사람이 이해하기 좋다. (:code:`/1/` 보다 :code:`/blog/` 가 좋다) + | 제목과 URL을 동일하게 맞춰 검색엔진 최적화(SEO)에 도움이 된다. diff --git a/docs/subquery.rst b/docs/subquery.rst index 854dcab..c39e23d 100644 --- a/docs/subquery.rst +++ b/docs/subquery.rst @@ -1,8 +1,7 @@ -How to do a subquery expression in Django? -============================================= +장고에서 서브쿼리 식을 사용할 수 있나요? +============================================================== -Django allows using SQL subqueries. -Let's start with something simple, We have a :code:`UserParent` model which has :code:`OnetoOne` relation with auth user. We will find all the :code:`UserParent` which have a :code:`UserParent`. +장고에서 SQL 서브쿼리(subquery, 질의문 내의 하위 질의) 식을 사용할 수 있습니다. 간단한 것부터 시작해 봅시다. :code:`auth_user` 모델과 일 대 일(:code:`OneToOne`) 관계로 연결된 :code:`UserParent` 모델이 있다고 합시다. 아래 코드로 :code:`UserParent` 모델에서 :code:`auth_user` 를 가진 행을 모두 구할 수 있습니다. .. code-block:: ipython @@ -11,9 +10,9 @@ Let's start with something simple, We have a :code:`UserParent` model which has >>> UserParent.objects.filter(user_id__in=Subquery(users.values('id'))) , , ]> -Now for something more complex. For each :code:`Category`, we want to find the most benevolent :code:`Hero`. +조금 더 까다로운 예제를 살펴봅시다. :code:`Category` 모델의 각 행 별로, 가장 선한 :code:`Hero` 행을 구해 봅시다. -The models look something like this. +모델은 다음과 같이 준비합니다. .. code-block:: python @@ -32,7 +31,7 @@ The models look something like this. ) -You can find the most benevolent Hero like this +이 모델에서 가장 선한 영웅을 구하려면 다음 코드를 실행합니다. .. code-block:: python @@ -45,7 +44,7 @@ You can find the most benevolent Hero like this ) ) -If you look at the generated sql, you will see +이 코드가 실행하는 SQL 질의문은 다음과 같습니다. .. code-block:: sql @@ -60,7 +59,7 @@ If you look at the generated sql, you will see FROM "entities_category" -Let's break down the queryset logic. The first part is +질의문을 한 단계씩 나누어 살펴봅시다. 다음 코드가 첫 번째 단계입니다. .. code-block:: python @@ -68,9 +67,8 @@ Let's break down the queryset logic. The first part is category=OuterRef("pk") ).order_by("-benevolence_factor") -We are ordering the :code:`Hero` object by :code:`benevolence_factor` in DESC order, and using -:code:`category=OuterRef("pk")` to declare that we will be using it in a subquery. +:code:`Hero` 모델의 항목들을 선함(:code:`benevolence_factor`)에 따라 내림차순으로 정렬하여 선택합니다. 그리고 :code:`category=OuterRef("pk")` 를 이용해 이 선택이 서브쿼리로 사용될 수 있도록 준비합니다. -Then we annotate with :code:`most_benevolent_hero=Subquery(hero_qs.values('name')[:1])`, to get use the subquery with a :code:`Category` queryset. The :code:`hero_qs.values('name')[:1]` part picks up the first name from subquery. +그 뒤 :code:`most_benevolent_hero=Subquery(hero_qs.values('name')[:1])` 로 서브쿼리에 별칭을 붙여 :code:`Category` 쿼리셋 안에서 사용합니다. 이 때, :code:`hero_qs.values('name')[:1]` 는 서브쿼리에서 첫 번째 행의 name 필드를 구하는 코드입니다. diff --git a/docs/table_name.rst b/docs/table_name.rst index 1c15699..8dbc10e 100644 --- a/docs/table_name.rst +++ b/docs/table_name.rst @@ -1,19 +1,16 @@ -How to specify the table name for a model? -=============================================== +모델에 연결된 표의 이름을 지정할 수 있나요? +========================================================================= +여러분이 모델에 연결된 데이터베이스 표의 이름을 직접 지정하지 않으면 장고가 자동으로 표의 이름을 지어 줍니다. 자동으로 붙는 데이터베이스 표의 이름은 "앱의 레이블"(manage.py startapp 명령에서 지은 이름)과 모델 클래스의 이름을 밑줄 기호로 연결한 것이 됩니다. -To save you time, Django automatically derives the name of the database table from the name of your model class and the app that contains it. -A model’s database table name is constructed by joining the model’s “app label” – the name you used in manage.py startapp – to the model’s class name, -with an underscore between them. - -We have two apps in our demo application i.e., :code:`entities` and :code:`events` so all the models in them will have app names as the prefixes followed by `_` then the model name. +이 책의 예제에서는 :code:`entities` 앱과 :code:`events` 앱을 사용했으므로 모든 모델의 표 이름이 :code:`entities_` 또는 :code:`events_` 로 시작합니다. .. image:: db_table.png -For renaming them we cab use :code:`db_table` parameter :: +이 이름을 직접 붙이시려면 모델의 :code:`Meta` 클래스에 :code:`db_table` 값을 설정하면 됩니다. :: class TempUser(models.Model): first_name = models.CharField(max_length=100) . . . class Meta: - db_table = "temp_user" \ No newline at end of file + db_table = "temp_user" diff --git a/docs/truncate.rst b/docs/truncate.rst index 275c4b4..7a4a594 100644 --- a/docs/truncate.rst +++ b/docs/truncate.rst @@ -1,9 +1,9 @@ -How to perform truncate like operation using Django ORM? -========================================================== +TRUNCATE 문을 수행하는 방법이 있나요? +============================================================= -Truncate statement in SQL is meant to empty a table for future use. -Though Django doesn't provide a builtin to truncate a table, but still similar result can be achived using :code:`delete()` method. -For example: +SQL의 TRUNCATE 문은 표에 저장된 모든 항목을 제거하는 명령입니다. 장고는 TRUNCATE 문을 실행하는 명령을 제공하지 않습니다. 하지만 :code:`delete` 메서드를 이용해 비슷한 결과를 얻을 수 있습니다. + +다음 예를 보십시오. .. code-block:: python @@ -14,7 +14,7 @@ For example: >>> Category.objects.all().count() 0 -This works, but this uses :code:`DELETE FROM ...` SQL statement. If you have a large number of records, this can be quite slow. You can add a :code:`classmethod` to :code:`Category` if you want to enable :code:`truncate`. +위 코드는 잘 동작합니다. 하지만 TRUNCATE 문이 아니라 :code:`DELETE FROM ...` 과 같은 SQL 질의를 수행합니다. 삭제해야 하는 항목의 수가 매우 많은 경우 처리 속도가 느릴 수 있습니다. :code:`truncate` 명령이 필요하다면 다음과 같이 :code:`Category` 모델에 :code:`classmethod` 로 추가하면 됩니다. .. code-block:: python @@ -27,4 +27,4 @@ This works, but this uses :code:`DELETE FROM ...` SQL statement. If you have a l with connection.cursor() as cursor: cursor.execute('TRUNCATE TABLE "{0}" CASCADE'.format(cls._meta.db_table)) -Then you can call :code:`Category.truncate()` to a real database truncate. +이렇게 메서드를 정의해 두면 :code:`Category.truncate()` 를 실행하여 정말로 데이터베이스 시스템에 TRUNCATE 문을 질의할 수 있습니다. diff --git a/docs/union.rst b/docs/union.rst index bdb0e1f..f068271 100644 --- a/docs/union.rst +++ b/docs/union.rst @@ -1,10 +1,10 @@ -How to do union of two querysets from same or different models? -++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +동일한 모델 또는 서로 다른 모델에서 구한 쿼리셋들을 합할 수 있나요? +======================================================================================================================= -The UNION operator is used to combine the result-set of two or more querysets. -The querysets can be from the same or from different models. When they querysets are from different models, the fields and their datatypes should match. +SQL에서는 여러 개의 결과 집합을 합할 때 UNION 연산을 이용합니다. 장고 ORM에서 union 메서드를 이용해 쿼리셋을 합할 수 있습니다. 합하려는 쿼리셋의 모델이 서로 다른 경우, 각 쿼리셋에 포함된 필드와 데이터 유형이 서로 맞아야 합니다. -Let's continue with our :code:`auth_user` model and generate 2 querysets to perform union operation + +:code:`auth_user` 모델에서 두 쿼리셋을 구한 뒤 합집합을 구해 봅시다. .. code-block:: python @@ -19,7 +19,7 @@ Let's continue with our :code:`auth_user` model and generate 2 querysets to perf >>> q2.union(q1) , , , , , , , , , ]> -Now try this +다음 코드는 실행하면 오류가 발생합니다. .. code-block:: python @@ -30,11 +30,9 @@ Now try this django.db.utils.OperationalError: SELECTs to the left and right of UNION do not have the same number of result columns -The union operation can be performed only with the querysets having same fields and the datatypes. Hence our last union operation encountered error. You can do a union on two models as long as they have same fields or same subset of fields. - -Since :code:`Hero` and :code:`Villain` both have the :code:`name` and :code:`gender`, -we can use :code:`values_list` to limit the selected fields then do a union. +union 메서드는 합하려는 쿼리셋의 필드와 데이터 유형이 서로 일치할 때만 실행할 수 있습니다. 그래서 마지막 명령이 실패했습니다. +:code:`Hero` 모델과 :code:`Villain` 모델은 둘 다 :code:`name` 필드와 :code:`gender` 필드를 갖고 있습니다. :code:`values_list` 를 이용해 공통된 필드만 가져온 뒤 union을 수행할 수 있습니다. .. code-block:: python @@ -45,4 +43,5 @@ we can use :code:`values_list` to limit the selected fields then do a union. "name", "gender" )) -This would give you all :code:`Hero` and :code:`Villain` objects with their name and gender. +위 코드를 실행하면 :code:`Hero` 모델과 :code:`Villain` 모델의 이름과 성별을 구할 수 있습니다. + diff --git a/docs/update_denormalized_fields.rst b/docs/update_denormalized_fields.rst index 33c1564..5b18a6f 100644 --- a/docs/update_denormalized_fields.rst +++ b/docs/update_denormalized_fields.rst @@ -1,7 +1,7 @@ -How to update denormalized fields in other models on save? -======================================================================== +모델 인스턴스를 저장할 때, 다른 모델에 반정규화된 필드를 함께 갱신하는 방법이 있나요? +========================================================================================================== -You have models like this. +모델을 다음과 같이 구성했다고 합시다. .. code-block:: python @@ -26,9 +26,9 @@ You have models like this. # ... -You need the :code:`hero_count` and :code:`villain_count`, to be updated when new objects are created. +Hero 모델과 Villain 모델의 항목을 새로 저장할 때, Category 모델의 :code:`hero_count` 필드와 :code:`villain_count` 필드를 갱신해야 합니다. -You can do something like this +다음과 같이 Hero 모델과 Villain 모델의 :code:`save` 메서드를 재정의하면 됩니다. .. code-block:: python @@ -50,9 +50,9 @@ You can do something like this super().save(*args, **kwargs) -Note how we did not use :code:`self.category.hero_count += 1`, as :code:`update` will do a DB update. +위 코드에서 :code:`self.category.hero_count += 1` 과 같이 인스턴스의 값을 수정하는 것이 아니라, :code:`update` 메서드로 데이터베이스의 갱신을 수행하도록 한 것을 확인하시기 바랍니다. -The alternative method is using `signals`. You can do it like this. +또 다른 방법으로, '시그널(신호)'이라는 기능을 이용하는 방법이 있습니다. 시그널을 이용하는 예를 살펴봅시다. .. code-block:: python @@ -72,12 +72,11 @@ The alternative method is using `signals`. You can do it like this. Category.objects.filter(pk=villain.category_id).update(villain_count=F('villain_count')+1) -Signals vs Overriding :code:`.save` -++++++++++++++++++++++++++++++++++++ +:code:`save` 메서드 재정의 방법과 시그널의 비교 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +:code:`save` 메서드를 재정의하는 방법과 시그널을 이용하는 방법 모두 사용할 수 있습니다. 어느 것을 사용하는 것이 좋을까요? 다음 규칙을 권해 드립니다. -Since either of signals of :code:`.save` can be used for the save behviour, when should you use which one? I follow a simple rule. - -- If your fields depend on a model you control, override :code:`.save` -- If your fields depend on a model from a 3rd party app, which you do no control, use signals. +- 반정규화 필드에 영향을 끼치는 모델을 여러분이 통제할 수 있다면 :code:`save` 메서드를 재정의합니다. +- 반정규화 필드에 영향을 끼치는 모델을 여러분이 통제할 수 없다면(그 영향이 라이브러리 등에서 이루어진다면) 시그널을 이용합니다. diff --git a/docs/uuid.rst b/docs/uuid.rst index 9c9fa4b..6c78f69 100644 --- a/docs/uuid.rst +++ b/docs/uuid.rst @@ -1,11 +1,9 @@ -How to use a UUID instead of ID as prmary key? -++++++++++++++++++++++++++++++++++++++++++++++++++ +기본 키(PK)로 ID 대신 UUID를 사용할 수 있나요? +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -Whenever we create any new model, there is an ID field attached to it. The ID field's data type will be Integer by default. +장고에서 모델을 생성하면 ID 필드가 기본 키로 생성됩니다. ID 필드의 기본 데이터 유형은 양의 정수입니다. -To make id field as UUID, there is a new field type UUIDField which was added in django version 1.8+. - -Example :: +양의 정수가 아니라 UUID를 기본 키로 사용하고 싶다면 장고 1.8 버전에서 추가된 :code:`UUIDField` 를 사용하면 됩니다. :: import uuid from django.db import models