"Business is not iterable"错误返回与表单相同的 HTML 页面上的数据



我可以将数据从表单获取到数据库中,并将其传递给它查询Yelp并将其放入JSON文件的视图,然后将JSON文件中的特定字段保存到数据库中。但是我无法显示数据库数据。

当我应该将数据返回到页面时,我收到搜索成功消息。我发现我的字典只是一条数据,而不是该行的所有字段,我不确定为什么:

{% for key, values in yelp_data.items %}
<tr>
<td>{{key}}</td>
{% for v in values %}
<td>{{v}}</td>
{% endfor %}
</tr>
{% endfor %}

我收到"业务不可迭代"错误。

索引.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! &raquo;</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')

大喊大叫.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 %}

应用/网址.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'),
]

顶点/网址.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'
...

蟒蛇.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

问题

我认为底线是你的第一直觉,即页面yelp.html被覆盖是正确的。 您的yelping返回render(request, 'app/yelp.html'),其中没有数据,因为没有为其提供上下文。 现在这个视图函数首先调用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,然后只在最后发送字典:

# views.py
from django.http import HttpResponse
@csrf_exempt
def yelping(request):
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 redirect('app:yelping')
#return render(request, 'app/yelp.html', {'form' : form})

messages.error(request, "Unsuccessful Search. Invalid information.")

assert isinstance(request, HttpRequest)
# NOTE: I removed the .first() from the following line
yelp_data = Business.objects.filter(business_id=business_id).order_by('-id')
dic = {
'yelp_data': yelp_data,
}
print(dic)

return render(request, 'app/yelp.html', dic)

# yelp.py
from django.http import HttpResponse
@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 HttpResponse("OK")
#return render(request, 'app/yelp.html')

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)

return HttpResponse("OK")
#return render(request, 'app/yelp.html', dic)

编辑

为什么字典只打印一条数据?
我可能误解了你所说的一条数据的意思.
Business.objects.filter(business_id=business_id).order_by('-id').first()将返回业务对象,其中包括该类的所有字段,但如果你print它只会显示business_name为什么? 因为这是你在定义时要求 Django 打印的内容

def __str__(self):
return self.business_name

如果,正如我认为你想打印出所有的行,那么删除.first()因为这将返回一个业务对象,这显然不是你可以迭代的东西,给你"业务不是可迭代的"。 然后在您的 HTML 中,您应该能够执行以下操作:

{% for y in yelp_data %}
<td>{{ y.business_name }}</td>
<td>{{ y.phone }}</td>
<td>{{ y.city }}</td>
...
{% endfor %}

最新更新