我可以从表单获取数据到数据库,并将其传递给视图,在那里它查询Yelp并将其放入JSON文件中,然后将JSON文件中的特定字段保存到数据库中。但我无法显示数据库数据。
当我应该将数据返回到页面时,我收到了搜索成功消息。我发现我的字典只是一条数据,而不是一行的所有字段,我不确定为什么:
{% for key, values in yelp_data.items %}
<tr>
<td>{{key}}</td>
{% for v in values %}
<td>{{v}}</td>
{% endfor %}
</tr>
{% endfor %}
我得到“业务是不可迭代的”错误。
Index.html
...
<div class="row">
<div class="col-md-4">
<h2>Getting started</h2>
<p>
Click here to begin with Yelp!
</p>
<p><a class="btn btn-default" href="yelping">Yelp! »</a></p>
</div>
...
Views.py
...
@csrf_exempt
def yelping(request):
if request.method == "POST":
form = YelpForm(request.POST or None)
if form.is_valid():
form.save(commit=False)
term = request.POST['term']
location = request.POST['location']
form.save()
print("yelping", term, location)
yelp_main(request)
messages.success(request, "Search successful." )
return render(request, 'app/yelp.html', {'form' : form})
else:
form = YelpForm()
messages.error(request, "Unsuccessful Search. Invalid information.")
form = YelpForm()
assert isinstance(request, HttpRequest)
return render(request, 'app/yelp.html')
...
Yelp.py
# -*- coding: utf-8 -*-
from __future__ import print_function
import json
import requests
import sys
import sqlite3
from urllib.parse import quote
from django.views.decorators.csrf import csrf_exempt
from django.shortcuts import render, redirect
from app.models import Business
from django.shortcuts import get_object_or_404
API_KEY = '*****************************************************************************'
# API constants, you shouldn't have to change these.
API_HOST = 'https://api.yelp.com'
SEARCH_PATH = '/v3/businesses/search'
BUSINESS_PATH = '/v3/businesses/' # Business ID will come after slash.
# Defaults
DEFAULT_TERM = 'dinner'
DEFAULT_LOCATION = 'Glassboro, NJ'
SEARCH_LIMIT = 3
OFFSET = 0
def request(host, path, api_key, url_params=None):
url_params = url_params or {}
url = '{0}{1}'.format(host, quote(path.encode('utf8')))
headers = {
'Authorization': 'Bearer %s' % api_key,
}
print(u'Querying {0} ...'.format(url))
response = requests.request('GET', url, headers=headers, params=url_params)
return response.json()
def search(api_key, term, location):
url_params = {
'term': term.replace(' ', '+'),
'location': location.replace(' ', '+'),
'limit': SEARCH_LIMIT,
'offset': OFFSET
}
return request(API_HOST, SEARCH_PATH, api_key, url_params=url_params)
def get_business(api_key, business_id):
business_path = BUSINESS_PATH + business_id
return request(API_HOST, business_path, api_key)
def query_api(request, term, location):
print("query_api", term, location)
response = search(API_KEY, term, location)
businesses = response.get('businesses')
if not businesses:
print(u'No businesses for {0} in {1} found.'.format(term, location))
return
business_id = businesses[0]['id']
response = get_business(API_KEY, business_id)
write_to_file = json.dumps([response], indent=4)
with open('app/API/YelpAPI/yelp.json', 'w') as f:
f.write(write_to_file)
yelp_data = Business.objects.filter(business_id=business_id).order_by('-id').first()
dic = {
'yelp_data': yelp_data,
}
print(dic)
return render(request, 'app/yelp.html', dic)
def db():
with open('app/API/YelpAPI/yelp.json', 'r') as f:
data = json.load(f)
conn = sqlite3.connect('capstone/db.sqlite3')
cur = conn.cursor()
# Create the table if it doesn't exist.
cur.execute(
"""CREATE TABLE IF NOT EXISTS Business(
id INTEGER PRIMARY KEY,
business_id varchar(100),
business_name varchar(100),
yelp_business_id varchar(254),
phone varchar(15),
city varchar(100),
state varchar(20),
address varchar(100),
postal_code varchar(15),
latitude float(100),
longitude float(100),
business_stars float(10),
business_review_count integer(10),
is_open integer(1)
);"""
)
business_id = data[0]['id']
business_name = data[0]['name']
yelp_business_id = data[0]['alias']
phone = data[0]['phone']
city = data[0]['location']['city']
state = data[0]['location']['state']
address = data[0]['location']['address1']
postal_code = data[0]['location']['zip_code']
latitude = data[0]['coordinates']['latitude']
longitude = data[0]['coordinates']['longitude']
business_stars = data[0]['rating']
business_review_count = data[0]['review_count']
is_open = data[0]['hours'][0]['is_open_now']
# Execute the command and replace '?' with the each value
# in 'values'. DO NOT build a string and replace manually.
# the sqlite3 library will handle non safe strings by doing this.
sql = '''INSERT INTO Business (business_id, business_name, yelp_business_id, phone, city, state, address, postal_code, latitude, longitude, business_stars, business_review_count, is_open) VALUES(
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?,
?
);'''
cur.execute(sql, (business_id, business_name, yelp_business_id, phone, city, state, address, postal_code, latitude, longitude, business_stars, business_review_count, is_open, ))
conn.commit()
conn.close()
@csrf_exempt
def yelp_main(request):
#request.session._get_or_create_session_key()
term = request.POST.get('term')
location = request.POST.get('location')
db()
print("yelp_api", term, location)
query_api(request, term, location)
return render(request, 'app/yelp.html')
Yelp.html
{% extends "app/layout.html" %}
{% block content %}
<h2>{{ title }}</h2>
<form name='YelpForm' action="" class="post-form" method="post">
{% csrf_token %}
<label for="term">Term: </label>
<input id="term" type="text" name="term" placeholder="Type..." value="{{ YelpForm.term }}">
<label for="location">Location: </label>
<input id="location" type="text" name="location" placeholder="Where..." value="{{ YelpForm.location }}">
<input type="submit" value="OK">
</form>
<h1>{{ yelp_data.business_name }}</h1>
{% endblock %}
App/urls.py
from django.urls import re_path, path
from app import views
from .API.YelpAPI.yelp import yelp_main, query_api
# SET THE NAMESPACE!
app_name = 'app'
# Be careful setting the name to just /login use userlogin instead!
urlpatterns=[
path('yelp_main/', yelp_main, name='yelp_main' ),
path('query_api/', query_api, name='query_api'),
path('registration/', views.register_request, name='registration'),
re_path(r'^user_login/$', views.user_login,name='user_login'),
]
Capstone/urls.py
from datetime import datetime
from django.urls import re_path, path, include
from django.contrib import admin
from django.contrib.auth.views import LoginView, LogoutView
from app import forms, views
urlpatterns = [
path('home/', views.home, name='home'),
path('contact/', views.contact, name='contact'),
path('about/', views.about, name='about'),
path('admin/', admin.site.urls),
re_path(r'^$',views.index,name='index'),
re_path(r'^special/',views.special,name='special'),
re_path('', include('app.urls', namespace='app')),
re_path(r'^logout/$', views.user_logout, name='logout'),
path('foodie/', views.foodie, name='foodie'),
path('yelping/', views.yelping, name='yelping'),
]
Models.py
...
class Business(models.Model):
business_id = models.CharField(max_length=100)
business_name = models.CharField(max_length=100)
yelp_business_id = models.CharField(max_length=45, blank=True, null=True)
phone = models.CharField(max_length=100)
city = models.CharField(max_length=100)
state = models.CharField(max_length=100)
address = models.CharField(max_length=100, blank=True, null=True)
postal_code = models.CharField(max_length=15, blank=True, null=True)
latitude = models.DecimalField(max_digits=100, decimal_places=2, blank=True, null=True)
longitude = models.DecimalField(max_digits=100, decimal_places=2, blank=True, null=True)
business_stars = models.DecimalField(max_digits=10, decimal_places=2, blank=True, null=False)
business_review_count = models.IntegerField(blank=True, null=True)
is_open = models.IntegerField(blank=True, null=True)
class Meta:
managed = True
db_table = 'business'
ordering = ['business_name', 'business_stars', 'is_open']
verbose_name = 'Business Information'
verbose_name_plural = "Business's Information"
def __str__(self):
return self.business_name
...
class YelpInputModel(models.Model):
term = models.CharField(blank=True, null=False, max_length=100)
location = models.CharField(blank=True, null=False, max_length=100)
class Meta:
managed = True
db_table = 'yelpinputmodel'
...
Python.exe
Performing system checks...
System check identified no issues (0 silenced).
November 11, 2022 - 10:20:42
Django version 4.1.3, using settings 'capstone.settings.development'
Starting development server at http://127.0.0.1:61098/
Quit the server with CTRL-BREAK.
[11/Nov/2022 10:20:43] "GET / HTTP/1.1" 200 2624
[11/Nov/2022 10:20:44] "GET /static/app/content/site.css HTTP/1.1" 200 723
[11/Nov/2022 10:20:44] "GET /static/app/content/bootstrap.min.css HTTP/1.1" 200 97968
[11/Nov/2022 10:20:44] "GET /static/app/scripts/modernizr-2.6.2.js HTTP/1.1" 200 52810
[11/Nov/2022 10:20:44] "GET /favicon.ico HTTP/1.1" 404 3796
[11/Nov/2022 10:20:50] "GET /yelping HTTP/1.1" 301 0
[11/Nov/2022 10:20:50] "GET /yelping/ HTTP/1.1" 200 2035
yelping dinner 08501
yelp_api dinner 08501
query_api dinner 08501
Querying https://api.yelp.com/v3/businesses/search ...
Querying https://api.yelp.com/v3/businesses/a0FEhgrOIk_M6_o0ie-NpQ ...
{'yelp_data': <Business: The Roost Restaurant>}
[11/Nov/2022 10:20:54] "POST /yelping/ HTTP/1.1" 200 2095
1条答案
按热度按时间8ftvxx2r1#
问题
我认为底线是,您认为页面
yelp.html
被覆盖的第一直觉是正确的。您的yelping
返回render(request, 'app/yelp.html')
,其中没有数据,因为没有为它提供任何上下文。现在,该view函数首先调用yelp_main(request)
,它也返回render(request, 'app/yelp.html')
,也就是没有数据的页面。但它确实调用了def query_api(request, term, location):
。这确实返回页面数据,因为它有一个上下文,dic
,render(request, 'app/yelp.html', dic)
。但是query_api
返回到yelp_main
,它用页面的无数据版本覆盖它,然后原始调用函数用页面的另一个无数据版本替换它。解决方案
您是否可以只返回一个空的HttpResponse,然后只在最后发送字典,而不是使用Render返回页面:
和
编辑
为什么词典只打印一条数据?
我可能误解了你所说的一项数据的意思。
Business.objects.filter(business_id=business_id).order_by('-id').first()
将返回BusinessObject,其中包括该类的所有字段,但如果print
它将只显示business_name
。为什么?因为这是您在定义时要求Django打印的如果您想要打印出所有行,那么删除
.first()
,因为这将返回OneBusiness Object,这显然不是您可以遍历的东西,这会给您带来“Business is Not Iterable”。然后,在您的HTML中,您应该能够执行以下操作: