[Python_django]_3_ 인스타 앱 구현 (사진업로드post, 프로필사이트)

Hyejin Beck·2024년 1월 21일

Python

목록 보기
15/23

Python 부트캠프(멀티잇 데이터 분석&엔지니어링 캠프) 에서 배운 django수업을 기반으로 직접 2023년 8월경 다른 블로그에 작성한 글을 가져왔습니다.
github

프로젝트이름: insta

APP이름: posts

0.기본셋팅

python -m venv venv
source venv/bin/activate
pip install django
django-admin startproject insta .
django-admin startapp posts
settings.py 의 INSTALLED_APPS 추가 
settings.py 의 TEMPLATES [BASE_DIR/'templates'], 추가 
상위폴더 > templates폴더 생성 > base.html 생성 
.gitignore생성 
README.md생성

1. posts모델링

모델링

posts>models.py

class Post(models.Model): 
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    image = models.ImageField(upload_to='image/')
    # ImageField는 Pillow함수가 있어야 사용가능하다. 

사진을 다운받을 수 있는 라이브러리 다운받기

pip install pillow

여기서 잠깐 tip!

현재 작동되는 버전 확인

pip freeze

해당 내용들을 txt로 저장

pip freeze >> requirement.txt 

clone후 다른사람 사용버전 그대로 다운받기

pip install -r requrements.txt

MEDIA_

MEDIA_ROOT와 MEDIA_URL
settings.py 하단

# 업로드한 사진을 저장할 위치 
# media라는 폴더를 만들거고, 그 안에 사진들을 저장할거야. 
MEDIA_ROOT = BASE_DIR / 'media'

# 미디어 경로를 처리할 URL 
# 그리고 그 저장된 사진들을 찾을 때는, 
MEDIA_URL = '/mdeia/'

db번역

models.py에 추가했거나, 변형 일어날 경우마다 해야함

python manage.py makemigrations
python manage.py migrate

관리자계정

admin

from django.contrib import admin
from .models import Post

# Register your models here.
admin.site.register(Post)
python manage.py createsuperuser
python manage.py runserver
http://127.0.0.1:8000/admin/

사진게시글 포스팅

Posts클릭후 이미지 및 게시글 생성

포스팅 후, 상위폴더에 media/image폴더 생성되고, 포스팅한 이미지가 저장됨을 확인할 수 있다.


현재 MEDIA_ROOT를 보면,
BASE_DIR 전체안에 -> media폴더 안에 -> upload_to 라고 image폴더를 만들어서 거기 안에 넣겠다.

사진 정보(날짜추가)

models.py

image = models.ImageField(upload_to='image/%Y/%m')

models.py에 수정이 일어났으니 다시 db접근

python manage.py makemigrat
ions
python manage.py migrate
python manage.py runserver


날짜가 추가된 별도폴더에 저장된다.

저렇게 회색으료 표시 = 자체 gitignore

.gitignore파일에 ###Django### 를 보면
media가 포함되어 있다.

2.Read(all)기본페이지

urls.py

from django.contrib import admin
from django.urls import path, include # include추가 

