django 공식 다큐먼트를 통해 의문점 찾아보기 (listView)

11465 단어 pythondjangodjango

아래 코드의 경우, Product 클래스 정의시 id 속성은 정의해놓지 않았지만 html에서는 받아오고 있다.

models.py에서 클래스를 구현하고 난 뒤면, views.py에서 아래와 같이 인스턴스 생성 후 모델에서 정의해놓지 않았던 필드(id)를 사용할 수 있게 된 것이다.

해당 값이 어떻게 생성된 것인지 공식 다큐먼트를 통해 확인해나가기로 했고, 이번 포스팅은 그 과정에 대해서 작성해보았다.

models.py

class Product(models.Model):
    name = models.CharField(verbose_name='상품명')
    price = models.IntegerField(verbose_name="가격")
    class Meta:
        db_table = 'basic_product'
        verbose_name = '상품'
        verbose_name_plural = '상품 복수'

views.py

class ProductView(ListView):
    model = Product
    template_name = 'product.html'
    context_object_name = 'product_list'

product_list.html

{% for product in object_list %}
<tr>
  <th scope="row">{{ product.id }}</th>
  <th scope="row">{{ product.name }}</th>
  <th scope="row">{{ product.price }}원</th>
</tr>
                {% endfor %}

위 코드의 product_list.html을 확인해보면, Product 클래스에서 정의되지 않은 값(id)을 호출하고 있었다. 이를 위해서 확인해보아야할 포인트는 2가지로 잡았다.

클라이언트의 브라우저에서 확인되는 product_list.html 페이지는 urls.py를 통해 views.ProductView를 통해 만들어진다.
ProductView는 클래스 기반 뷰를 생성하기 위한 함수로, django.views.generic.ListView를 상속받아 구현되었다.

ListView의 Method Flow는 아래와 같다

이 때, ListView 클래스는 아래 4가지 클래스를 다중 상속받은 클래스이며, 아래의 Method Flow를 수행한다.

ListView의 부모 클래스들

django.views.generic.list.MultipleObjectTemplateResponseMixin
django.views.generic.base.TemplateResponseMixin
django.views.generic.list.BaseListView
django.views.generic.list.MultipleObjectMixin
django.views.generic.base.View

ListView의 Method Flow

setup()
dispatch()
http_method_not_allowed()
get_template_names()
get_queryset()
get_context_object_name()
get_context_data()
get()
render_to_response()

위 과정에 대한 숙지를 바탕으로, product_list.html 함수에서 호출 가능했던 object_list에 대해서 찾아본 결과, object_list 데이터는 ListView 클래스의 부모 클래스인MultipleObjectMixin 클래스 내 get_context_data()에서 반환되는 context data였다.

object_list 내 object는 ProductView 클래스 내 model 변수와 관계된 값으로, model 변수 역시 MultipleObjectMixin 클래스의 model 변수를 상속받은 값인데, 'model = Product' 부분은 Model._default_manager와 get_queryset()에 의해서 'queryset = Product.objects.all()'의 동작을 수행하여 데이터베이스에서 object들을 가져온다.

그렇다면 object 객체의 멤버인 id는 데이터베이스에 지정되어 있는 값임을 알 수 있었으며, 해당 부분은 makemigrations시 생성되는 0001_initial.py에서 확인할 수 있었다.

class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='Product',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('name', models.CharField(max_length=256, verbose_name='상품명')),
                ('price', models.IntegerField(verbose_name='가격')),
                ('description', models.TextField(verbose_name='상품설명')),
                ('stuck', models.IntegerField(verbose_name='재고')),
                ('register_date', models.DateTimeField(auto_now_add=True, verbose_name='등록날짜')),
            ],
            options={
                'verbose_name': '상품',
                'verbose_name_plural': '상품 복수',
                'db_table': 'basic_product',
            },
        ),
    ]

id는 해당 모델의 primary Key로 자동 사용되는 값이었으며, Model Meta Option에서 ordering = ['-order_date']와 같이 default ordering for the object(for use when obtaining lists of objects)를 지정해주지 않으면 자동으로 primary key를 기준으로 데이터를 가져온다고 추정할 수 있었다.

의문점을 공식 다큐먼트를 통해 확인해가며 해소하려다보니 생각보다 시간이 많이 소요됐다. 앞으로 항상 이렇게 의문점을 다큐먼트를 통해 확인하기는 시간상 쉽지 않겠지만 이런 과정들이 쌓일수록 프레임워크 자체에 대한 이해도가 높아지는 것 같다.

좋은 웹페이지 즐겨찾기