장고로 DB연동해서 데이터를 화면에 보여주자

포스트 목록을 볼 수 있도록 하기 위해서는 데이터베이스 모델 설정, 데이터베이스 마이그레이션, 그리고 뷰와 템플릿 설정이 필요합니다. 아래 단계에 따라 설정을 진행해보세요.

1. 데이터베이스 모델 설정

models.py 파일에서 Post 모델을 정의합니다.

# mysite/models.py
from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100)
    body = models.TextField()

    def __str__(self):
        return self.title

2. 데이터베이스 마이그레이션

새로운 모델을 데이터베이스에 반영하기 위해 마이그레이션을 수행합니다.

python manage.py makemigrations
python manage.py migrate

에러가 발생할 수 있습니다. 저의 경우에는 아래와 같은 오류가 발생했습니다.

➜  mysite python manage.py makemigrations
Traceback (most recent call last):
  File "manage.py", line 22, in <module>
    main()
  File "manage.py", line 18, in main
    execute_from_command_line(sys.argv)
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
    utility.execute()
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/core/management/__init__.py", line 413, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/core/management/base.py", line 354, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/core/management/base.py", line 393, in execute
    self.check()
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/core/management/base.py", line 423, in check
    databases=databases,
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/core/checks/registry.py", line 76, in run_checks
    new_errors = check(app_configs=app_configs, databases=databases)
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/core/checks/urls.py", line 13, in check_url_config
    return check_resolver(resolver)
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/core/checks/urls.py", line 23, in check_resolver
    return check_method()
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/urls/resolvers.py", line 416, in check
    for pattern in self.url_patterns:
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/urls/resolvers.py", line 602, in url_patterns
    patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/utils/functional.py", line 48, in __get__
    res = instance.__dict__[self.name] = self.func(instance)
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/urls/resolvers.py", line 595, in urlconf_module
    return import_module(self.urlconf_name)
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/importlib/__init__.py", line 127, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
  File "<frozen importlib._bootstrap>", line 983, in _find_and_load
  File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 728, in exec_module
  File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
  File "/Users/xxx/Projects/django/mysite/mysite/urls.py", line 19, in <module>
    from . import views
  File "/Users/xxx/Projects/django/mysite/mysite/views.py", line 11, in <module>
    from .models import Post
  File "/Users/xxx/Projects/django/mysite/mysite/models.py", line 4, in <module>
    class Post(models.Model):
  File "/Users/xxx/.pyenv/versions/3.7.17/lib/python3.7/site-packages/django/db/models/base.py", line 116, in __new__
    "INSTALLED_APPS." % (module, name)
RuntimeError: Model class mysite.models.Post doesn't declare an explicit app_label and isn't in an application in INSTALLED_APPS.

대충 마지막 라인을 보니 명시적인 앱라벨이 정의되지 않은 것 같습니다.

# mysite/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'mysite', # 요거 추가
]

다시 명령어를 실행해봅니다.

➜  mysite python manage.py makemigrations
No changes detected
mysite python manage.py migrate       
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, sessions
Running migrations:
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying admin.0003_logentry_add_action_flag_choices... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying auth.0008_alter_user_username_max_length... OK
  Applying auth.0009_alter_user_last_name_max_length... OK
  Applying auth.0010_alter_group_name_max_length... OK
  Applying auth.0011_update_proxy_permissions... OK
  Applying auth.0012_alter_user_first_name_max_length... OK
  Applying sessions.0001_initial... OK

3. 관리자 인터페이스 설정 (선택 사항)

Django 관리자 인터페이스에서 데이터를 관리할 수 있도록 admin.py 파일을 설정합니다.

# mysite/admin.py
from django.contrib import admin
from .models import Post

admin.site.register(Post)

관리자 계정을 생성합니다.

python manage.py createsuperuser

아래와 같이 진행됩니다.

➜  mysite python manage.py createsuperuser
Username (leave blank to use 'xxx'): admin
Email address: xxx@gmail.com
Password: 
Password (again): 
Superuser created successfully.

4. 포스트 목록 보기

views.py 파일에서 post_list 뷰를 정의합니다.

# mysite/views.py
from django.shortcuts import render
from .models import Post

def post_list(request):
    posts = Post.objects.all()
    return render(request, 'post_list.html', {'posts': posts})

urls.py 파일을 수정하여 post_list 뷰를 연결합니다.

# mysite/urls.py
from django.contrib import admin
from django.urls import path
from . import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('posts/', views.post_list, name='post_list'),
    path('search/', views.search_results, name='search_results'),  # 검색 뷰 추가
]

5. 템플릿 파일 생성

templates 폴더에 post_list.html 파일을 생성하고 다음 내용을 추가합니다.

<!-- templates/post_list.html -->
<html>
<head>
    <title>Post List</title>
</head>
<body>
    <h1>Post List</h1>
    <ul>
        {% for post in posts %}
        <li>
            <h2>{{ post.title }}</h2>
            <p>{{ post.body }}</p>
        </li>
        {% endfor %}
    </ul>
</body>
</html>

검색 폼을 위한 search_form.html 파일도 생성합니다.

<!-- templates/search_form.html -->
<form method="GET" action="{% url 'search_results' %}">
    <input type="text" name="q" placeholder="Search...">
    <button type="submit">Search</button>
</form>

검색 결과를 보여줄 search_results.html 파일을 생성합니다.

<!-- templates/search_results.html -->
<html>
<head>
    <title>Search Results</title>
</head>
<body>
    <h1>Search Results</h1>
    <ul>
        {% for post in results %}
        <li>
            <h2>{{ post.title }}</h2>
            <p>{{ post.body }}</p>
        </li>
        {% endfor %}
    </ul>
</body>
</html>

6. 검색 뷰 정의

views.py 파일에서 검색 결과를 처리하는 search_results 뷰를 정의합니다.

# mysite/views.py
from django.db.models import Q
from .models import Post

def search_results(request):
    query = request.GET.get('q')
    results = Post.objects.filter(Q(title__icontains=query) | Q(body__icontains=query))
    return render(request, 'search_results.html', {'results': results})

7. 서버 실행

이제 모든 설정이 완료되었습니다. 서버를 실행하여 포스트 목록과 검색 기능을 확인할 수 있습니다.

python manage.py runserver

브라우저에서 http://localhost:8000/posts/에 접속하여 포스트 목록을 확인하고, http://localhost:8000/search/에 접속하여 검색 기능을 테스트해보세요.

테이블이 없다고 에러가 나올수 있다. 그럴땐 아래 파일을 생성하고 명시적으로 마이그레이션을 한번더 해본다.

# mysite/apps.py
from django.apps import AppConfig

class MysiteConfig(AppConfig):
    name = 'mysite'

그리고 다시 마이그레이션을 수행한다.

➜  mysite python manage.py makemigrations mysite
Migrations for 'mysite':
  mysite/migrations/0001_initial.py
    - Create model Post
➜  mysite python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, contenttypes, mysite, sessions
Running migrations:
  Applying mysite.0001_initial... OK

그리고 다시 사이트에 접속하면,

끗!