
먼저 근간이 되는 뼈대를 잡아 줘야 한다 "Hello world!"로 테스트를 해 보았지만 진짜는 이제부터!
admin.py
from django.contrib import admin
from django.utils.html import format_html
from .models import BannerImage, ReviewImage, SpecialOffer,CompanyInfo,CompanyVideo, ReviewImage2
@admin.register(BannerImage)
class BannerImageAdmin(admin.ModelAdmin):
list_display = ('alt_text',)
@admin.register(ReviewImage)
class ReviewImageAdmin(admin.ModelAdmin):
list_display = ('alt_text',)
@admin.register(ReviewImage2)
class ReviewImageAdmin(admin.ModelAdmin):
list_display = ('alt_text',)
@admin.register(SpecialOffer)
class SpecialOfferAdmin(admin.ModelAdmin):
list_display = ('description',)
@admin.register(CompanyInfo)
class CompanyInfoAdmin(admin.ModelAdmin):
list_display = (('title', 'description') )
@admin.register(CompanyVideo)
class CompanyVideoAdmin(admin.ModelAdmin):
list_display = ('company_info', 'description', 'video_link')
def video_link(self, obj):
if obj.video:
return format_html('<a href="{0}" target="_blank">View Video</a>', obj.video.url)
return 'No Video'
video_link.short_description = 'Video'
view.py
from django.shortcuts import render
from .models import BannerImage, ReviewImage, ReviewImage2, SpecialOffer
from .models import CompanyInfo
def mainpage(request):
banners = BannerImage.objects.all()
reviews = ReviewImage.objects.all()
reviews2 = ReviewImage2.objects.all()
special_offers = SpecialOffer.objects.all()
context = {
'banners': banners,
'reviews': reviews,
'reviews2': reviews2,
'special_offers': special_offers,
}
return render(request, 'home/mainpage.html', context)
def company(request):
company_info = CompanyInfo.objects.first()
return render(request, 'home/company_info.html', {'company_info': company_info})
apps.py
from django.apps import AppConfig
class HomeConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "home"
urls.py
# home/urls.py
from django.urls import path
from . import views
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('', views.mainpage, name='mainpage'),
path('company/', views.company, name='company'),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

