반응형
M:N 관계
ex) 의사-환자 모델링
- models.py
from django.db import models
# Create your models here.
class Doctor(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return f'{self.pk}번 의사 {self.name}'
class Patient(models.Model):
name = models.CharField(max_length=20)
def __str__(self):
return f'{self.pk}번 환자 {self.name}'
class Reservation(models.Model):
doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
patient = models.ForeignKey(Patient, on_delete=models.CASCADE)
def __str__(self):
return f'{self.doctor}의 {self.patient}'
- shell_plus
In [1]: doctor = Doctor.objects.create(name='KIM')
In [2]: patient = Patient.objects.create(name='TOM')
In [3]: doctor
Out[3]: <Doctor: 1번 의사 KIM>
In [4]: patient
Out[4]: <Patient: 1번 환자 TOM>
# reservation을 활용해서 의사와 환자를 연결한다.
In [5]: Reservation.objects.create(doctor=doctor, patient=patient)
Out[5]: <Reservation: 1번 의사 KIM의 1번 환자 TOM>
# 의사 입장에서 예약정보를 가져오기
# 1은 N을 보장할 수 없기 때문에
In [6]: doctor.reservation_set.all()
Out[6]: <QuerySet [<Reservation: 1번 의사 KIM의 1번 환자 TOM>]>
# 환자 입장에서 예약정보를 가져오기
In [7]: patient.reservation_set.all()
Out[7]: <QuerySet [<Reservation: 1번 의사 KIM의 1번 환자 TOM>]>
# 2번환자 생성하고 연결하기
In [8]: patient2 = Patient.objects.create(name='KANG')
In [9]: Reservation.objects.create(doctor=doctor, patient=patient2)
Out[9]: <Reservation: 1번 의사 KIM의 2번 환자 KANG>
In [10]: doctor.reservation_set.all()
Out[10]: <QuerySet [<Reservation: 1번 의사 KIM의 1번 환자 TOM>, <Reservation: 1번 의사 KIM의 2번 환자 KANG>]>
# 의사1의 환자이름
In [11]: for reservation in doctor.reservation_set.all():
...: print(reservation.patient.name)
...:
TOM
KANG
# 의사1의 환자번호
In [12]: for reservation in doctor.reservation_set.all():
...: print(reservation.patient.pk)
...:
1
2
- 위의 중개모델 말고도 조금 더 쉽게 가져올 수 있는 방법이 존재한다.(ManyToManyField)
# 환자 입장에서 의사 가져오기
In [1]: patient = Patient.objects.get(pk=1)
In [2]: patient.doctors.all()
Out[2]: <QuerySet [<Doctor: 1번 의사 KIM>]>
# 의사 입장에서 환자 가져오기
doctor = Doctor.objects.get(pk=1)
In [10]: doctor.patient_set.all()
Out[10]: <QuerySet [<Patient: 1번 환자 TOM>, <Patient: 2번 환자 KANG>]>
# 이제는 patient_set.all()로 가져올 수 없고 지정한 patients로만 가져올 수 있다.
In [1]: doctor = Doctor.objects.get(pk=1)
In [2]: doctor.patients.all()
Out[2]: <QuerySet [<Patient: 1번 환자 TOM>, <Patient: 2번 환자 KANG>]>
= > relate_name을 쓸거면 reservation 클래스가 필요없다.
In [1]: doctor = Doctor.objects.create(name='KIM')
In [2]: patient = Patient.objects.create(name='TOM')
# 환자 추가
In [3]: doctor.patients.add(patient)
# 환자 제거
In [4]: doctor.patients.remove(patient)
In [5]: doctor.patients.all()
Out[5]: <QuerySet []>
!! 추가 필드가 요구될 시에는 중개모델(ex. Reservaion class)을 만들어줘야한다.!!
- 언제 related_name이 반드시 필요한가?
- ?
게시글 좋아요 만들기
# urls.py
path('<int:article_pk>/like/', views.like, name="like"),
# views.py
@login_required
def like(request, article_pk):
# 특정 게시물에 대한 정보
article = get_object_or_404(Article, pk=article_pk)
# 좋아요를 누른 유저에 대한 정보
user = request.user
# 사용자가 게시글의 좋아요 목록에 있으면 지우고 없으면 추가한다.
if user in article.like_users.all():
article.like_users.remove(user)
else:
article.like_users.add(user)
return redirect('articles:index')
# index.html
{% if user in article.like_users.all %}
<a href="{% url 'articles:like' article.pk %}"> 좋아요 취소 </a>
{% else %}
<a href="{% url 'articles:like' article.pk %}"> 좋아요 </a>
{% endif %}
- font awesome 사용하기
- base.html에 Kit code를 붙여넣는다.
- 좋아요를 하나의 모듈로 만들기
# _like.html
{% if user in article.like_users.all %}
<a href="{% url 'articles:like' article.pk %}"> 좋아요취소<i class="fas fa-thumbs-down"></i> </a>
{% else %}
<a href="{% url 'articles:like' article.pk %}"> 좋아요<i class="fas fa-thumbs-up"></i> </a>
{% endif %}
</div>
<div class="col-lg-2">
{% if user in article.recommend_users.all %}
<a href="{% url 'articles:recommend' article.pk %}"> 추천 취소 </a>
{% else %}
<a href="{% url 'articles:recommend' article.pk %}"> 추천 </a>
{% endif %}
# index.html
## 넣고 싶은 부분에 include를 이용
{% include 'articles/_like.html' %}
프로필만들기
# urls.py
path('<str:username>/', views.profile, name="profile"),
# views.py
from django.shortcuts import get_object_or_404
from django.contrib.auth import get_user_model
def profile(request, username):
person = get_object_or_404(get_user_model(), username=username)
context={
'person' : person
}
return render(request, 'accounts/profile.html', context)
# profile.html
{% extends 'base.html' %}
{% block body %}
<h3>{{ person.username }}</h3>
<!-- 유저가 작성한 모든 게시물 -->
<p>유저가 작성한 게시글들</p>
<ul>
{% for article in person.article_set.all %}
<li>{{ article.title }}</li>
<li>{{ article.content }}</li>
{% endfor %}
</ul>
<p>유저가 작성한 게시글들</p>
<ul>
{% for comment in person.comment_set.all %}
<li>{{ comment.content }}</li>
{% empty %}
<p>댓글을 단 적이 없습니다.</p>
{% endfor %}
</ul>
<p>유저가 좋아요 누른 게시글들</p>
<ul>
{% for comment in person.like_articles.all %}
<li>{{ like.content }}</li>
{% empty %}
<p>좋아요를 누른 적이 없습니다.</p>
{% endfor %}
</ul>
{% endblock %}
팔로우하기
get_user_model
vsAUTH_USER_MODEL
- 전자는 객체를 반환하기때문에 accounts를 바라보게된다? => 활성화된 객체를 찾아간다.
- 후자는 스트링값 반환=> migrations -> migrate 과정에서 문자열이기 때문에 원활하게 진행
- articles에 있는 models.py에서는 AUTH_USER_MODEL을 사용
- accounts에 있는 models.py에서는 get_user_model을 사용
- Models.py에서 정의할 때 빼고는 전부 get_user_model을 사용하면된다!!
# admin.py ( accounts )
###### ^^^^^^ 여기서만 예외 ########
from django.contrib.auth.admin import UserAdmin
from .models import User
admin.site.register(User, UserAdmin)
# models.py ( accounts )
from django.db import models
from django.conf import settings
from django.contrib.auth.models import AbstractUser
# Create your models here.
class User(AbstractUser):
followers = models.ManyToManyField(
settings.AUTH_USER_MODEL,
related_name="followings",
blanck=True
)
- 추가로 forms.py도 커스터마이징해줘야한다!!
# forms.py ( accounts )
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = get_user_model()
# fileds =
# views.py ( accounts )
from .forms import CustomUserCreationForm
UserCreationForm.Meta를 써주면 기존에 있는 Meta를 쓰기때문에 필드를 생략해도 된다.
# 기존 에서
def signup(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
user = form.save()
auth_login(request, user)
return redirect('articles:index')
else:
form = UserCreationForm()
context = {
'form' : form
}
return render(request, 'accounts/signup.html', context)
# 이렇게 바꾼다.
def signup(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
auth_login(request, user)
return redirect('articles:index')
else:
form = CustomUserCreationForm()
context = {
'form' : form
}
return render(request, 'accounts/signup.html', context)
# accounts/urls.py
urlpatterns = [
path('signup/', views.signup, name="signup"),
path('login/', views.login, name="login"),
path('logout', views.logout, name="logout"),
path('delete/', views.delete, name="delete"),
path('update/', views.update, name="update"),
path('password/', views.password, name="password"),
path('follow/<int:user_pk>/', views.follow, name="follow"), # 여기에 추가했다
path('<str:username>/', views.profile, name="profile"), # 문자열 하나만 받을 친구는 밑에 둬야한다.(오류생김)
]
# accounts/views.py
def follow(request, user_pk):
# person에 담긴 user_pk값을 가진 유저는
# 프로필의 주인이다.
# request.user는 나. 요청을 보내온 사용자이다
person = get_object_or_404(get_user_model(), pk=user_pk)
if request.user in person.followers.all():
person.followers.remove(request.user)
else :
person.followers.add(request.user)
return redirect('accounts:profile',person.username)
<!--profile.html-->
{% extends 'base.html' %}
{% block body %}
<h3>{{ person.username }}</h3>
<!-- 팔로우 로직 구현-->
{% if user != person %} <!-- 본인일때는 팔로우 안보이도록-->
{% if user in person.followers.all %}
<a href="{% url 'accounts:follow' person.pk %}">팔로우 취소</a>
{% else %}
<a href="{% url 'accounts:follow' person.pk %}">팔로우</a>
{% endif %}
{% endif %}
...
...
...
DB다 지우고 makemigrations와 migrate한다
페이징 구현
# articles/views.py
from django.core.paginator import Paginator
def index(request): #index 부분을 수정한다.(paging 추가)
#embed()
articles = Article.objects.all()
# 1. Paginator(전체 리스트, 한 페이지당 개수)
paginator = Paginator(articles, 3)
# 2. 몇 번째 페이지를 보여줄 것인지 GET으로 받
# 'articles/?page=3'
page = request.GET.get('page')
# 해당하는 페이지의 게시글만 가져오기
articles = paginator.get_page(page)
context = {
'articles': articles
}
return render(request, 'articles/index.html', context)
- index.html
{% extends 'base.html' %}
{% block body %}
<h1>메인 페이지 입니다.</h1>
<hr>
<a href="{% url 'articles:create' %}">[CREATE]</a>
<hr>
<p>{{ articles.all|length }}개의 글</p>
<hr>
{% for article in articles %}
<p>{{ article.pk }}번째 글</p>
<h2>{{ article.title }}</h2>
<p>좋아요 개수 : {{ article.like_users.all|length }}</p>
<p>추천 개수 : {{ article.recommend_users.all|length }}</p>
<p>댓글 개수 : {{ article.comment_set.all|length }}</p>
<div class="container">
<div class="row">
<div class="col-lg-2">
{% include 'articles/_like.html' %}
</div>
<div class="col-lg-2">
<a href="{% url 'articles:detail' article.pk %}">[DETAIL]</a>
</div>
</div>
</div>
<hr>
{% endfor %}
{% for num in articles.paginator.page_range %}
<a href="{% url articles:index' %}?page={{ num }}">{{ num }}</a>
{% endfor %}
{% endblock %}
아이디 2개를 만들어 주소로 내 아이디 말고 다른 사람 아이디를 들어가보면
반응형
'웹 프로그래밍 > [ Django ]' 카테고리의 다른 글
[ Django ] 08. Django에서 JavaScript 이용하여 좋아요 구현하기 (1) | 2020.08.11 |
---|---|
[ Django ] 06. Django relation 1:N 복습 (0) | 2020.08.11 |
[ Django ] 05. Django relation 1:N (사용자 분할) (0) | 2020.08.11 |
[ Django ] 04. Django 로그인/회원가입 구현 (0) | 2020.08.11 |
[ Django ] 03. Django Model-Form 알아보기 (0) | 2020.08.11 |