1:N

hey hey·2021년 12월 7일
0

Django

목록 보기
4/9
post-thumbnail
* articles/models

class Comment(models.Model):
    **article = models.ForeignKey(Article, on_delete=models.CASCADE)**
    content = models.CharField(max_length=200)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return self.content

article이라는 이름으로 만들면 DB에는 article_id 라는 번호가 저장된다

on_delete 옵션

  • CASCADE ⇒ 부모가 삭제 됐을 때, 이를 참조하는 객체도 삭제

댓글 작성해보기

* python manage.py shell_plus

In [1]: comment = Comment()
In [2]: comment.content ='first comment'
In [3]: comment.save()  ----> error (NOT NULL)
-------------------------------------------------------------
In [4]: article = Article.objects.create(title='title',content='content')
In [7]: comment.article = article
In [8]: comment.save()

In [9]: comment
Out[9]: <Comment: first comment>

두번째 댓글 쓰기

In [10]: comment = Comment(content='second comment',article=article)
In [11]: comment.save()

In [12]: comment.pk
Out[12]: 2

Admin 등록하기

* articles/admin.py
 admin.site.register(Comment)

역참조

article.comment 형태로 사용이 불가
article.comment_set manager가 생성됨

In [1]: article = Article.objects.get(pk=1)

In [2]: article
Out[2]: <Article: title>

In [4]: article.**comment_set**.all()
Out[4]: <QuerySet [<Comment: first comment>, <Comment: second comment>]>

귀찮다 이름을 바꾸자

* articles/models
class Comment(models.Model):
    article = models.ForeignKey(Article, on_delete=models.CASCADE**,related_name='comments'**)

CommentsForm 작성

* articles/forms.py
class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        fields = '__all__'
* articles/views.py
from .forms import CommentForm
def detail(request, pk):
    article = get_object_or_404(Article, pk=pk)
    comment_form = CommentForm()
    context = {
        'article': article,
        'comment_form':comment_form
    }
    return render(request, 'articles/detail.html', context)

??? 1번글에 들어왔는데 2번글 댓글을 작성가능?

* articles/forms.py
class CommentForm(forms.ModelForm):
    class Meta:
        model = Comment
        # fields = '__all__'
        exclude =('article',)

⭐ comments_create

* articles/views
@require_POST
def comments_create(request,pk):
    if request.is_authenticated:
        article =get_object_or_404(Article,pk=pk)
        comment_form = CommentForm(request.POST)
        if comment_form.is_valid():
            **comment = comment_form.save(commit=False)
            comment.article = article
            comment.save()**
        return redirect('articles:detail',article.pk)
    return redirect('accounts:login')

commit =False

→ 아직 데이터베이스에 저장되지 않은 인스턴스를 반환

→ 저장하기 전에 객체에 대한 사용자 지정 처리를 수행할 때 유용

* articles/views 
@require_safe
def detail(request, pk):
    article = get_object_or_404(Article, pk=pk)
    comment_form = CommentForm()
    comments = article.comment_set.all()
    context = {
        'article': article,
        'comment_form':comment_form,
        'comments':comments,
    }
    return render(request, 'articles/detail.html', context)

댓글 삭제하기

* articles/urls.py

path('<int:article_pk>/comments/<int:comment_pk>/delete',views.comments_delete,name='comments_delete'),
* articles/views.py
@require_POST
def comments_delete(request,article_pk,comment_pk):
    if request.is_authenticated:
        comment = get_object_or_404(Comment,pk=comment_pk)
        comment.delete()
    return redirect('articles:detail',**article_pk**)

article의 pk로 돌아가고 싶은데 comment에서 그것을 가져오기는 어렵다

→ url에서 pk값을 comment pk 와 article pk 두개를 들고오게 한다.

* articles/detail.html
<h4>**댓글 목록**</h4>
  <ul>
    {% for comment in comments %}
      <li>
        {{comment.content}}
				**댓글 삭제**
        <form action="{% url 'articles:comments_delete' article.pk comment.pk %}"method='POST' class='d-inline'>
          {% csrf_token %}
          <input type="submit" value='DELETE'>
        </form>
      </li>
    {% endfor %}
  </ul>

	<h4>**댓글 작성**</h4>
  <form action="{% url 'articles:comments_create' article.pk %}" method ='POST'>
    {% csrf_token %}    
    {{ comment_form}}
    <input type="submit">
  </form>

댓글개수 출력

* detail.html
<h4>댓글 목록</h4>
{% if comments %}
  <p><b>{{comments|length}}개의 댓글이 있습니다.</b></p>
{% endif %}

{% empty %}    없을때는 for 문 사이에
  <p>댓글이 없어요</p>

User 모델 대체하기

내장 User 모델이 제공하는 인증 요구사항이 적절하지 않을 수 있다.

커스텀 유저 모델을 초기에 설정하는 것을 권장한다

* settings.py 
AUTH_USER_MODEL = 'accounts.User'  (맨밑)
* accounts/models.py
from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    pass

Custom을 하지 않더라도 반드시 하는 것을 권장한다.

* accounts/admin.py 
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .models import User
# Register your models here.

admin.site.register(User,UserAdmin)

UserCreationForm , UserChangeForm

기존 내장 User 모델을 사용했기에 무조건 수정해서 사용해야한다.

* accounts/forms.py
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.contrib.auth import get_user_model

class CustomUserChangeForm(UserChangeForm):
    class Meta:
        model = get_user_model()
        fields = ('email', 'first_name', 'last_name',)

class CustomUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        model = get_user_model()
        fields= UserCreationForm.Meta.fields+('email',)
* accounts/view.py에서 form을 다 바꿔줘야한다
**-> form = CustomUserCreationForm()
-> form = CustomUserChangeForm()**

get_user_model()

현재 프로젝트에서 활성화된 사용자 모델을 반환 == User?

  • User 모델을 커스터마이징한 상황→ Custom User 모델을 반환

get_user_model() 을 써야한다

→ 또한 유연성이 달라진다 (변경사항)

profile
FE - devp

0개의 댓글