[django] 03-16 기능 추가 관련 질문
안녕하세요 선생님, 책 구매해서 열심히 쭉쭉 따라가고 있습니다. 어렵긴 하지만 재미있네요 ㅎㅎ..
3장 끝까지 다 나가고 기능을 조금 추가하고 싶어서 수정 중인데 몇 가지 궁금한 것이 있어 질문 드립니다.
(1) 회원가입 기능 추가
현재 회원가입은 id, pw, email인데 추가적으로 사용자에게 몇 가지 input을 더 받고 싶습니다.
실명을 받기 위해서는 아래와 같이 수정하면 될까요? 혹은 별도의 수정이 필요한가요?
# common/forms.py
class UserForm(UserCreationForm):
...
realname = forms.Field(label="실명")
class Meta:
model = User
fields = ("username", "email", "realname")
(2) 추가한 input 항목을 선택항목으로 수정 가능한지?
input 항목을 추가하되 필수항목이 아니도록 하고 싶은데 회원가입 같은 경우는 별도의 model.py를 사용하지 않아서 어떻게 해결해야하는지 궁금합니다.
정 안되면 사용자에게 특정 문자열을 받아서 그걸로 사용 여부를 판단하는 방법도 있을 것 같긴한데, 그냥 공란으로 비울 수 있는 방법이 있는지 궁금합니다.
(3) 페이징 기법 에러 (해결)
메인 화면을 추가하고 싶어 메인화면을 만들고config/urls.py에서 ' '을 새로 만든 메인화면으로 링크를 걸었더니
questionlist.html에서 페이징 기법처리하여 만들어진 버튼들이 새로 만든 메인화면으로 넘어갑니다.
혹시 어느 부분을 건드려야하는지 알려주시면 감사하겠습니다.
(현재 수정한 부분)*
# pybo/urls.py
...
urlpatterns = [
# base_views
path('', base_views.main, name='main'),
path('all/', base_views.index, name='index'), # 여기 수정
path('<int:question_id>/', base_views.detail, name='detail'),
...
]
# base_views.py
...
def main(request): # main.html로 이동하기 위해 추가
return render(request, 'pybo/main.html')
...
(4) 카테고리 기능
게시글 생성 시 카테고리를 입력받게 만들고 분류하는 것 까지는 다 만들었습니다.
각 카테고리별 html파일을 따로 만들어서 기존 question_list.html의 코드를 가져와 kw를 활용하여 별도의 게시판을 만들면 될까요?
shin 님 1236
M 2021년 7월 22일 6:06 오후
6개의 답변이 있습니다. 1 / 1 Page
[자문자답]
3번 해결했습니다.
계속 pybo/url.py만 확인했는데, config/url.py에서 index 설정을 제대로 건들지 못했네요.
shin 님
M 2021년 7월 22일 6:02 오후
안녕하세요.
1)번은 realname 속성을 User 모델에도 추가해 주셔야 합니다.
2)번은 realname = forms.Field(label="실명", blank=True) 처럼 blank 옵션을 사용하시면 됩니다.
4)번은 카테고리 때문에 기존 작성한 파일들을 모두 중복해서 만들 필요가 없습니다. 카테고리에 대한 글들은 이 곳 게시판에도 있으니 참고하시면 좋을것 같습니다.
박응용 님
2021년 7월 22일 7:26 오후
카테고리 사용하시는 것을 찾아 보고 왔는데 제가 확인 전에 구현한 방법과 방식이 달라서 혹시 그대로 써도 될지, 혹은 변경을 해야될지 여쭤보고 싶어서 남깁니다.
# https://pybo.kr/pybo/question/detail/616/
@login_required(login_url='common:login')
def question_create(request, category_name):
"""
pybo 질문등록
"""
category = get_object_or_404(Category, name=category_name)
if request.method == "POST":
form = QuestionForm(request.POST)
if form.is_valid():
question = form.save(commit=False)
question.author = request.user # 추가한 속성 author 적용
question.create_date = timezone.now()
question.category = category
question.save()
return redirect('pybo:question_list', category_name)
else:
form = QuestionForm()
context = {'form': form, 'category': category}
return render(request, 'pybo/question_form.html', context)
아래는 제가 구현한 방식입니다.
# question_form.html
<div class="form-group">
<label for="subject">제목</label>
<input name="subject" id="subject" class="form-control" type="text" value="{{ form.subject.value|default_if_none:'' }}" >
</div>
<div class="form-group">
<label for="category">카테고리</label>
<select class="form-control" name="category" id="category">
<option value="free">자유게시판</option>
<option value="practice">연습문제</option>
<option value="portfolio">포트폴리오</option>
<option value="qna">Q & A</option>
<option value="notice">공지사항</option>
</select>
</div>
<div class="form-group">
<label for="content">내용</label>
<textarea name="content" id="content" rows="10" class="form-control">{{ form.content.value|default_if_none:'' }}</textarea>
</div>
<button type="submit" class="btn btn-primary">저장히기</button>
# models.py
class Question(models.Model):
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='author_question')
subject = models.CharField(max_length=200)
category = models.TextField()
content = models.TextField()
create_date = models.DateTimeField()
modify_date = models.DateTimeField(null=True, blank=True)
voter = models.ManyToManyField(User, related_name='voter_question')
shin 님
M 2021년 7월 22일 9:52 오후
pybo.kr의 모델 입니다.
from django.db import connection
from django.db import models
from django.urls import reverse
from common.models import CustomUser
class Category(models.Model):
name = models.CharField(max_length=20, unique=True)
description = models.CharField(max_length=200, null=True, blank=True)
has_answer = models.BooleanField(default=True) # 답변가능 여부
def __str__(self):
return self.name
class Question(models.Model):
class Meta:
ordering = ['id']
author = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='author_question')
subject = models.CharField(max_length=200)
content = models.TextField()
create_date = models.DateTimeField(auto_now_add=True, blank=True)
modify_date = models.DateTimeField(null=True, blank=True)
voter = models.ManyToManyField(CustomUser, related_name='voter_question', blank=True)
category = models.ForeignKey(Category, on_delete=models.CASCADE, related_name='category_question')
view_count = models.IntegerField(null=True, blank=True, default=0)
notice = models.BooleanField(default=False) # 공지사항 여부
def __str__(self):
return self.subject
def get_absolute_url(self):
return reverse('pybo:question_detail', args=[self.id])
def get_recent_comments(self):
return self.comment_set.all().order_by('-create_date')[:5]
class Answer(models.Model):
author = models.ForeignKey(CustomUser, on_delete=models.CASCADE, related_name='author_answer')
question = models.ForeignKey(Question, on_delete=models.CASCADE)
content = models.TextField()
create_date = models.DateTimeField()
modify_date = models.DateTimeField(null=True, blank=True)
voter = models.ManyToManyField(CustomUser, related_name='voter_answer', blank=True)
def get_absolute_url(self):
# 현재 답변이 작성된 페이지 정보가 필요
answer_index = self.get_index()
page, r = divmod(answer_index, 10)
if r != 0:
page += 1
return reverse('pybo:question_detail', args=[self.question.id]) + "?page=%s#answer_%s" % (page, self.id)
def get_index(self):
queryset = self.question.answer_set.order_by('create_date')
numbered_qs = queryset.extra(select={
'queryset_row_number': 'ROW_NUMBER() OVER (ORDER BY "id")'
})
with connection.cursor() as cursor:
cursor.execute(
"WITH OrderedQueryset AS (" + str(numbered_qs.query) + ") "
"SELECT queryset_row_number FROM OrderedQueryset WHERE id = %s",
[self.id]
)
index = cursor.fetchall()[0][0]
# index = 0
# for _answer in self.question.answer_set.all().order_by('create_date'):
# index += 1
# if self.id == _answer.id:
# break
return index
def get_recent_comments(self):
return self.comment_set.all().order_by('-create_date')[:5]
class Comment(models.Model):
author = models.ForeignKey(CustomUser, on_delete=models.CASCADE)
content = models.TextField()
create_date = models.DateTimeField()
modify_date = models.DateTimeField(null=True, blank=True)
question = models.ForeignKey(Question, null=True, blank=True, on_delete=models.CASCADE)
answer = models.ForeignKey(Answer, null=True, blank=True, on_delete=models.CASCADE)
voter = models.ManyToManyField(CustomUser, related_name='voter_comment')
class Meta:
ordering = ['create_date']
def get_question(self):
if self.question:
return self.question
elif self.answer:
return self.answer.question
else:
return None
def get_absolute_url(self):
if self.question:
_anchor = "#anchor_question_all_comments"
return reverse('pybo:question_detail', args=[self.question.id]) + _anchor
elif self.answer:
# 현재 답변이 작성된 페이지 정보가 필요
answer_index = self.answer.get_index()
page, r = divmod(answer_index, 10)
if r != 0:
page += 1
_anchor = "?page=%s#anchor_answer_all_comments_%s" % (page, self.answer.id)
return reverse('pybo:question_detail', args=[self.answer.question.id]) + _anchor
else:
return None
class QuestionCount(models.Model):
ip = models.CharField(max_length=30)
question = models.ForeignKey(Question, on_delete=models.CASCADE)
def __unicode__(self):
return self.ip
박응용 님
2021년 7월 22일 10:43 오후
에고고.. 자꾸 여쭤봐서 죄송합니다..
AbstractUser를 이용해서 수정을 했는데 자꾸 문제가 나타나네요..
인터넷을 뒤져봐도 다람쥐 챗바퀴 구르듯이 다시 같은 문제로 돌아옵니다.
수정 후 'python manage.py makemigrations'를 하려고 하니 에러가 나타납니다.
혹시 해결 방법이 있을까요...
(mysite) D:\Study\django\mysite>python manage.py makemigrations
Traceback (most recent call last):
File "D:\Study\django\mysite\manage.py", line 22, in <module>
main()
File "D:\Study\django\mysite\manage.py", line 18, in main
execute_from_command_line(sys.argv)
File "C:\venvs\mysite\lib\site-packages\django\core\management\__init__.py", line 401, in execute_from_command_line
utility.execute()
File "C:\venvs\mysite\lib\site-packages\django\core\management\__init__.py", line 395, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "C:\venvs\mysite\lib\site-packages\django\core\management\base.py", line 330, in run_from_argv
self.execute(*args, **cmd_options)
File "C:\venvs\mysite\lib\site-packages\django\core\management\base.py", line 371, in execute
output = self.handle(*args, **options)
File "C:\venvs\mysite\lib\site-packages\django\core\management\base.py", line 85, in wrapped
res = handle_func(*args, **kwargs)
File "C:\venvs\mysite\lib\site-packages\django\core\management\commands\makemigrations.py", line 101, in handle
loader.check_consistent_history(connection)
File "C:\venvs\mysite\lib\site-packages\django\db\migrations\loader.py", line 302, in check_consistent_history
raise InconsistentMigrationHistory(
django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency common.0001_initial on database 'default'.
shin 님
M 2021년 7월 23일 1:15 오전
원래 인터넷 찾아보면서 독학을 해야하는데 다 물어보고 해결하는 것 같네요.. 번거롭게 해서 죄송합니다..
위에서 말씀하신대로 카테고리를 pybo 코드를 참고하여 수정하였습니다.
Page not found (404)
Request Method: GET
Request URL: http://localhost:8000/pybo/list/free
Raised by: pybo.views.base_views.index
No Category matches the given query.
You're seeing this error because you have DEBUG = True in your Django settings file. Change that to False, and Django will display a standard 404 page.
현재 게시판에 접근을 시도 하면 현재 이런 에러가 브라우저에 나타납니다.
shell을 통해 Category를 먼저 별도로 생성을 해야하는 것인가요?
혹시 코드 에러인가 싶어 관련 코드도 같이 올립니다.
navi.html
<li class="nav-item">
<a href="{% url 'pybo:index' 'free' %}" class="nav-link">자유게시판</a>
</li>
url.py
urlpatterns = [
path('list/<str:category_name>/', base_views.index, name='index'),
]
forms.py
class QuestionForm(forms.ModelForm):
class Meta:
model = Question
fields = ['subject', 'content', 'category']
labels = {
'subject': '제목',
'category': '카테고리',
'content': '내용',
}
views.py
def index(request, category_name):
page = request.GET.get('page', '1')
kw = request.GET.get('kw', '')
so = request.GET.get('so', 'recent')
category = get_object_or_404(Category, name=category_name)
_question_list = Question.objects.filter(category__name=category.name)
# 정렬
if so == 'recommend':
_question_list = Question.objects.annotate(num_voter=Count('voter')).order_by('-num_voter', '-create_date')
elif so == 'popular':
_question_list = Question.objects.annotate(num_answer=Count('answer')).order_by('-num_answer', '-create_date')
else:
_question_list = Question.objects.order_by('-create_date')
# 검색
if kw:
_question_list = _question_list.filter(
Q(subject__icontains=kw) |
Q(content__icontains=kw) |
Q(author__username__icontains=kw) |
Q(answer__author__username__icontains=kw)
).distinct()
# 페이징 처리
paginator = Paginator(_question_list, 10)
page_obj = paginator.get_page(page)
context = {'question_list': page_obj, 'page': page, 'kw': kw, 'category': category}
return render(request, 'pybo/question_list.html', context)
def detail(request, question_id):
question = get_object_or_404(Question, pk=question_id)
context = {'question': question, 'category': question.category}
return render(request, 'pybo/question_detail.html', context)
shell에서 Category결과
<QuerySet [{'id': 1, 'name': 'free', 'description': '1', 'has_answer': True}, {'id': 2, 'name': 'practice', 'description': '2', 'has_answer': True}, {'id': 3, 'name': 'portfolio', 'description': '3', 'has_answer': True}, {'id': 4, 'name': 'qna', 'description': '4', 'has_answer': True}, {'id': 5, 'name': 'notice', 'description': '5', 'has_answer': True}]>
model.py는 pybo와 동일하게 수정했습니다.
발생하는 문제
NoReverseMatch at /pybo/list/free/
Reverse for 'index' with no arguments not found. 1 pattern(s) tried: ['pybo/list/(?P<category_name>[^/]+)/$']
shin 님
M 2021년 7월 23일 8:20 오후