ManyToManyField’s Arguments
- related_name
- target model이 source model을 참조할 때 사용할 manager name
- ForeignKey의 relqted_name과 동일
- through
- 중개 테이블을 직접 작성하는 경우, through 옵션을 사용하여 중개 테이블을 나타내는 Django 모델을 지정
- 일반적으로 중개 테이블에 추가 데이터를 사용하는 다대다 관계와 연결하려는 경우(extra data with a many-to-many relationship)에 사용됨
- symmetrical
- 기본 값: True
- ManyToManyField가 동일한 모델을 가리키는 정의에서만 사용
- True일 겅우
- _set 매니저를 추가하지 않음
- source 모델의 인스턴스가 target 모델의 인스턴스를 참조하면 자동으로 target 모델 인스턴스도 source 모델 잉ㄴ스턴스를 참조하도록 함
- Quid pro quo. If I am your friend, you are my friend too.
- 대칭을 원하지 않는 경우 False로 설정
# example
class Person(models.Model):
friends = models.ManyToManyField('self')
M:N 관계를 통한 좋아요 기능 구현
# articles/models.py
class Article(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
like_users = models.ManyToManyField(settings.AUTH_USER_MODEL, related_name='like_articles')
...
related manager 정리
- article.user : 게시글을 작성한 유저
- user.article_set : 유저가 작성한 게시글(역참조)
- article.like_users : 게시글에 좋아요를 누른 유저
- user.like_articles : 유저가 좋아요한 게시글(역참조)
# articles.urls.py
...
path('<int:article_pk>/likes/', views.likes, name='likes'),
# articles/views.py
@require_POST
def likes(request, article_pk):
if request.user.is_authenticated:
article = Article.objects.get(pk=article_pk)
if article.like_users.filter(pk=request.user.pk).exists():
article.like_users.remove(request.user)
else:
article.like_users.add(request.user)
return redirect('articles:index')
return redirect('accounts:login')
# index 템플릿에서 if문으로 좋아요 버튼 출력
{% request.user in article.like_users.all %}
<input type="submit" value="좋아요 취소">
{% else %}
<input type="submit" value="좋아요">
{% endif %}
Profile 구현
- url 및 view 함수
urlpatterns = [
...
path('profile/<username>/', views.profile, name = 'profile'),
]
from django.contrib.auth import get_user_model
def profile(request, username):
User = get_user_model()
person = User.objects.get(username=username)
context = {'person':person}
return render(request, 'accounts/profile.html',context)
- profile 템플릿 작성
<h3>{{person.username}}님의 프로필</h3>
<hr>
<h4>{{person.username}}'s 게시글</h4>
{% for article in person.article_set.all %}
<div>{{article.title}}</div>
{% endfor %}
<hr>
<h4>{{person.username}}'s 댓글</h4>
{% for comment in person.comment_set.all %}
<div>{{comment.content}}</div>
{% endfor %}
<hr>
<h4>{{person.username}}'s 좋아요한 게시글</h4>
{% for article in person.like_articles.all %}
<div>{{article.title}}</div>
{% endfor %}
- profile 템플릿으로 이동할 수 있는 하이퍼링크 작성
<h3>Hello, {{user}}</h3>
<a href="{% url 'accounts:profile' user.username %}">내 프로필</a>
<!-- articles/index.html -->
<p>
<b>작성자: <a href="<% url 'accounts:profile' article.user.username %}">{{article.user}}</a></b>
</p>
Follow 구현
- ManyToManyField 작성 및 Migration 진행
# accounts/models.py
class User(AbstractUser):
followings = models.ManyToManyField('self', symmetrical=False, related_name='followers')
- url 및 view 함수 작성
urlpatterns = [
...
path('<int:user_pk>/follow/', views.follorw, name='follow'),
]
@require_POST
def follow(request, user_pk):
if request.user.is_authenticated:
User = get_user_model()
person = User.objects.get(pk=user_pk)
if person != request.user:
if person.followersfilter(pk=request.user.pk).exist():
person.followers.remove(request.user)
else:
person.followers.add(request.user)
return redirect('accounts:profile', person.username)
return redirect('accounts:login')
- 프로필 유저의 팔로잉, 팔로워 수, 팔로우/언팔로우 버튼 작성
<h3>{{person.username}}님의 프로필</h3>
<div>
<div>
Following: {{person.folwings.all|length}} / Followers: {{person.followers.all|length}}
</div>
{% if request.user != person %}
<div>
<form action="{% url 'accounts:follow' person.pk %}" method="POST">
{% csrf_token %}
{% if request.user in person.followers.all %}
<input type='submit' value='Unfollow'>
{% else %}
<input type='submit' value='Follow'>
{% endif %}
</form>
</div>
{% endif %}
</div>
'Programming Language > SQLite' 카테고리의 다른 글
SQLite_06)Fixtures (0) | 2023.04.12 |
---|---|
SQLite_04)Foreign Key_2 (0) | 2023.04.12 |
SQLite_03)Foreign Key_1 (0) | 2023.04.12 |
SQLite_02)CRUD (0) | 2023.04.12 |
SQLite_01)Set up & Basics (0) | 2023.04.12 |