urlpatterns = [
    path("admin/", admin.site.urls),
    path('posts/', include('posts.urls')),

posts> urls.py 생성

from django.urls import path
from . import views 

app_name = 'posts'

urlpatterns - [
    path('',views.index, name='index'),
]

views.py

def index(request): 
    pass 

기본html꾸미기

기본셋팅

base.html
! 하고 tab 으로 기본폼 불러오기

bootstrap으로 꾸밀거라 CSS코드,JS코드 붙혀넣기

CSS코드는 </head> 바로 전에, JS코드는 </body> 바로 전에 붙힌다. 

{빈공간} 만들고 위아래로 container박스화해서 꾸미자

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
</head>
<body>
    
    
    
    <div class="container">
        {% block body %}     
        {% endblock %}  
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>
</body>
</html>

templates폴더 > _nav.html생성
bootstrap에서 NavBar맘에드는 코드

<nav class="navbar navbar-expand-lg bg-body-tertiary">
  <div class="container-fluid">
    <a class="navbar-brand" href="#">Navbar</a>
    <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
      <span class="navbar-toggler-icon"></span>
    </button>
    <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
      <div class="navbar-nav">
        <a class="nav-link active" aria-current="page" href="#">Home</a>
        <a class="nav-link" href="#">Features</a>
        <a class="nav-link" href="#">Pricing</a>
        <a class="nav-link disabled" aria-disabled="true">Disabled</a>
      </div>
    </div>
  </div>
</nav>

기본세팅+NavBar

base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-4bw+/aepP/YC94hEpVNVgiZdgIC5+VKNBQNGCHeKRQN+PtmoHDEXuppvnDJzQIu9" crossorigin="anonymous">
</head>
<body>
    
    {% include '_nav.html' %}  <!--여기 넣읍니다-->

    <div class="container">
        {% block body %}     
        {% endblock %}  
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-HwwvtgBNo3bZJJLYd8oVXjrBZt8cqVSpeBNS5n7C8IVInixGAoxmnlMuBnhbgrkm" crossorigin="anonymous"></script>
</body>
</html>

기능구현

views.py

from .models import Post

def index(request): 
    posts = Post.objects.all()

    context = {
        'posts' : posts, 
    }

    return render(request, 'index.html', context)

posts>templates폴더>index.html

{% extends 'base.html' %}

{% block body %}

    {{posts}}
    
{% endblock %}

확인
http://127.0.0.1:8000/posts/

card넣기

posts>templates>_card.html생성
bootstrap card코드

<div class="card" style="width: 18rem;">
    <img src="..." class="card-img-top" alt="...">
    <div class="card-body">
      <h5 class="card-title">Card title</h5>
      <p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
      <a href="#" class="btn btn-primary">Go somewhere</a>
    </div>
  </div> 

index.html

{% extends 'base.html' %}

{% block body %}

    {% for post in posts %}
        {% include '_card.html' %}
    {% endfor %}

{% endblock %}

확인
http://127.0.0.1:8000/posts/

card에 이미지넣기

_card.html 잠깐 수정

<div class="card" style="width: 18rem;">
    <img src="..." class="card-img-top" alt="...">
    <div class="card-body">
      <!--<h5 class="card-title">Card title</h5>-->
      <p class="card-text">{{post.content}}</p>
      <!--<a href="#" class="btn btn-primary">Go somewhere</a>-->
    </div>
  </div>

여기서 잠깐!
image는 표 형식이 아닌 정보이다.
post.image를 적어 출력하면, 그냥 그 image의 이름이 나온다.
이제 우리는 이미지의모습과 저장되어있는이미지를 일치화한다.

이미지url주소

insta>urls.py

from django.contrib import admin
from django.urls import path, include # include추가 
from django.conf import settings   # 이미지 출력시 
from django.conf.urls.static import static # 이미지출력시 

urlpatterns = [
    path("admin/", admin.site.urls),
    path('posts/', include('posts.urls')),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT) 
# 이 image를 처리할 때, urls주소를 저장하고, 그 이미지의 위치는 저기 settings.py안에 있어요. 

일치화->image출력

_card.html
{{post.image.url}} 를 추가해보자.

<div class="card" style="width: 18rem;">
    <img src="..." class="card-img-top" alt="...">
    <div class="card-body">
      <!--<h5 class="card-title">Card title</h5>-->
      <p class="card-text">{{post.content}}</p>
      <p>{{post.image}}</p>
      <p>{{post.image.url}}</p>
      <!--<a href="#" class="btn btn-primary">Go somewhere</a>-->
    </div>
  </div>


img src="{{post.image.url}}" 을 추가해줘야한다.
_card.html

<div class="card" style="width: 18rem;">
    <img src="{{post.image.url}}" class="card-img-top" alt="...">
    <div class="card-body">
      <!--<h5 class="card-title">Card title</h5>-->
      <p class="card-text">{{post.content}}</p>
      <!--<a href="#" class="btn btn-primary">Go somewhere</a>-->
    </div>
  </div>

db인 sql상에서 저장되있는 이미지 url주소와
static이라는 정적파일(표가 아닌) 로 경로로 만들고, 실제 파일이 저장되있는 위치를 알려준다.

어떤 경로로 들어왔을 때, 실제 실행할 (보여줄) 파일을 알려준다.

그래야 화면에 출력시, 이미지를 출력하는게 아니라

static이 만들어준 경로로 따라,
사진을 가져오고, 화면에 보여준다.

3. Create

_nav.html

<nav class="navbar navbar-expand-lg bg-body-tertiary">
    <div class="container-fluid">
      <a class="navbar-brand" href="{% url 'posts:index' %}">Home</a>
      <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNavAltMarkup" aria-controls="navbarNavAltMarkup" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarNavAltMarkup">
        <div class="navbar-nav">
          <a class="nav-link" href="{% url 'posts:create' %}">Create</a>
          <a class="nav-link" href="#">Features</a>
          <a class="nav-link" href="#">Pricing</a>
          <a class="nav-link disabled" aria-disabled="true">Disabled</a>
        </div>
      </div>
    </div>
  </nav>

posts>urls.py

from django.urls import path
from . import views 

app_name = 'posts'

urlpatterns = [
    path('',views.index, name='index'),
    path('create/',views.create, name='create'),
]

views.py

def create(request): 
    if request.method == 'POST': 
        pass
    else: 
        pass

posts>forms.py생성

from django import forms 
from .models import Post 

class PostForm(forms.ModelForm): 
    class Meta: 
        model = Post 
        fields = '__all__'

views.py

from .forms import PostForm



def create(request): 
    if request.method == 'POST': 
        pass
    else: 
        form = PostForm()

    context = {
        'form': form,
    }
    return render(request,'form.html',context)

posts>templates폴더>form.html

{% extends 'base.html' %}

{% block body %}


{% endblock %}

이제 조건문으로 게시글 하나하나

{% extends 'base.html' %}

{% block body %}
    <form action="" method="POST">
        {% csrf_token %}
        {{form}}
        <input type="submit">
    </form>

{% endblock %}

확인
http://127.0.0.1:8000/posts/create/

but!
작성후 이미지 넣고 제출하면 error

사진을 넣는게 아니라, 사진있는 위치를 알려줘야한다.

사진넣기

form.html
enctype="multipart/form-data" 추가해주기

{% extends 'base.html' %}

{% block body %}
    <form action="" method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        {{form}}
        <input type="submit">
    </form>

{% endblock %}

http://127.0.0.1:8000/posts/create/
게시글 작성 및 이미지 넣고 제출 하면 해당 error 발생되어야함

안에 파일(값)은 들어가 있는 상태이다.
이제 사용자가 입력한 사진(get)요청을 -> post화 하여 출력시키자

views.py

def create(request): 
    if request.method == 'POST': 
        form = PostForm(request.POST, request.FILES)
        # request.POST 사용자가 입력한 사진 
        # request.FILES 그 사진을 파일화 함 
        if form.is_valid(): 
            form.save() 
            return redirect('posts:index')
from django.shortcuts import render, redirect # redirect추가 

확인

포스팅-날짜추가,최신정렬

작성시간

목표:
_card.html
{{post.content}} 아래에 내용 추가

<p class="card-text">{{post.created_at}}</p>

작성시간(얼마나흘렀는지)

timesince를 이용해보자

<p class="card-text">{{post.created_at |timesince}}</p>

작성순서대로 정렬

order_by()적용
views.py

def index(request): 
    posts = Post.objects.all() 
    # 모든 값을 보여줘 
    posts = Post.objects.all().order_by('-id')
    # id값(작성순서)를 역순으로 보여줘
    # 최신작성된 거 먼저 보여줘

포스팅-사진 사이즈

현재는 업로드한 사진들을 원본 그대로 저장하기때문에, 비율이 제각각이다.

외부라이브러리를 이용해서, 크롭화 기능을 시키자
django resized

잠시 ctrl+c로 기능 끄고 설치하자.

pip install django-resized

그리고 설치한 걸 기록화 해주자

pip freeze >> requirements.txt

models.py

from django.db import models
from django_resized import ResizedImageField # 이미지크롭화 


class Post(models.Model): 
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    # image = models.ImageField(upload_to='image/%Y/%m')
    # 그리고 이걸 추가 
    image = ResizedImageField(
        size=[500,500],
        crop=['middle', 'center'], 
        upload_to='image/%Y/%m'
    )  

models.py에 수정이 생겼으니, db 도 업데이트

python manage.py makemigrations 
python manage.py migrate
python manage.py runserver

확인

원본사진 그대로가 아닌, 규격화한 사이즈대로 포스팅된다.

규격화하는 외부라이브러리는

이 외에도 많다.
그나마 쉬워보이는 걸로 적용하긴 했다.

4. user기능추가

accounts앱

accounts앱 모델링

django-admin startapp accounts

settings.py

INSTALLED_APPS = [

    "accounts",
]

insta>urls.py

path('accounts/', include('accounts.urls')),

accounts>urls.py생성

from django.urls import path
from . import views 

app_name = 'accounts'

urlpatterns = [
    path('signup/', views.signup, name='signup'),
]

accountsviews.py

from django.shortcuts import render

# Create your views here.

def signup(request): 
    if request.method == 'POSt': 
        pass
    else: 
        pass

accountsmodels.py

from django.db import models
from django.contrib.auth.models import AbstractUser
from django_resized import ResizedImageField

# Create your models here.

class User(AbstractUser): 
    # 컬럼은 일단 하나만 추가 
    profile_image = ResizedImageField(
        size=[500,500], 
        crop=['middle','center'],
        upload_to='profile',
    ) 

settings.py

AUTH_USER_MODEL = 'accounts.USER' # 추가 

db초기화


빨간거 삭제

``

python manage.py makemigrations
python manage.py migrage 

그래도 안되면 db.sqlite3 삭제

python manage.py migrage 

두 APP의 1:N 모델링

accounts 의 models.py
posts 의 modesl.py
를 1: N 연결
postsmodels.py

from django.conf import settings 

    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)


