django

django m2m

Posted by 동식이 블로그 on April 23, 2019

190423

09-m2m

1. 모델설정(models)

1) User

  • 팔로우기능을 구현
  • id // from_user_id // to_user_id
    • ManyToManyField가 선언된 모델과 가리키는 모델이 동일하다면, 위와 같이 필드가 생성됨
1
2
3
4
5
6
7
8
9
# accounts-models.py
from django.db import models
from django.contrib.auth.models import AbstractUser
from conf import settings

class User(AbstractUser):
    followings = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name="followers", blank=True)
    def __str__(self):
        return self.username

2) Movie, Genre, Score

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from django.db import models
from django.conf import settings

class Genre(models.Model):
    name = models.CharField(max_length=20)
        
class Movie(models.Model):
    title = models.CharField(max_length=30)
    audience = models.IntegerField()
    poster_url = models.TextField()
    description = models.TextField()
    genre = models.ForeignKey(Genre, on_delete=models.CASCADE)

class Score(models.Model):
    content = models.CharField(max_length=20)
    value = models.IntegerField()
    movie = models.ForeignKey(Movie, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

2. accountApp

1) 유저목록(accounts/)

  • 사용자의 목록이 나타나도록
1
2
# accounts-urls.py
path('', views.list, name='list'),
1
2
3
4
5
6
7
# accountgs.views.py
from django.contrib.auth import get_user_model

def list(request):
    User = get_user_model()
    user_info = User.objects.all()
    return render(request, "accounts/list.html", {"user_info":user_info})
1
2
3
4
5
6
7
# accounts-list.html
{% extends 'base.html' %}
{% block body %}
    {% for user in user_info %}
       <a href="{% url 'accounts:user_page' user.id %}"> <h2></h2></a>
    {% endfor %}
{% endblock %}

2) 유저 상세보기 (accounts/{user.pk}/)

  • 사용자 이름을 누르면 상세 페이지로 이동하도록
1
2
# accounts-urls.py
path('user_page/<int:id>', views.user_page, name="user_page"),
1
2
3
4
5
# accountgs.views.py
def user_page(request, id):
    User = get_user_model()
    user_info = User.objects.get(id=id)
    return render(request, "accounts/user_page.html", {"user_info":user_info})
1
2
3
4
5
6
7
8
9
# accounts-user_page.html
{% extends 'base.html' %}
{% block body %}
    <h1></h1>
    <h3></h3>
    <h3></h3>
    <h3></h3>
    <h3></h3>
{% endblock %}
  • 로그인한 사람만이 팔로우 가능

  • 팔로우, 팔로잉 사람 수

    • 로그인이 되어있는 사람의 정보 : me
    • 상대방 : you
    • if문you가 내 팔로잉 안에 있으면 , 단 내가 나를 팔로우 할 수 없게
1
2
3
4
5
6
7
8
9
10
11
12
# accounts-views.py
def follow(request, id):
    User = get_user_model()
    me = request.user
    you = User.objects.get(id=id)
    
    if(me != you):
        if(you in me.followings.all()):
            me.followings.remove(you)
        else:
            me.followings.add(you)
    return redirect("accounts:user_page", id)
1
2
3
4
5
6
7
8
9
10
11
# accounts-user_page.html
## user.id가 아니라 user_info.id : user.id는 현재 로그인한 사람
{% if user.id != user_info.id  %}
	{% if user_info.id in user.followings.all %}
		<a href="{% url 'accounts:follow' user_info.id %}" class="btn btn-light">팔로잉</a>
	{% else %}
		<a href="{% url 'accounts:follow' user_info.id %}" class="btn btn-primary">팔로우</a>
	{% endif %}
{% endif %}
<p class="card-text">팔로잉 :  명</p>
<p class="card-text">팔로워 :  명</p>
  • 유저가 작성한 평점 정보 출력

3. moviesApp

1) 평점작성

  • 로그인한 사람만 작성 가능
1
2
# movies-urls.py
path('<int:m_id>/scores/new/', views.new, name="new"),
1
2
3
4
5
6
7
8
9
10
11
12
13
# movies-views.py
def new(request, m_id):
    if(request.method == "POST"):
        s_form = ScoreForm(request.POST)
        if(s_form.is_valid()):
            form = s_form.save(commit=False)
            # commite=False를 해주는 이유는 밑에서 movie와 user정보를 저장하기 위해서
            form.movie = Movie.objects.get(id=m_id)
            form.user = request.user
            form.save()
            return redirect("movies:detail", m_id)
        else:
            return redirect("movies:list")
1
2
3
4
5
6
7
8
9
# movies-detail.html
<!-- form태그에 action이 없을때는 위치한 url로 해당 요청을 보낼때 그렇게 하고, 
	action에 url이 있으면 해당 url로 요청을 보내기 위해서 -->
<form action="{% url 'movies:new' movie.id %}" method="post">
        {% csrf_token %}
        <p>평점 : </p>
        <p>내용 : </p>
        <input type="submit">
</form>

2) 평점 삭제

  • 작성한 본인만 가능하게 구현
1
2
# movies-urls.py
path('<int:m_id>/scores/<int:s_id>/s_delete/', views.s_delete, name="s_delete"),
1
2
3
4
5
# movies-views.py
def s_delete(request, m_id, s_id):
    score = Score.objects.get(id=s_id)
    score.delete()
    return redirect("movies:detail", m_id)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# movies-detail.html
<div class="card-body">
        {% for score in movie.score_set.all %}
        <p class="card-text">
              <strong style="color:black;"></strong> 
               
         <!--현재 로그인한 사람과 평점을 작성한 사람이 같을 때-->
         <!--html코드에서 user는 기본적으로 request에 담겨있는, 즉 현재 로그인한 user-->
              {% if user.id == score.user.id %}
                  <a href="{% url 'movies:s_delete' movie.id score.id %}">삭제</a>
              {% endif %}
        </p>
        {% empty %}
          <p class="card-text">평점이 없어요요</p>
        {% endfor %}
</div>