프론트 부분은 부트스트랩을 이용해서 불필요한 HTML 노가다를 줄여 줬다 프레임이 짜여 있어서 편했지만 처음 써 보는 나에게는 적응하기 까지 시간이 조금 걸리기는 했다.
https://getbootstrap.kr/docs/5.1/examples/
참고로 나는 여기서 받았다!
view
<header class="banner-fst">
<div class="container px-lg-5">
<div id="banner-slider">
{% for banner in banners %}
<div class="banner-slide">
<img src="{{ banner.image.url }}" alt="{{ banner.alt_text }}">
</div>
{% endfor %}
</div>
</div>
</header>
JS
2.5초에 한 번 자동으로 넘어가는 배너를 생성
document.addEventListener('DOMContentLoaded', function() {
const bannerSlider = document.getElementById('banner-slider');
let index = 0;
function showBannerSlide() {
const slides = bannerSlider.getElementsByClassName('banner-slide');
for (let i = 0; i < slides.length; i++) {
slides[i].style.display = i === index ? 'block' : 'none';
}
index = (index + 1) % slides.length;
setTimeout(showBannerSlide, 2500);
}
showBannerSlide();

view
<div class="wrap">
<div class="rolling-list" id="roller1">
<!-- 첫 번째 슬라이드 원본 -->
{% for review in reviews %}
<div class="review-slide">
<img src="{{ review.image.url }}" alt="{{ review.alt_text }}">
</div>
{% endfor %}
<!-- 첫 번째 슬라이드 클론 -->
{% for review in reviews %}
<div class="review-slide">
<img src="{{ review.image.url }}" alt="{{ review.alt_text }}">
</div>
{% endfor %}
</div>
</div>
<div class="wrap-2">
<div class="rolling-list-2" id="roller2">
<!-- 두 번째 슬라이드 원본 -->
{% for review in reviews2 %}
<div class="review-slide review-slide2">
<img src="{{ review.image.url }}" alt="{{ review.alt_text }}">
</div>
{% endfor %}
<!-- 두 번째 슬라이드 클론 -->
{% for review in reviews2 %}
<div class="review-slide review-slide2">
<img src="{{ review.image.url }}" alt="{{ review.alt_text }}">
</div>
{% endfor %}
</div>
</div>
JS
클론을 이용해서 이미지가 회전초밥처럼 무한히 움직이게 구현
document.addEventListener('DOMContentLoaded', function() {
function setupRollingSlider(rollerId) {
const roller = document.getElementById(rollerId);
const clone = roller.cloneNode(true);
clone.id = rollerId + '-clone';
document.querySelector('.wrap').appendChild(clone);
// 초기 위치 설정
roller.style.position = 'absolute';
clone.style.position = 'absolute';
roller.style.left = '0px';
clone.style.left = roller.scrollWidth + 'px';
function animateSlider() {
let pos1 = parseFloat(roller.style.left);
let pos2 = parseFloat(clone.style.left);
const rollerWidth = roller.scrollWidth;
pos1 -= 1;
pos2 -= 1;
if (pos1 <= -rollerWidth) {
pos1 = pos2 + rollerWidth;
}
if (pos2 <= -rollerWidth) {
pos2 = pos1 + rollerWidth;
}
roller.style.left = pos1 + 'px';
clone.style.left = pos2 + 'px';
requestAnimationFrame(animateSlider);
}
animateSlider();
}
setupRollingSlider('roller1');
});
document.addEventListener('DOMContentLoaded', function() {
function setupRollingSlider(rollerId) {
const roller = document.getElementById(rollerId);
const clone = roller.cloneNode(true);
clone.id = rollerId + '-clone';
document.querySelector('.wrap-2').appendChild(clone);
roller.style.position = 'absolute';
clone.style.position = 'absolute';
roller.style.left = '0px';
clone.style.left = '-' + roller.scrollWidth + 'px';
function animateSlider() {
let pos3 = parseFloat(roller.style.left);
let pos4 = parseFloat(clone.style.left);
const rollerWidth = roller.scrollWidth;
pos3 += 1;
pos4 += 1;
if (pos3 >= rollerWidth) {
pos3 = pos4 - rollerWidth;
}
if (pos4 >= rollerWidth) {
pos4 = pos3 - rollerWidth;
}
roller.style.left = pos3 + 'px';
clone.style.left = pos4 + 'px';
requestAnimationFrame(animateSlider);
}
animateSlider();
}
setupRollingSlider('roller2');
});
// 이 부분이 꽤나 난관 이었는데 클론도 잘 만들어 지지 않았고
이동이 자꾸 같은곳으로 가는등 문제가 많아 그냥 나누어 줬더니 잘 작동이 되었다

view
<div class="special-offers-container">
<div class="text-section">
<p class="p">✨오늘의 야세지 공구</p><br>
<h5>오늘이 지나면 혜택이 사라져요</h5>
<div id="countdown"></div>
</div>
<div class="offers-wrapper">
<div id="special-offers">
{% for offer in special_offers %}
<div class="special-offer">
<img
src="{{ offer.image.url }}"
alt="{{ offer.description }}"
onclick="window.location.href='/mysite/recomm/{{ offer.id }}/';"
style="cursor: pointer;"/>
</div>
{% endfor %}
</div>
</div>
</div>
{% endblock content %}
JS
24시간 기준 아침11시 이벤트 종료 카운트다운 함수
function updateCountdown() {
const now = new Date();
const deadline = new Date();
deadline.setHours(11, 0, 0, 0);
if (now > deadline) {
deadline.setDate(deadline.getDate() + 1);
}
const timeDiff = deadline - now;
const hours = Math.floor((timeDiff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
const minutes = Math.floor((timeDiff % (1000 * 60 * 60)) / (1000 * 60));
const seconds = Math.floor((timeDiff % (1000 * 60)) / 1000);
document.getElementById('countdown').innerHTML =
`종료까지 ${hours}시간 ${minutes}분 ${seconds}초`;
}
updateCountdown();
setInterval(updateCountdown, 1000);
});
// 이 부분은 수정이 필요하다 만약 상품이 시간 내 품절 된 경우 품절 안내 문자 그리고 시간수정을 조금 해서 대기시간 안내를 해 줄 예정이다 이번프로젝트에서는 자바스크립트 맛보기로 카운트다운을 만들어 보았다
참고로 CSS는 알아서 예쁘게 하면 될거라 생각해서 코드에 안넣었다 템플릿보면 예쁜거 많으니 참고 하세요.....