models.py 두 개나 수정했으니,
다음은 뭐다????

db초기화

accounts> migrations > 0001 파일 삭제

posts> migrations > 0001 파일 삭제

db.sqlite3 삭제

다시 재설치

python manage.py makemigrations
python manage.py migrate

모델폼 생성

accounts>forms.py 생성

from django.contrib.auth.forms import UserCreationForm 
from .models import User 
from django.contrib.auth import get_user_model 

class CustomUserCreationForm(UserCreationForm): 
    class Meta: 
        model = get_user_model() 
        # model = User 를 대신 사용할 수 있는데 
        # 다만, get_user_model() 쓰는게 유지보수하기 좋다. 
        fields = ('username', 'profile_image',) 
        # profile_image = 사용자가 회원가입할때 프로필사진 올릴수있도록 

views.py

from django.shortcuts import render
from .forms import CustomUserCreationForm # 모델폼 추가 

# Create your views here.

def signup(request): 
    if request.method == 'POST': 
        pass
    else: 
        form = CustomUserCreationForm()  # 모델폼으로 보여주게 해줘(작성할수있도록)

    context = {
        'form': form, 
    }
    return render(request, 'form.html', context)
    # 아직 form.html 파일을 만들지 않았는데 , 
    # 여기까지 후 작동하게 되면 


