Django

Django 실습(8) RDB(관계형 데이터베이스) 만들어보기

UserDonghu 2023. 10. 17. 23:11

RDB : Relational DataBase. 테이블을 통해 데이터 집합을 표현하는 방식의 데이터베이스.

- 계층형 데이터베이스 (1:N)

- 망형 데이터베이스 (N:M)

 


실습

tutorialdjango 프로젝트를 만들고, startapp blog후, settings.py를 수정해준다.

 

DB 모델 설계

 

blog / models.py 에 모델 구현

구현 후 makemigrations, migrate 하기

from django.db import models
from django.contrib.auth.models import User # User 모델을 import

class Post(models.Model):
    title = models.CharField(max_length=100)
    content = models.TextField()
    head_image = models.ImageField(
        upload_to='blog/images/%Y/%m/%d/', blank=True)
    file_upload = models.FileField(
        upload_to='blog/files/%Y/%m/%d/', blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateField(auto_now=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE) # 1:N 관계. on_delete=models.CASCADE : 유저가 지워지면 게시글들도 모두 지워진다.
    tags = models.ManyToManyField('Tag', blank=True) # N:M 관계. 한곳에만 정의하면 된다

    def __str__(self):
        return self.title
    
class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments') # 1:N 관계. related_name : Post에서 Comment를 부를때 사용할 이름
    message = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateField(auto_now=True)
    author = models.ForeignKey(User, on_delete=models.CASCADE) # 1:N 관계.
    
    def __str__(self):
        return self.message
    
class Tag(models.Model):
    name = models.CharField(max_length=10, unique=True)
    
    def __str__(self):
        return self.name

 

blog / admin.py 수정

admin계정을 생성 후, admin페이지에서 테스트

from django.contrib import admin
from .models import Post, Comment, Tag

admin.site.register(Post)
admin.site.register(Comment)
admin.site.register(Tag)

 

tutorialdjango / urls.py 수정

from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path("admin/", admin.site.urls),
    path("blog/", include('blog.urls')),
]

 

blog / urls.py 추가

from django.urls import path
from . import views

app_name = 'blog'

urlpatterns = [
    path('', views.postlist, name='postlist'),
    path('<int:pk>/', views.postdetail, name='postdetail'),
    path('tag/<str:tag>/', views.posttag, name='posttag'),
]

 

blog / forms.py 추가

댓글폼 생성

from django import forms
from .models import Comment

class CommentForm(forms.ModelForm):
    
    class Meta:
        model = Comment
        fields = ("message")

 

blog / views.py 수정

from django.shortcuts import render
from .models import Post, Comment, Tag
from .forms import CommentForm
from django.db.models import Q

def postlist(request):
    if request.GET.get('q'): # get요청의 q가 있으면
        q = request.GET.get('q')
        posts = Post.objects.filter(Q(title__icontains=q)|Q(content__icontains=q)|Q(comments__message__icontains=q)).distinct() # comments__message :model에서 related_name으로 설정한 comments인 Comment모델의 message필드
    else:
        posts = Post.objects.all()
    return render(request, 'blog/postlist.html', {'posts':posts})

def postdetail(request, pk):
    post = Post.objects.get(pk=pk)
    form = CommentForm() # 댓글폼
    if request.method == 'POST': # Post 요청이 들어오면
        form = CommentForm(request.POST)
        if form.is_valid():
            comment = form.save(commit=False) # DB에는 저장하지않는 임시 form으로 저장
            comment.author = request.user # author에 request.user 할당
            comment.post = post # 해당 댓글이 속하는 post 설정
            comment.save() # DB에 저장
    return render(request, 'blog/postdetail.html', {'post':post, 'form':form})

def posttag(request, tag):
    posts = Post.objects.filter(tags__name__iexact=tag) # tags모델의 name필드가 tag와 완벽하게 일치하는것들
    return render(request, 'blog/postlist.html', {'posts':posts})

 

blog / templates / blog / postlist. html, posdetail.html 추가

<!-- postlist.html -->
<form action="" method="GET">
    <input type="text" name="q">
    <button type="submit">검색</button>
</form>
{% for i in posts %}
    <h1><a href="{% url 'blog:postdetail' i.pk%}">{{ i.title }}</a></h1>
    <p>{{ i.content }}</p>
    <p>{{ i.author }}</p>
    <!-- 관계형 모델에서 접근할때는 all 사용 -->
    {% for comment in i.comments.all %}
        <p>{{ comment.message }}</p>
    {% endfor %}
    {% for tag in i.tags.all %}
        <p>{{ tag.name }}</p>
    {% endfor %}
    <hr>
{% endfor %}

 

<!-- postdetail.html -->
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<p>{{ post.author }}</p>

{% for comment in post.comments.all %}
    <p>{{ comment.message }}</p>
{% endfor %}
{% for tag in post.tags.all %}
    <a href="{% url 'blog:posttag' tag.name %}">#{{ tag.name }}</a>
{% endfor %}

<form action="" method="post">
    {% csrf_token %}
    {{ form }}
    <input type="submit">
</form>