django를 사용하여 뉴스 앱 빌드
48527 단어 djangopythonwebdevjavascript
이 앱은 Google News에서 영감을 받았습니다.
프로젝트에 대한 종속성 설치
pip install django
pip install requests
django 프로젝트 설정
django에 대한 자세한 내용은 페이지를 참조하십시오.
이제 프로젝트를 만들 수 있습니다.
django-admin startproject newsapp
cd newsapp
프로젝트가 작동하는지 확인하려면 다음 명령을 실행하십시오.
python manage.py runserver
프로젝트 생성이 성공했음을 의미하는 로켓 페이지가 표시될 것입니다. 이 명령을 실행하면 제거하라는 경고가 미적용 마이그레이션과 같은 터미널에 표시되더라도 말입니다.
이 명령은 기본 마이그레이션을 세션, 사용자 테이블과 같은 데이터베이스로 이동합니다.
python manage.py migration
이 디렉터리에서 manage.py 파일과 newsapp 디렉터리를 찾을 수 있습니다. 그런 다음 앱 호출 리더를 만듭니다.
python manage.py startapp reader
이제 setting.py에 앱 리더를 추가해야 합니다.
이것은 django가 레코드 앱을 식별하는 데 도움이 됩니다.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'reader',
]
https://newsapi.org/ 에서 API 키를 받는 것을 잊지 마세요.
그런 다음 setting.py에 api 키를 추가하십시오.
APIKEY = "XXXXXXXXXXXXXXXXXXX"
보기 및 URL
우리가 논리를 쓸 곳
reader 디렉토리 내에 urls.py를 생성한 후 reader/urls.py 파일을 newsapp/urls.py에 연결합니다.
이것은 모든 URL의 마스터 역할을 할 것입니다.
from django.contrib import admin
from django.urls import path
from django.conf.urls import include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include("reader.urls")),
]
NewsApi
이 API는 모든 출처에서 최고의 뉴스를 얻을 것입니다.
url = https://newsapi.org/v2/top-headlines?country=us&apiKey=XXXXXXXXXXXXXXXXXXX
데이터를 얻기 위해 사용자 ** 파이썬 요청 **
r = requests.get(url=url)
data = r.json()
데이터는 다음과 같습니다
{
"status": "ok",
"totalResults": 38,
-"articles": [
-{
-"source": {
"id": null,
"name": "CNET"
},
"author": "Amanda Kooser",
"title": "Ancient underground lakes discovered on Mars - CNET",
"description": "Mars could be home to more liquid water than we originally thought.",
"url": "https://www.cnet.com/news/ancient-underground-lakes-found-on-mars/",
"urlToImage": "https://cnet2.cbsistatic.com/img/OJOEhYPBRrJmmwv03JD_1RF2wPI=/1200x630/2015/02/09/3a560b3c-d9eb-4f0c-af5c-9e9671844c93/mars-ice-cap.jpg",
"publishedAt": "2020-09-29T16:14:00Z",
"content": "This beautiful..."
}]}
콘텐츠를 표시하는 보기를 만들 수 있습니다.
def home(request):
page = request.GET.get('page', 1)
search = request.GET.get('search', None)
if search is None or search=="top":
# get the top news
url = "https://newsapi.org/v2/top-headlines?country={}&page={}&apiKey={}".format(
"us",1,settings.APIKEY
)
else:
# get the search query request
url = "https://newsapi.org/v2/everything?q={}&sortBy={}&page={}&apiKey={}".format(
search,"popularity",page,settings.APIKEY
)
r = requests.get(url=url)
data = r.json()
if data["status"] != "ok":
return HttpResponse("<h1>Request Failed</h1>")
data = data["articles"]
context = {
"success": True,
"data": [],
"search": search
}
# seprating the necessary data
for i in data:
context["data"].append({
"title": i["title"],
"description": "" if i["description"] is None else i["description"],
"url": i["url"],
"image": temp_img if i["urlToImage"] is None else i["urlToImage"],
"publishedat": i["publishedAt"]
})
# send the news feed to template in context
return render(request, 'index.html', context=context)
위의 홈 보기는 트렌드 뉴스 또는 요청된 검색어를 반환한 다음 템플릿에 전달하여/reader/templates/index.html 내부에 템플릿 파일을 생성해야 하는 프런트엔드에서 렌더링합니다.
<!-- to get the next page content -->
<!-- in each ajax success request page value gets incremented -->
var page = 2;
<!-- we are using infinity scrolling in this page to get data -->
<!-- to prevent the unnecessary call -->
var window_scroll = true;
<!-- to get the news related to the page on -->
var search = "{{ search }}";
<!-- this will listen when scrolling -->
window.addEventListener('scroll', function(e) {
console.log("Hi Dude...");
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>News App</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>
<div>
{% include 'sidebar.html' %}
</div>
<div class="container" id="articles-container">
{% for value in data %}
<div class="card mb-3 box" style="max-width: 640px; margin:auto;">
<div class="row">
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title"><a href="{{value.url}}" target="_blanck">{{value.title}}</a></h5>
<p class="card-text">{{value.description}}</p>
<p class="card-text"><small class="text-muted">{{value.publishedat}}</small></p>
</div>
</div>
<div class="col-md-4 img-box">
<img src="{{value.image}}" class="card-img" alt="..." height="100%">
</div>
</div>
</div>
{% endfor %}
</div>
<h1 id="loading">Loading....</h1>
</body>
<style>
#articles-container{
margin-left: 250px;
}
.box{
transition-property: box-shadow, transform;
transition-duration: 1s;
}
.box:hover{
/* box-shadow: 2px 2px 5px #8080807a; */
box-shadow: 1px 2px 8px 0px #00bcffb0;
transform: translateY(-9px);
}
.img-box{
padding: 20px;
}
.img-box img{
border-radius: 15px;
object-fit: cover;
}
#loading{
text-align: center;
display: none;
}
</style>
<script>
$(document).ready(function() {
console.log( "ready!" );
el = document.getElementsByClassName("text-muted")
for (i = 0; i < el.length; i++) {
t = document.getElementsByClassName("text-muted")[i].innerText
var d = new Date(t)
document.getElementsByClassName("text-muted")[i].innerText = d.toDateString()
}
});
var page = 2;
var window_scroll = true;
var search = "{{ search }}";
window.addEventListener('scroll', function(e) {
// scroll check
console.log("scroll check...")
if(window_scroll){
if((window.innerHeight + window.scrollY) >= (document.body.scrollHeight-200)){
window_scroll = false;
document.getElementById("loading").style.display = "block";
$.ajax({
url: '/next?page=' + page + '&search=' + search,
dataType: 'json',
success: function (data) {
if (data["success"]) {
articles = data["data"]
articles_html = ''
for (i = 0; i < articles.length; i++) {
articles_html += ' \
<div class="card mb-3 box" style="max-width: 640px; margin:auto;">\
<div class="row">\
<div class="col-md-8">\
<div class="card-body">\
<h5 class="card-title"><a href="'+ articles[i]["url"] +'" target="_blanck">'+ articles[i]["title"] +'</a></h5>\
<p class="card-text">'+ articles[i]["description"] +'</p>\
<p class="card-text"><small class="text-muted">'+ articles[i]["publishedat"] +'</small></p>\
</div>\
</div>\
\
<div class="col-md-4 img-box">\
<img src="'+ articles[i]["image"] +'" class="card-img" alt="..." height="100%">\
</div>\
</div>\
</div>\
'
}
$("#articles-container").append(articles_html);
page += 1
window_scroll = true;
document.getElementById("loading").style.display = "none";
}
else {
console.log("Failed")
window_scroll = true;
document.getElementById("loading").style.display = "none";
}
}
});
}
}
})
</script>
</html>
그런 다음/reader/template/sidebar.html 안에 다른 템플릿 파일을 만듭니다.
Get 메서드에서 쿼리 매개변수를 보내는 django 방법
<a href="{% url 'Home' %}?search=Business">Business</a>
<style>
.sidebar{
position: fixed;
width: 200px;
height: 100%;
top: 0px;
left: 0px;
}
.sidebar a{
width: 250px;
display: block;
margin: 24px 0px;
padding: 10px 5px;
font-weight: bolder;
font-size: large;
text-decoration: none;
background-color: #d9e4ffc7;
border-top-right-radius: 30px;
border-bottom-right-radius: 30px;
box-shadow: 0px 0.5px 1px grey;
text-align: center;
}
</style>
<div class="sidebar">
<a href="{% url 'Home' %}">Home</a>
<a href="{% url 'Home' %}?search=top">Top News</a>
<a href="{% url 'Home' %}?search=Business">Business</a>
<a href="{% url 'Home' %}?search=Technology">Technology</a>
<a href="{% url 'Home' %}?search=Entertainment">Entertainment</a>
<a href="{% url 'Home' %}?search=Sports">Sports</a>
<a href="{% url 'Home' %}?search=Science">Science</a>
<a href="{% url 'Home' %}?search=Health">Health</a>
</div>
홈 보기 기능에서 html 페이지를 렌더링하고 사용자가 페이지를 스크롤하는 동안 뉴스를 업데이트하기 위해 추가 API가 필요하므로 전체 페이지를 로드하지 않고도 웹을 더 다루기 어렵게 만듭니다.
ajax 요청을 사용하여 이 loadcontent api에서 json 값을 가져옵니다.
def loadcontent(request):
try:
page = request.GET.get('page', 1)
search = request.GET.get('search', None)
# url = "https://newsapi.org/v2/everything?q={}&sortBy={}&page={}&apiKey={}".format(
# "Technology","popularity",page,settings.APIKEY
# )
if search is None or search=="top":
url = "https://newsapi.org/v2/top-headlines?country={}&page={}&apiKey={}".format(
"us",page,settings.APIKEY
)
else:
url = "https://newsapi.org/v2/everything?q={}&sortBy={}&page={}&apiKey={}".format(
search,"popularity",page,settings.APIKEY
)
print("url:",url)
r = requests.get(url=url)
data = r.json()
if data["status"] != "ok":
return JsonResponse({"success":False})
data = data["articles"]
context = {
"success": True,
"data": [],
"search": search
}
for i in data:
context["data"].append({
"title": i["title"],
"description": "" if i["description"] is None else i["description"],
"url": i["url"],
"image": temp_img if i["urlToImage"] is None else i["urlToImage"],
"publishedat": i["publishedAt"]
})
return JsonResponse(context)
except Exception as e:
return JsonResponse({"success":False})
뷰와 템플릿을 만들었고 액세스하려면 URL을 제공해야 합니다.
from django.urls import path
from reader import views
urlpatterns = [
path('', views.home, name="Home"),
path('next', views.loadcontent, name="Loadcontent"),
]
이 API를 사용하여 Json 데이터를 가져오고 그에 따라 쿼리 매개변수를 보낼 수 있습니다.
path('next', views.loadcontent, name="Loadcontent"),
이제 앱을 실행하면 볼 수 있습니다.
마침내 우리는 해냈다
프로젝트 구조입니다
감사합니다. 좋은 하루 되세요.🤪😎
Reference
이 문제에 관하여(django를 사용하여 뉴스 앱 빌드), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다
https://dev.to/magesh236/news-app-in-django-2dcd
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념
(Collection and Share based on the CC Protocol.)
url = https://newsapi.org/v2/top-headlines?country=us&apiKey=XXXXXXXXXXXXXXXXXXX
r = requests.get(url=url)
data = r.json()
{
"status": "ok",
"totalResults": 38,
-"articles": [
-{
-"source": {
"id": null,
"name": "CNET"
},
"author": "Amanda Kooser",
"title": "Ancient underground lakes discovered on Mars - CNET",
"description": "Mars could be home to more liquid water than we originally thought.",
"url": "https://www.cnet.com/news/ancient-underground-lakes-found-on-mars/",
"urlToImage": "https://cnet2.cbsistatic.com/img/OJOEhYPBRrJmmwv03JD_1RF2wPI=/1200x630/2015/02/09/3a560b3c-d9eb-4f0c-af5c-9e9671844c93/mars-ice-cap.jpg",
"publishedAt": "2020-09-29T16:14:00Z",
"content": "This beautiful..."
}]}
def home(request):
page = request.GET.get('page', 1)
search = request.GET.get('search', None)
if search is None or search=="top":
# get the top news
url = "https://newsapi.org/v2/top-headlines?country={}&page={}&apiKey={}".format(
"us",1,settings.APIKEY
)
else:
# get the search query request
url = "https://newsapi.org/v2/everything?q={}&sortBy={}&page={}&apiKey={}".format(
search,"popularity",page,settings.APIKEY
)
r = requests.get(url=url)
data = r.json()
if data["status"] != "ok":
return HttpResponse("<h1>Request Failed</h1>")
data = data["articles"]
context = {
"success": True,
"data": [],
"search": search
}
# seprating the necessary data
for i in data:
context["data"].append({
"title": i["title"],
"description": "" if i["description"] is None else i["description"],
"url": i["url"],
"image": temp_img if i["urlToImage"] is None else i["urlToImage"],
"publishedat": i["publishedAt"]
})
# send the news feed to template in context
return render(request, 'index.html', context=context)
<!-- to get the next page content -->
<!-- in each ajax success request page value gets incremented -->
var page = 2;
<!-- we are using infinity scrolling in this page to get data -->
<!-- to prevent the unnecessary call -->
var window_scroll = true;
<!-- to get the news related to the page on -->
var search = "{{ search }}";
<!-- this will listen when scrolling -->
window.addEventListener('scroll', function(e) {
console.log("Hi Dude...");
}
<!DOCTYPE html>
<html lang="en">
<head>
<title>News App</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>
<div>
{% include 'sidebar.html' %}
</div>
<div class="container" id="articles-container">
{% for value in data %}
<div class="card mb-3 box" style="max-width: 640px; margin:auto;">
<div class="row">
<div class="col-md-8">
<div class="card-body">
<h5 class="card-title"><a href="{{value.url}}" target="_blanck">{{value.title}}</a></h5>
<p class="card-text">{{value.description}}</p>
<p class="card-text"><small class="text-muted">{{value.publishedat}}</small></p>
</div>
</div>
<div class="col-md-4 img-box">
<img src="{{value.image}}" class="card-img" alt="..." height="100%">
</div>
</div>
</div>
{% endfor %}
</div>
<h1 id="loading">Loading....</h1>
</body>
<style>
#articles-container{
margin-left: 250px;
}
.box{
transition-property: box-shadow, transform;
transition-duration: 1s;
}
.box:hover{
/* box-shadow: 2px 2px 5px #8080807a; */
box-shadow: 1px 2px 8px 0px #00bcffb0;
transform: translateY(-9px);
}
.img-box{
padding: 20px;
}
.img-box img{
border-radius: 15px;
object-fit: cover;
}
#loading{
text-align: center;
display: none;
}
</style>
<script>
$(document).ready(function() {
console.log( "ready!" );
el = document.getElementsByClassName("text-muted")
for (i = 0; i < el.length; i++) {
t = document.getElementsByClassName("text-muted")[i].innerText
var d = new Date(t)
document.getElementsByClassName("text-muted")[i].innerText = d.toDateString()
}
});
var page = 2;
var window_scroll = true;
var search = "{{ search }}";
window.addEventListener('scroll', function(e) {
// scroll check
console.log("scroll check...")
if(window_scroll){
if((window.innerHeight + window.scrollY) >= (document.body.scrollHeight-200)){
window_scroll = false;
document.getElementById("loading").style.display = "block";
$.ajax({
url: '/next?page=' + page + '&search=' + search,
dataType: 'json',
success: function (data) {
if (data["success"]) {
articles = data["data"]
articles_html = ''
for (i = 0; i < articles.length; i++) {
articles_html += ' \
<div class="card mb-3 box" style="max-width: 640px; margin:auto;">\
<div class="row">\
<div class="col-md-8">\
<div class="card-body">\
<h5 class="card-title"><a href="'+ articles[i]["url"] +'" target="_blanck">'+ articles[i]["title"] +'</a></h5>\
<p class="card-text">'+ articles[i]["description"] +'</p>\
<p class="card-text"><small class="text-muted">'+ articles[i]["publishedat"] +'</small></p>\
</div>\
</div>\
\
<div class="col-md-4 img-box">\
<img src="'+ articles[i]["image"] +'" class="card-img" alt="..." height="100%">\
</div>\
</div>\
</div>\
'
}
$("#articles-container").append(articles_html);
page += 1
window_scroll = true;
document.getElementById("loading").style.display = "none";
}
else {
console.log("Failed")
window_scroll = true;
document.getElementById("loading").style.display = "none";
}
}
});
}
}
})
</script>
</html>
<a href="{% url 'Home' %}?search=Business">Business</a>
<style>
.sidebar{
position: fixed;
width: 200px;
height: 100%;
top: 0px;
left: 0px;
}
.sidebar a{
width: 250px;
display: block;
margin: 24px 0px;
padding: 10px 5px;
font-weight: bolder;
font-size: large;
text-decoration: none;
background-color: #d9e4ffc7;
border-top-right-radius: 30px;
border-bottom-right-radius: 30px;
box-shadow: 0px 0.5px 1px grey;
text-align: center;
}
</style>
<div class="sidebar">
<a href="{% url 'Home' %}">Home</a>
<a href="{% url 'Home' %}?search=top">Top News</a>
<a href="{% url 'Home' %}?search=Business">Business</a>
<a href="{% url 'Home' %}?search=Technology">Technology</a>
<a href="{% url 'Home' %}?search=Entertainment">Entertainment</a>
<a href="{% url 'Home' %}?search=Sports">Sports</a>
<a href="{% url 'Home' %}?search=Science">Science</a>
<a href="{% url 'Home' %}?search=Health">Health</a>
</div>
def loadcontent(request):
try:
page = request.GET.get('page', 1)
search = request.GET.get('search', None)
# url = "https://newsapi.org/v2/everything?q={}&sortBy={}&page={}&apiKey={}".format(
# "Technology","popularity",page,settings.APIKEY
# )
if search is None or search=="top":
url = "https://newsapi.org/v2/top-headlines?country={}&page={}&apiKey={}".format(
"us",page,settings.APIKEY
)
else:
url = "https://newsapi.org/v2/everything?q={}&sortBy={}&page={}&apiKey={}".format(
search,"popularity",page,settings.APIKEY
)
print("url:",url)
r = requests.get(url=url)
data = r.json()
if data["status"] != "ok":
return JsonResponse({"success":False})
data = data["articles"]
context = {
"success": True,
"data": [],
"search": search
}
for i in data:
context["data"].append({
"title": i["title"],
"description": "" if i["description"] is None else i["description"],
"url": i["url"],
"image": temp_img if i["urlToImage"] is None else i["urlToImage"],
"publishedat": i["publishedAt"]
})
return JsonResponse(context)
except Exception as e:
return JsonResponse({"success":False})
from django.urls import path
from reader import views
urlpatterns = [
path('', views.home, name="Home"),
path('next', views.loadcontent, name="Loadcontent"),
]
path('next', views.loadcontent, name="Loadcontent"),
Reference
이 문제에 관하여(django를 사용하여 뉴스 앱 빌드), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/magesh236/news-app-in-django-2dcd텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)