아직 form.html 파일을 만들지 않았는데
여기까지 후 작동하게 되면 작성할수있는 어떤 form이 나온다!
이때 나오는건, posts>templates>forms.html 이다.

전체프로젝트폴더 내의 templates 의 .html 을 모아놓고
해당 요청하는 form.html 똑같은 이름이 있으니까 보여주는거다.

폴더 순서대로있는 .html 으로 조회된다.

1. 파일의 이름을 다르게 해도 되고,

2. templates폴더>accounts폴더로 생성>form.html생성 하면

accounts>views.py

return render(request, 'accounts/form.html', context)

accounts>templates>accounts폴더생성>form.html 생성

{% extends 'base.html' %}

{% block body %}
<h1>signup</h1>
    <form action="" method="POST" >
        {% csrf_token %}
        {{form}}
        <input type="submit">
    </form>

{% endblock %}

뭐 어자피 현재로서는 form.py 안의 내용물은 똑같아서 똑같이 출력되긴 한데,,, 헷갈리니까 signup의 form.html은 signup을 추가해보자

signup페이지꾸미기

bootstrap코드 불러오기

pip install django-bootstrap-v5

뭔가 install했을때는 그걸 저장해주자

pip freeze >> requirements.txt

settings.py

INSTALLED_APPS = [

    'bootstrap5'
]

