model 작성
# articles/models.py
**class Hashtag(models.Model):
content = models.TextField(unique=True)
def __str__(self):
return self.content**
class Article(models.Model):
**hashtags = models.ManyToManyField(Hashtag)**
$ python manage.py makemigrations
$ python manage.py migrate
# articles/admin.py
from .models import Article, Comment, **Hashtag**
**admin.site.register(Hashtag)**
# articles/views.py
from .models import Article, Comment, **Hashtag**
@login_required
@require_http_methods(['GET', 'POST'])
def create(request):
if request.method == 'POST':
form = ArticleForm(request.POST)
if form.is_valid():
article = form.save(commit=False)
article.user = request.user
article.save()
**# hashtag
for word in article.content.split(): # content 를 공백기준으로 리스트로 변경
if word[0] == '#': # '#'로 시작하는 요소 선택
hashtag, created = Hashtag.objects.get_or_create(content=word) # word(content안에 해시태그)랑 같은 기존 해시태그를 찾으면 기존 객체를, 없으면 새로운 객체를 return
article.hashtags.add(hashtag)**
return redirect('articles:detail', article.pk)
...
# articles/forms.py
from django import forms
from .models import Article, Comment
class ArticleForm(forms.ModelForm):
class Meta:
model = Article
fields = ('title', 'content',)
article.save()
보다 하단에 작성해야 한다.**unique
arguments**
https://docs.djangoproject.com/ko/3.1/ref/models/fields/#unique
True
인 경우 이 필드는 테이블 전체에서 고유한 값임을 의미한다.".save()
메서드로 인해 IntegrityError
가 발생**get_or_create()**
https://docs.djangoproject.com/ko/3.1/ref/models/querysets/#get-or-create
(object, created)
형태의 튜플을 return 한다.object
created
defaults
를 제외하고 전달 된 키워드 인수는 get()
호출에 사용된다."단, 이 메서드는 DB 가 키워드 인자의 unique
옵션을 강제한다고 가정한다. "
unique 옵션이 없다면 이 메서드를 동시에 호출할 때
동일한 매개 변수가 삽입된 여러 행이 발행 할 수 있기 때문이다.
(hashtag에 unique=True를 주어서 사용가능 한 것)
try:
obj = Person.objects.get(first_name='John', last_name='Lennon')
except Person.DoesNotExist:
obj = Person(first_name='John', last_name='Lennon', birthday=date(1940, 10, 9))
obj.save()
obj, created = Person.objects.get_or_create(
first_name='John',
last_name='Lennon',
defaults={'birthday': date(1940, 10, 9)},
)
# articles/views.py
@login_required
@require_http_methods(['GET', 'POST'])
def update(request, pk):
article = get_object_or_404(Article, pk=pk)
if request.user == article.user:
if request.method == 'POST':
form = ArticleForm(request.POST, instance=article)
if form.is_valid():
article = form.save()
**article.hashtags.clear() # 해당 article 의 hashtag 전체 삭제
for word in article.content.split():
if word[0] == '#':
hashtag, created = Hashtag.objects.get_or_create(content=word)
article.hashtags.add(hashtag)**
return redirect('articles:detail', article.pk)
...
hashtag 테이블의 기존 hashtag는 유지되어 있어야 하고,
수정이나 새로운 입력으로 생긴 새 hashtag들이 저장되어 있어야 한다.
# articles/urls.py
urlpatterns = [
...,
path('<int:hash_pk>/hashtag/', views.hashtag, name='hashtag'),
]
# articles/views.py
def hashtag(request, hash_pk):
hashtag = get_object_or_404(Hashtag, pk=hash_pk)
articles = hashtag.article_set.order_by('-pk')
context = {
'hashtag': hashtag,
'articles': articles,
}
return render(request, 'articles/hashtag.html', context)
<!-- articles/hashtag.html -->
{% extends 'base.html' %}
{% block content %}
<h1>{{ hashtag.content }}</h1>
<p>{{ articles|length }}개의 게시글이 {{ hashtag.content }}를 태그중입니다.</p>
<hr>
<h2>{{ hashtag.content }}를 태그한 게시글</h2>
{% for article in articles %}
<p>제목 : {{ article.title }}</p>
<a href="{% url 'articles:detail' article.pk %}">보러가기</a>
<hr>
{% endfor %}
{% endblock %}
http://127.0.0.1:8000/articles/1/hashtag/
예시
https://docs.djangoproject.com/en/3.1/howto/custom-template-tags/#custom-template-tags-and-filters
articles 앱 안에 templatetags
폴더 생성 (폴더명은 반드시 templatetags
****)
templatetags 폴더안에 다음과 같은 파일트리 만들기
**articles/**
__init__.py
models.py
**templatetags/**
__init__.py
**make_hashtag_link.py**
views.py
사용자 정의 필터 작성
# articles/templatetags/make_hashtag_link.py
from django import template
register = template.Library()
@register.filter
def hashtag_link(word):
content = word.content + ' '
hashtags = word.hashtags.all()
for hashtag in hashtags:
content = content.replace(hashtag.content + ' ', f'<a href="/articles/{hashtag.pk}/hashtag/">{hashtag.content}</a> ') # 마지막 공백 있음!
return content
hashtag_link
라는 이름의 함수를 정의한다. (템플릿에서 사용할 커스텀 필터의 이름이 됨)#스타벅스
=> <a href="/articles/1/hashtag/">#스타벅스</a>
templatetags 폴더를 추가하고 나서 반드시 서버를 재시작 해야 한다.
<!-- articles/detail.html -->
{% extends 'base.html' %}
**{% load make_hashtag_link %}**
{% block content %}
<h2>DETAIL</h2>
<h3>{{ article.pk }} 번째 글</h3>
<hr>
<p>제목 : {{ article.title }}</p>
**<p>내용 : {{ article|hashtag_link|safe }}</p>**
load
해준다.| (파이프 라인)
앞에(왼쪽) 변수가 인자로 들어간다.hashtag_link(article)
로 동작하게 된다.**safe
filter**
https://docs.djangoproject.com/en/3.1/ref/templates/builtins/#safe
detail 페이지 결과 확인