(정리완료)
오늘도 어제와 마찬가지로 한번 더 다른 기능을 만들었다.
pip install django
django-admin startproject config .
python manage.py migrate(default값으로 데이터베이스 만든다)
python manage.py createsuperuser(관리자 계정)
python manage.py startapp photo
'photo',
from django.contrib.auth.models import User#작성자 가져옴(기본설정 되어있는 user를 가져온다)
class Photo(models.Model):#model 받아옴
author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='user_photos')#user로 연결하고 삭제되면 같이 삭제되게 한다
photo = models.ImageField(upload_to='photos/%Y/%m/%d', default='photos/no_img.png')#디렉토리 찾는 창을 띄워주는 형식이다.포토 폴더안에 연도/월/날짜 를 만들어준다.
#없으면 no_img.png를 만들어줘서 오류를 방지해준다.
text = models.TextField()#본문 적기
created = models.DateTimeField(auto_now_add=True)#생성된 날짜, 자동으로 현재시간을 추가해준다.
updated = models.DateTimeField(auto_now=True)#수정된 시간을 넣어준다.
class Meta:
ordering = ['-updated'] #업데이트된 시각을 기준으로 정렬한다.(-는 내림차순 없으면 오름차순)
def __str__(self):
return self.author.username + " " + self.created.strftime("%Y-%m-%d")#users안에 username이 있다.
#이름과 시간을 받아온다. 시 분 초가 대문자를 쓰고 나머지는 소문자로 쓴다
######################만들거라고 정의만 한거다.
pip install pillow(사진 저장하려면 설치해야한다)
python manage.py makemigrations photo(만든다)
python manage.py migrate photo(적용하기)
from django.contrib import admin
from .models import * #같은 폴더에 있으면 .만 붙이면된다. 아니면 경로 써줘야함... *은 전체다 불러옴
# Register your models here.
admin.site.register(Photo)#admin에 photo의 데이터를 등록해줬다.
import os
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
베이스 디렉터리를 설정해서 경로를 지정해준다.
admin.site.register(Photo, PhotoAdmin)#admin에 photo의 데이터를 등록해줬다.///만든걸 적용해야한다.
class PhotoAdmin(admin.ModelAdmin):
list_display = ['id', 'author', 'created', 'updated']#리스트를 어떻게 표현할것인가
raw_id_fields = ['author']#기준 id
list_filter = ['created', 'updated', 'author']#단어들이 떠서 검색하기 편함(필터로 쓸 값들)
search_fields = ['text', 'created'] #본문과 생성일 기준으로 검색
ordering = ['-updated', '-created'] #정렬기준은 -(내림차순) 업데이트날짜와 생성 날짜
from django.shortcuts import render, redirect # 다시 주소 돌려주는거 호출
from django.views.generic.edit import CreateView, DeleteView, UpdateView # 기능 호출
from .models import Photo
class PhotoUploadView(CreateView): # 생성되는 페이지를 직접 작성하지 않고 장고에서 생성된거로 쓴다
model = Photo
field = ['photo', 'text'] # 입력은 포토와 텍스트를 가져온다
template_name = 'photo/upload.html' # 여기랑 연결시킨다
def form_valid(self, form):
form.instance.author_id = self.request.user.id # 현재 열려있는 유저 아이디랑 연결시킨다
if form.is_valid(): # 입력없을때 액션하면 오류막아줌
form.instance.save() # 값이 있으면 save
return redirect('/')
else:
return self.render_to_response({'form': form}) # 값이없으면 여기로보낸다
class PhotoDeleteView(DeleteView)
model = Photo
success_url = '/' #성공하면 리스트페이지로 넘긴다
template_name = 'photo/delete.html'
class PhotoUpdateView(UpdateView):#수정
model = Photo
field = ['photo', 'text'] #수정 필드
template_name = 'photo/update.html'
def photo_list(request): # 리스트 페이지를 보여주기 위한... 데이터를 html로 통채로 넘겨주고 html에서 처리하게한다.
photos = Photo.objects.all() # 데이터를 전부 photos에 담겠다
return render(request, 'photo/list.html',
{'photos': photos}) # photoslist req 되면 (photo/list.html 주소일때) {'photos:photos}를 불러온다.
from django.urls import path
from django.views.generic.detail import DetailView
from .models import Photo # 데이터 불러옴
from .views import * # 다불러옴
app_name = 'photo'
urlpatterns = [
path('', photo_list, name='photo_list'), # 없으면 photo_list 호출
path('detail/<int:pk>', DetailView.as_view(model=Photo, template_name='photo/detail.html'), name='photo_detail'),
# 안만들고 바로씀, 그대신 형식 적어줘야함
path('upload/', PhotoUploadView.as_view(), name='photo_upload'), # view에서 정의한거 그대로씀
path('delete/<int:pk>', PhotoDeleteView.as_view(), name='photo_delete'),
path('update/<int:pk>', UpdateView.as_view(), name='photo_update'),
]
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('photo.urls')) # 바로들어가짐, photo.urls로 길 안내를 해준다.
]
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% block title %}{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="">Photo</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" aria-current="page" href="/">Home</a>
</li>
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" aria-current="page" href="">Welcome {{ user.get_username }}</a>
</li>
<li class="nav-item">
<a class="nav-link" aria-current="page" href="{% url 'photo:photo_upload %}">Upload</a>
</li>
<li class="nav-item">
<a class="nav-link" aria-current="page" href="">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" aria-current="page" href="">Login</a>
</li>
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="">SignUp</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-5">
{% block content %}
{% endblock %}
</div>
<footer class="container-fluid footer">
<p>© 2021 Bigdata. Powered by YOO</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>
</body>
</html>
'DIRS': [os.path.join(BASE_DIR,"templates")], 추가
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>GasanGram {% block title %}{% endblock %}</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="/">Gram</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" aria-current="page" href="/">Home</a>
</li>
{% if user.is_authenticated %}
<li class="nav-item">
<a class="nav-link" aria-current="page" href="">Welcome {{ user.get_username }}</a>
</li>
<li class="nav-item">
<a class="nav-link" aria-current="page" href="{% url 'photo:photo_upload' %}">Upload</a>
</li>
<li class="nav-item">
<a class="nav-link" aria-current="page" href="">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" aria-current="page" href="">Login</a>
</li>
<li class="nav-item">
<a class="nav-link" aria-current="page" href="">SignUp</a>
</li>
{% endif %}
</ul>
</div>
</div>
</nav>
<div class="container mt-5">
{% block content %}
{% endblock %}
</div>
<footer class="container-fluid footer">
<p>© 2021 GasanBigdata. Powered By UnionGraphix</p>
</footer>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>
</body>
</html>
{% extends 'base.html' %}
{% block title %}
- List
{% endblock %}
{% block content %}
{% for post in photos %}
<div class="row">
<div class="col-12 panel panel-default">
<div><img src="{{ post.photo.url }}" style="width:100%;"></div>
<p>{{ post.author.username }}</p>
<p>{{ post.text | linebreaksbr }}</p>
<div class="text-right">
<a href="{% url 'photo:photo_detail' pk=post.id %}" class="btn btn-xs btn-success">reply</a>
</div>
</div>
</div>
{% endfor %}
{% endblock %}
from django.contrib import admin
from django.urls import path, include
from django.conf.urls.static import static #고정파일 불러오기
from django.conf import settings
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('photo.urls')) # 바로들어가짐, photo.urls로 길 안내를 해준다.
]
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)#static에 관련된것만 붙여줘!
<meta name="viewport" content="width=device-width, initial-scale=1">
{% extends 'base.html' %}
{% block title %}
{{ object.text | truncatechars:10}}<!-- 10글자만 나오게 만듦-->
{% endblock %}
{% block content %}
<div class="row my-3">
<div class="col-12 panel panel-default">
<div><img src="{{ object.photo.url }}" style="width:100%;"></div>
<p>{{ object.author.username }}</p>
<p>{{ object.text | linebreaksbr }}</p>
<a href="{% url 'photo:photo_delete' pk=object.id %}"class="btn btn-outline-danger btn-sm float-right">Delete</a>
<a href="{% url 'photo:photo_update' pk=object.id %}"class="btn btn-outline-success btn-sm float-right">Modify</a>
</div>
</div>
</div>
{% endblock %}
{% extends 'base.html' %}
{% block title %}
- Delete
{% endblock %}
{% block content %}
<div class="row my-5">
<div class="col-12 panel panel-default">
<div class="alert alert-info">
정말로 {{ object }}을 삭제 하실건가요?
</div>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-danger" value="Confirm">
</form>
</div>
</div>
{% endblock %}
from django.urls import reverse
def get_absolute_url(self):
return reverse('photo:photo_detail', args=[str(self.id)])
#다시넘겨준다
{% extends 'base.html' %}
{% block title %}
{{ object.text | truncatechars:10 }} - update
{% endblock %}
{% block content %}
<div class="row my-5">
<div class="row">
<div class="col-12 panel panel-default">
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-primary" value="Update">
</form>
</div>
</div>
</div>
{% endblock %}
python manage.py startapp accounts
config/settings.py
accounts추가해주기
accounts/urls.py 추가
from django.urls import path
from django.contrib.auth import views as auth_view
urlpatterns = [
path('login/', auth_view.LoginView.as_view(), name='login'),
path('logout/', auth_view.LogoutView.as_view(template_name='registration/logout.html'), name='logout'),
]
path('accounts/', include('accounts.urls')),
{% extends 'base.html' %}
{% block title %}
- Login
{% endblock %}
{% block content %}
<div class="row my-5">
<div class="row">
<div class="col-12 panel panel-default">
<div class="alert alert-info">
로그인
</div>
<form action="" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" class="btn btn-primary" value="Login">
</form>
</div>
</div>
</div>
{% endblock %}
{% extends 'base.html' %}
{% block title %}
- Logout
{% endblock %}
{% block content %}
<div class="row my-5">
<div class="col-12 panel panel-default">
<div class="alert alert-info my-4">
로그아웃 되었습니다.
</div>
<a class="btn btn-primary" href="{% url 'login' %}">Click to Login</a>
</div>
</div>
{% endblock %}
<a class="nav-link" aria-current="page" href="{% url 'logout' %}">Logout</a>
</li>
{% else %}
<li class="nav-item">
<a class="nav-link" aria-current="page" href="{% url 'login' %}">Login</a>