accounts>templates>accounts>views.html for signup

{% extends 'base.html' %}
{% load bootstrap5 %}

{% block body %}
<h1>signup</h1>
    <form action="" method="POST" >
        {% csrf_token %}
        {% bootstrap_form form %}
        <input type="submit">
    </form>

{% endblock %}

signup입력값 기능

views.py

from django.shortcuts import render, redirect # redirect 추가 



def signup(request): 
    if request.method == 'POST': 
        form = CustomUserCreationForm(request.POST, request.FILES)
        if form.is_valid(): 
            form.save() 
            return redirect('posts:index')

form.html

{% extends 'base.html' %}
{% load bootstrap5 %}

{% block body %}
    <form action="" method="POST" enctype="multipart/form-data">
        {% csrf_token %}
        {% bootstrap_form form %}
        <input type="submit">
    </form>

{% endblock %}

login

_nav.html
signup, login 버튼생성

          <a class="nav-link" href="{% url 'posts:create' %}">Create</a> 
          <a class="nav-link" href="{% url 'accounts:signup' %}">Signup</a>
          <a class="nav-link" href="{% url 'accounts:login' %}">Login</a>

accountsurls.py

path('login/',views.login, name='login'),
]

accountsviews.py

def login(request): 
    if request.method == 'POST': 
        pass 
    else: 
        pass 

accountsforms.py

from django.contrib.auth.forms import UserCreationForm , AuthenticationForm 
# AuthenticationForm 추가 


class CustomAuthenticationForm(AuthenticationForm): 
    pass 

accountsviews.py

from .forms import CustomUserCreationForm , CustomAuthenticationForm




def login(request): 
    if request.method == 'POST': 
        pass 
    else: 
        form = CustomAuthenticationForm() 
    
    context = {
        'form': form, 
    }
    return render(request, 'accounts/form.html', context)

추가
views.py

from .forms import CustomUserCreationForm , CustomAuthenticationForm
from django.contrib.auth import login as auth_login




def login(request): 
    if request.method == 'POST': 
        form = CustomAuthenticationForm(request, request.POST)
        if form.is_valid(): 
            user = form.get_user()
            auth_login(request,user)
            return redirect('posts:index')

login 기능 구현

_nav.html
{{user}} 추가

        <div class="navbar-nav">
          <a class="nav-link" href="{% url 'posts:create' %}">Create</a>
          <a class="nav-link" href="{% url 'accounts:signup' %}">Signup</a>
          <a class="nav-link" href="{% url 'accounts:login' %}">Login</a>
          <a class="nav-link disabled" aria-disabled="true">{{user}}</a>
        </div>

조건문 추가
user가 로그인했나요?

        <div class="navbar-nav">
            {% if user.is_authenticated %}
          <a class="nav-link" href="{% url 'posts:create' %}">Create</a>
          <a class="nav-link disabled" aria-disabled="true">{{user}}</a>
          {% else %}
          <a class="nav-link" href="{% url 'accounts:signup' %}">Signup</a>
          <a class="nav-link" href="{% url 'accounts:login' %}">Login</a>
          {% endif %}
        </div>

create작성자 감추기

postsforms.py

# fields='__all__'대신, 
exclude = ('user',)

로그인 상태에서 포스팅 완료

postsviews.py

def create(request): 
    if request.method == 'POST': 
        form = PostForm(request.POST, request.FILES)
        if form.is_valid(): 
            post = form.save(commit=False)
            post.user = request.user
            post.save() 
            return redirect('posts:index')

프로필이미지 출력기능

_card.html

<div class="card" >
    <div class="card-header">
        <img src="{{post.user.profile_image.url}}" alt="">
        <p>{{post.user}}</p>
    </div>
    <img src="{{post.image.url}}" alt="...">
    <div class="card-body">
      <!--<h5 class="card-title">Card title</h5>-->
      <p class="card-text">{{post.content}}</p>
      <p class="card-text">{{post.created_at |timesince}}</p>
      <!--<a href="#" class="btn btn-primary">Go somewhere</a>-->
    </div>
  </div>

