render(request, template_name, context=None, ...)
request
와 template_name(html 파일명)
은 필수작성 사항화면에 html 파일을 띄우는 것
이라 생각하면 됨!context
: 화면에 원하는 인자를 띄워줌.딕셔너리 형태
로 사용하며 {html에서 사용할 이름 : views.py에서의 변수명}
과 같이 작성redirect(url 주소, permanent=False, **args, ***kwargs)
주어진 url로 이동
하는 것이므로(상대 / 절대 모두 가능) render와 같이 원하는 값들은 넘기지 못한다.render
는 html 파일로 이동하고, redirect
는 url을 통해 이동하는 것이다.urls.py에 url이 등록되어 있어야 한다
는 점이와 맞물린 함수가 있다
는 점해당 함수는 views.py에서 선언
이 되어 있어야 한다는 점해당 함수 안에서 render를 할 것인지 redirect를 할 것인지
결정할 수 있다는 점한 명의 글쓴이가 여러 개의 글을 보유
하고 있을 수는 있지만, 하나의 글이 여러 명의 글쓴이를 보유할 수 없는
것이다.mySpartaSns
에서는 모델을 생성할 때 사용한 ForeignKey
가 이에 해당한다. 아래의 코드를 한 번 보도록 하겠다. class UserModel(AbstractUser):
class Meta:
db_table = "my_user"
bio = models.TextField(max_length=500, blank=True)
class TweetModel(models.Model):
class Meta:
db_table = "tweet"
author = models.ForeignKey(UserModel, on_delete=models.CASCADE)
content = models.CharField(max_length=256)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
class TweetComment(models.Model):
class Meta:
db_table = "comment"
tweet = models.ForeignKey(TweetModel, on_delete=models.CASCADE)
author = models.ForeignKey(UserModel, on_delete=models.CASCADE)
comment = models.CharField(max_length=256)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
my_user
모델은 사용자를 정의하는 모델인데, 지금 보면 tweet
과 comment
모델에서 모두 author
라는 변수명으로 my_user
의 모든 내용을 가져다 쓰고 있다. 한 명의 사용자가 다수의 게시글과 댓글을 보유
하게 된다. one-to-many
관계가 성립된다. tweet
이랑 comment
모델도 one-to-many
관계가 성립된다!중복되지 않는 값을 발생
시키는 것이다.프로필
기능인것 같다. 물론 요즘에는 멀티 프로필이 가능하지만, 결국 하나의 아이디에 하나의 프로필
인 것은 똑같으니 적당한 예시라고 생각한다. OneToOneField
를 사용해 작성하게 된다. class UserModel(AbstractUser):
class Meta:
db_table = "my_user"
bio = models.TextField(max_length=500, blank=True)
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
user_pk = models.IntegerField(blank=True)
nickname = models.CharField(max_length=200, blank=True)
point = models.IntegerField(default=0)
phone = models.CharField(max_length=200, blank=True)
서로 n개씩
의 관계를 가질 수 있다.ManyToManyField
를 사용한다. 서로 n개씩
이라면서 왜 한 쪽에만 ManyToManyField
을 쓰냐고 생각할 수 있다. django에서는 한 쪽에만 입력해주면 알아서 다 해주니 걱정할 필요 없다.class MyTopping(models.Model):
topping_name = models.CharField(max_length=100)
class MyPizza(models.Model):
pizza_name = models.CharField(max_length=100)
pizza_topping = models.ManyToManyField(MyTopping)
restaurant
app을 생성하였다. $ django-admin startapp restaurant
mySpartaSns/settings.py
로 가서 내가 설치한 app이 무엇인지 django에게 알려주도록 하겠다. #### mySpartaSns/settings.py ####
# 상단 생략
INSTALLED_APPS = [
# 우리가 생성한 app 추가
'user',
'tweet',
'restaurant',
# django의 기본 app
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
# 하단 생략
restaurant/models.py
에 실습에 사용할 모델들을 만들도록 하겠다. # restaurant/models.py
from django.db import models
class MyTopping(models.Model):
class Meta:
db_table = "my_topping"
def __str__(self):
return self.topping_name
topping_name = models.CharField(max_length=100)
class MyPizza(models.Model):
class Meta:
db_table = "my_pizza"
def __str__(self):
return self.pizza_name
pizza_name = models.CharField(max_length=100)
pizza_topping = models.ManyToManyField(MyTopping)
$ python manage.py makemigrations
$ python manage.py migrate
resaturant/admin.py
에 등록하도록 하겠다. #### resaturant/admin.py ####
from django.contrib import admin
from .models import MyPizza, MyTopping
admin.site.register(MyPizza)
admin.site.register(MyTopping)
$ python manage.py createsuperuser
http://127.0.0.1:8000/admin
db.sqlite3
삭제migrations
폴더에서 __init__.py
파일을 제외한 다른 2 개의 파일을 전부 삭제데이터베이스 창
에 나와있는 데이터베이스도 모두 다 삭제auth_user
를 끌어다 쓰면서 관리자에 대한 제대로된 세팅이 이루어지지 않았기 때문
이며, 그래서 지우고 다시 세팅을 진행다시 db를 생성
하면 된다. $ python manage.py makemigrations
$ python manage.py migrate
db.sqlite3
가 다시 생기게 되고, 이거를 오른쪽의 데이터베이스 창에 드래그
해주면 다시 생성이 된다.$ python manage.py createsuperuser
My pizza
로 가서 피자를 만들어 보도록 하겠다.django를 실행하지 않고도
기능들을 사용할 수 있도록 도와주는 도구$ python manage.py shell
피자의 입장
에서 자신에게 들어가 있는 모든 토핑 불러오기restaurant
app에 있는 모델 중 MyTopping, MyPizza
사용MyPizza
안에 있는 모든 object를 불러옴MyPizza
중 이름이 domino
인 것을 불러옴papajones
인 피자에 추가되어 있는 topping
들을 전부 불러옴1 >>> from restaurant.models import MyTopping, MyPizza
2 >>> MyPizza.objects.all()
<QuerySet [<MyPizza: domino>, <MyPizza: pizzahut>, <MyPizza: papajones>]>
3 >>> MyPizza.objects.get(pizza_name='domino')
<MyPizza: domino>
4 >>> MyPizza.objects.get(pizza_name='papajones').pizza_topping.all()
<QuerySet [<MyTopping: cheese>, <MyTopping: pepparoni>, <MyTopping: onion>]>
토핑의 입장
에서 본인이 들어간 모든 피자 불러오기restaurant
app에 있는 모델 중 MyTopping, MyPizza
사용MyTopping
안에 있는 모든 object를 불러옴MyTopping
중 이름이 cheese
인 것을 불러옴MyTopping
중 cheese
가 포함된 모든 피자 불러옴MyTopping
중 pepparoni
가 포함된 모든 피자 불러옴1 >>> from restaurant.models import MyTopping, MyPizza
2 >>> MyTopping.objects.all()
<QuerySet [<MyTopping: cheese>, <MyTopping: pepparoni>, <MyTopping: onion>, <MyTopping: cow>, <MyTopping: chicken>, <MyTopping: shirimp>, <MyTopping: olive>]>
3 >>> MyTopping.objects.get(topping_name='cheeze')
<MyTopping: cheese>
4 >>> MyTopping.objects.get(topping_name='cheese').mypizza_set.all()
<QuerySet [<MyPizza: domino>, <MyPizza: pizzahut>, <MyPizza: papajones>]>
5 >>> MyTopping.objects.get(topping_name='pepparoni').mypizza_set.all()
<QuerySet [<MyPizza: pizzahut>, <MyPizza: papajones>]>
many-to-many
관계를 사용해서 작성해보자.#### user/models.py ####
from django.db import models
# django에서 기본적으로 제공하는 auth_user와 연동되는 클래스인 AbstractUser 사용
from django.contrib.auth.models import AbstractUser
# django가 관리하는 곳(메인 app)에 있는 settings를 불러옴
from django.conf import settings
# 내가 생성한 user model
class UserModel(AbstractUser):
# 데이터베이스에 반영되는 model의 이름 작성
class Meta:
db_table = "my_user"
# auth_user에 있는 내용들을 다 지워줌
# 상태 메세지
bio = models.CharField(max_length=256, default='')
# follow 모델
# 내가 팔로우하는 사람은 다른 모델이 아닌 사용자 모델에 있는 사용자이기 때문에 AUTH_USER_MODEL을 가져다 씀
# AUTH_USER_MODEL : 우리가 튜닝한 유저 모델이고 djangoProject/settings.py의 가장 아래부분에 우리가 추가했엄
# 내가 팔로우하는 사람들의 명단이 follow 안에 들어가는 것이고, 그 사람들 입장에서는 내가 followee가 된다.
# UserModel.followee : UserModel을 팔로우하는 사람들을 불러줌
# UserModel.follow : 내가 팔로우하는 사람들을 불러줌
follow = models.ManyToManyField(settings.AUTH_USER_MODEL,related_name='followee')
$ python manage.py makemigrations
$ python manage.py migrate
many-to-many
관계의 경우 참조할 것이 많다보니 자동적으로 생기는 것이므로 신경쓸 필요 없다. @login_required
def user_view(request):
if request.method == 'GET':
# exclude : 해당하는 데이터에서 조건에 맞는 데이터를 제거해주는 함수
# 사용자를 불러오기, exclude와 request.user.username 를 사용해서 '로그인 한 사용자'를 제외하기
user_list = UserModel.objects.all().exclude(username=request.user.username)
return render(request, 'user/user_list.html', {'user_list': user_list})
@login_required
def user_follow(request, id):
# 나(로그인한 사용자)
me = request.user
# 내가 팔로우하려고 방금 누른 사람
click_user = UserModel.objects.get(id=id)
# 팔로우를 당한 사람(click_user)도 UserModel의 정보를 가져와 쓰기 때문에 아래와 같이 쓸 수 있다.
# 만약 click_user를 팔로우하는 사람의 명단에 내가 있다면
if me in click_user.followee.all():
# 나를 명단에서 제외해줘(팔로우가 된 상태에서 팔로우를 또 누르면 팔로우가 취소되니까)
click_user.followee.remove(request.user)
else:
# 내가 명단에 없다면 나를 팔로우하는 사람들의 명단에 넣어줘
click_user.followee.add(request.user)
return redirect('/user')
from django.urls import path
from . import views
urlpatterns = [
path('sign-up/', views.sign_up_view, name='sign-up'),
path('sign-in/', views.sign_in_view, name='sign-in'),
path('logout/', views.logout, name='logout'),
path('user/', views.user_view, name='user-list'),
path('user/follow/<int:id>', views.user_follow, name='user-follow'),
]
<!-- templates/user/user_list.html -->
{% extends 'base.html' %}
{% block title %}
사용자 리스트
{% endblock %}
{% block content %}
<div class="container timeline-container">
<div class="row">
<!-- 왼쪽 컬럼 -->
<div class="col-md-3">
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ user.username }}</h5>
<p class="card-text"> {{ user.bio }}</p>
</div>
</div>
</div>
<!-- 오른 쪽 컬럼-->
<div class="col-md-7">
<div class="row">
<div class="alert alert-success" role="alert">
나를 팔로우 하는 사람 수 : {{ user.followee.count }} 명 / 내가 팔로우 하는 사람 수 : {{ user.follow.count }} 명
</div>
</div>
<div class="row">
<!-- 사용자 리스트 반복문 -->
{% for ul in user_list %}
<div class="card">
<div class="card-body">
<h5 class="card-title">{{ ul.username }}</h5>
<h6 class="card-subtitle mb-2 text-muted">{{ ul.email }}</h6>
<p class="card-text">
{{ ul.bio }}
</p>
<p class="card-text">
팔로잉 {{ ul.follow.count }} 명 / 팔로워 {{ ul.followee.count }} 명
</p>
{% if ul in user.follow.all %}
<a href="/user/follow/{{ ul.id }}" class="card-link">[팔로우 취소]</a>
{% else %}
<a href="/user/follow/{{ ul.id }}" class="card-link">[팔로우]</a>
{% endif %}
</div>
</div>
<hr>
{% endfor %}
</div>
</div>
<div class="col-md-2"></div>
</div>
</div>
{% endblock %}
친구
부분에 /user
url을 걸어주었다. <!-- templates/base.html -->
<!-- 상단 생략 -->
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="/">SpartaSNS</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item active">
<a class="nav-link" href="/user"> 친구 <span class="sr-only"></span></a>
</li>
</ul>
</div>
<!-- 하단 생략 -->