pip install django django-admin startproject my_django_project
python manage.py migrate - 초기 db.sqlite3이 생성됨 python manage.py createsuperuser - 관리자 계정 생성
python manage.py startapp blog
- settings.py에 App을 추가해주어야 함
python manage.py makemigrates python manage.py migrate
class Post(models.Model):
title = models.CharField(max_length=30)
content = models.TextField()
created_at = models.DateTimeField()
- python manage.py makemigrations
- python manage.py migrate
- admin.py에 등록
- admin.site.register(Post)
- URL에 사용할 패턴과 views.py의 메서드 연결
- views.py에서 사용할 템플릿과 연결
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
- __str__을 오버라이딩하여 객체의 대표가 될 내용 설정
- get_absolute_url을 생성해 상세보기 페이지로 이동하는 URL 설정
- 사용하려는 메서드를 모델에 넣으면 View에서 사용 가능
- settings.py와 urls.py에 MEDIA_URL 설정 필요
- 이미지 업로드 컬럼 추가
head_image = models.ImageField(upload_to='blog/images/%Y/%m/%d/', blank=True)
- 파일 업로드 컬럼 추가
file_upload = models.FileField(upload_to='blog/images/%Y/%m/%d/', blank=True)
- 업로드 파일 속성
- file_upload.name : 파일명
- file_upload.url : 파일경로
- 숫자인 pk 대신 읽을 수 있는 텍스트로 URL을 구성할 때 사용
models.SlugField(max_length=2000, unique=True, allow_unicode=True)
- blank=True : 해당 필드를 작성하지 않아도 됨(폼에서 비어있어도 됨), 유효성 검사때 사용
- null=True : Nullable 허용
- unique=True : Unique 속성
- on_delete=models.CASCADE : 연관 레코드가 삭제될 때 함께 삭제
- on_delete=models.SET_NULL : 연관 레코드가 삭제될 때 해당 필드를 NULL로 설정
- allow_unicode=True : Slug 필드에서의 한글 URL 유니코드 허용
def get_context_data(self, **kwargs):
context = super(PostList, self).get_context_data()
context['categories'] = Category.objects.all()
context['no_category_post_count'] = Post.objects.filter(category=None).count()
return context
# N:1 관계연결
category = models.ForeignKey(Category, null=True, blank=True, on_delete=models.SET_NULL)
# N:M 관계연결
tags = models.ManyToManyField(Tag, blank=True) # null=True를 설정필요없음
urlpatterns = [
path('', views.index),
path('<int:pk>', views.post_detail)
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
- MYMODEL.objects.all() : Table의 모든 값 선택
- .order_by('-pk') : PK DESC 정렬, -는 역순
- render : 템플릿과 컨텍스트로 넘겨줄 값 설정
def post_list(request):
posts = Post.objects.all().order_by('-pk')
return render(
request,
'blog/post_list.html',
{
'posts': posts
}
)
- ListView, DetailView, CreateView, UpdateView
class PostList(ListView):
model = Post
ordering = '-pk'
# render시 아래의 별도 설정이 없을 시 경로는 post_list.html, 모델은 자동으로 post_list로 할당됨
template_name = 'blog/post_list.html' #템플릿 설정
def get_context_data(self, **kwargs):
context = super(PostDetail, self).get_context_data()
context['categories'] = Category.objects.all()
return context
- SELECT ONE : Tag.objects.get(slug = slug)
- SELECT LIST : Post.objects.all()
- SELECT LIST WHERE : Post.objects.filter(category = category)
- 연관되어 있는 셋 조회 : post_list = tag.post_set.all()
- class PostCreate(LoginRequiredMixin, CreateView):
- POST 요청에서 유효한 폼이 제공되면 데이터를 확인 및 처리하여 결과 반환
def form_valid(self, form):
current_user = self.request.user
if current_user.is_authenticated and (current_user.is_staff or current_user.is_superuser):
form.instance.author = current_user
return super(PostCreate, self).form_valid(form)
else:
return redirect('/blog')
- 요청이 처리되기 전에 호출되는 메서드. HTTP 메서드에 따라 적절한 메서드 호출\
- 인증 및 권한 관리와 같은 전처리 작업을 수행함
def dispatch(self, request, *args, **kwargs):
if request.user.is_authenticated and request.user == self.get_object().author:
return super(PostUpdate, self).dispatch(request, *args, **kwargs)
else:
raise PermissionDenied
- request.method :Request Method
- request.POST : Form에 입력한 데이터를 담고있는 POST 요청객체
- request.user : 세션의 사용자
- is_authenticated : 인증이 되었는가?
- is_superadmin, is_staff : 권한이 ~인가?
- TIME_ZONE = 'Asia/Seoul'
- USE_TZ = False
- STATIC_URL = "static/"
MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, '_media')
- 관리자 페이지 설정
admin.site.register(Post)
class AutoSlugAdmin(admin.ModelAdmin):
prepopulated_fields = {'slug': ('name', )}
admin.site.register(Category, AutoSlugAdmin)
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('content',) #입력
def get_context_data(self, **kwargs):
context = super(PostDetail, self).get_context_data()
context['comment_form'] = CommentForm
return context
{% for p in post_list %}
<p class="card-text">{{ p.content }}</p>
{% endfor %}
{% load static %}
//...
<img src="{% static 'images/lena.jpg' %}">
첫 100개 문자 <p class="card-text">{{ p.content | truncatechars:100}}</p>
첫 45개 단어 <p class="card-text">{{ p.content | truncatewords:45}}</p>
- 부모 템플릿 상속
{% extends 'blog/base.html' %}
- 블록 영역 구분(부모 자식 모두)
{% block main_area %}
{% endblock %}
- 다른 템플릿 포함
{% include 'blog/navbar.html' %}