이렇게 되면 프로필사진 + 작성사진 까지 크~게 나온다.

<img src="{{post.user.profile_image.url}}" alt="" class="rouned-circle" width="30px">
<div class="card" style="width: 18rem;">
    <div class="card-header">
        <p>
            <img src="{{post.user.profile_image.url}}" alt="" class="rounded-circle" width="50px">
            {{post.user}}
        </p>
    </div>
    <img src="{{post.image.url}}" alt="...">
    <div class="card-body">
      <!--<h5 class="card-title">Card title</h5>-->
      <p class="card-text">{{post.content}}</p>
      <p class="card-text">{{post.created_at |timesince}}</p>
      <!--<a href="#" class="btn btn-primary">Go somewhere</a>-->
    </div>
  </div>

프로필페이지

유저 클릭하면, 그 유저의 프로필페이지를 만들어보자.

accountsurls.py

    path('<str:username>/', views.profile, name='profile'),
    # 여기에는 accounts/가 앞에 생략되었다. 

accountsviews.py

from .models import User # 이렇게 직접가져오는것 보다는 유지보수 차원에서 아래 추천 
from django.contrib.auth import get_user_model




def profile(request, username): 
    User = get_user_model()
    # 해당 프로필에 적용되는 일단, 모든 유저를 불러와줘 

    # User.objects.get(username=username)
    # id로 찾는게 아니라, username으로 찾아야한다. 
    user_info = User.objects.get(username=username)

    context = {
        'user_info': user_info
    }
    return render(request, 'accounts/profile.html', context)

accounts>templates>accounts>profile.html생성

{% extends 'base.html' %}
{% load bootstrap5 %}

{% block body %}

{{user_info}}

{% endblock %}

http://127.0.0.1:8000/accounts/유저이름/

프로필에 사진출력

profile.html

{% extends 'base.html' %}
{% load bootstrap5 %}

{% block body %}

<div class="row">
    <div class="col-4">
        <img src="{{user_info.profile_image.url}}" alt="">
    </div>
    <div class="col-8">
        2
    </div>
</div>

{% endblock %}

사진 둥글게 + 사이즈줄이면 사진도줄이는 fluid반응형기능

<img src="{{user_info.profile_image.url}}" alt="" class="img-fluid rounded-circle">


사진 옆 기능 추가

profile.html

    <div class="col-8"> <!--8-->
        <div class="row"></div>
            <div class="col-4">{{user_info.username}}</div>
            <div class="col-4"><a href="">팔로우</a></div>
        <div class="row"></div>

하단

        <div class="row">
            <div class="col">게시물</div>
            <div class="col">팔로잉</div>
            <div class="col">팔로우</div>
        </div>

더 하단
이제 포스트 한 갯수만큼 이미지

{% for post in user_info.post_set.all %}

{% endfor %}

{% endblock %}

근데 이걸 카드화

{% for post in user_info.post_set.all %}
    <div>
        <img src="{{post.image.url}}" alt="">
    </div>
{% endfor %}

사진출력시 grid화

한 줄에 3개씩
div.row.row-col3 누르고 tab
profile.html

<div class="row row-cols-3">
    {% for post in user_info.post_set.all %}
        <div class='col'>
            <div class="card">
                <img src="{{post.image.url}}" alt="">
            </div>
        </div>
    {% endfor %}
</div>
{% endblock %}


user이름클릭>프로필페이지이동

_card.html
{{post.user}} 에 이동페이지 url

<a href="{% url 'accounts:profile' username=post.user %}">{{post.user}}</a>



http://127.0.0.1:8000/posts/에서 어떤 유저 클릭
-> http://127.0.0.1:8000/accounts/blue/ 그 유저의 프로필사이트로 이동

_nav.html

          <a class="nav-link" href="{% url 'accounts:profile' username=user %}" >{{user}}</a>


<a태그> 푸른색 제거

_card.html
class="text-reset"
text-decoration-none추가

<a href="{% url 'accounts:profile' username=post.user %}" class="text-reset text-decoration-none">{{post.user}}</a>

profile
데이터기반 스토리텔링을 통해 인사이트를 얻습니다.

0개의 댓글