如何让用户下载Django详细页面上下文对象的json

时间:2019-07-03 10:27:23

标签: django

我使用来自模型实例和Elasticsearch查询的数据为DetailView构建了精致的上下文。它可以很好地渲染模板,并遍历context ['payload']和context ['traces']列表中的数据。如果显示{{有效负载}}和{{跟踪}},我可以将所有数据视为原始JSON。

我想在页面上提供一个按钮,以将JSON下载为文件。

这是工作中的DetailView代码“ PlacePortalView()”,然后是我尝试将其修改为函数“ placeFull()”,然后是我得到的错误的堆栈跟踪。

PlacePortalView()-很好地呈现到模板

class PlacePortalView(DetailView):
  template_name = 'places/place_portal.html'

  def get_object(self):
    id_ = self.kwargs.get("id")
    es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
    q = {"query":{"bool": {"must": [{"match":{"_id": id_}}]}}}
    pid=es.search(index='whg', doc_type='place', body=q)['hits']['hits'][0]['_source']['place_id']
    self.kwargs['pid'] = pid
    return get_object_or_404(Place, id=pid)

  def get_success_url(self):
    id_ = self.kwargs.get("id")
    return '/places/'+str(id_)+'/detail'

  def minmax(timespans):
    starts = sorted([t['start']['in'] for t in timespans])
    ends = sorted([t['end']['in'] for t in timespans])
    minmax = [min(starts), max(ends)]

  def get_context_data(self, *args, **kwargs):
    context = super(PlacePortalView, self).get_context_data(*args, **kwargs)
    es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
    id_ = self.kwargs.get("id")
    pid = self.kwargs.get("pid")
    place = get_object_or_404(Place, id=pid)
    context['whg_id'] = id_
    context['payload'] = [] # parent and children if any
    context['traces'] = [] # 

    ids = [pid]
    # get child record ids from index
    q = {"query": {"parent_id": {"type": "child","id":id_}}}
    children = es.search(index='whg', doc_type='place', body=q)['hits']
    for hit in children['hits']:
      ids.append(int(hit['_id']))

    # database records for parent + children into 'payload'
    qs=Place.objects.filter(id__in=ids).order_by('-whens__minmax')

    for place in qs:
      ds = get_object_or_404(Dataset,id=place.dataset.id)
      record = {
        "whg_id":id_,
        "dataset":{"id":ds.id,"label":ds.label},
        "place_id":place.id,
        "src_id":place.src_id, 
        "purl":ds.uri_base+str(place.id) if 'whgaz' in ds.uri_base else ds.uri_base+place.src_id,
        "title":place.title,
        "ccodes":place.ccodes, 
        "names":[name.jsonb for name in place.names.all()], 
        "types":[t.jsonb for t in place.types.all()], 
        "links":[link.jsonb for link in place.links.all()], 
        "geoms":[geom.jsonb for geom in place.geoms.all()],
        "whens":[when.jsonb for when in place.whens.all()], 
        "related":[rel.jsonb for rel in place.related.all()], 
        "descriptions":[descr.jsonb for descr in place.descriptions.all()], 
        "depictions":[depict.jsonb for depict in place.depictions.all()]
      }
      context['payload'].append(record)

    # get traces
    qt = {"query": {"bool": {"must": [{"match":{"body.whg_id": id_ }}]}}}
    trace_hits = es.search(index='traces', doc_type='trace', body=qt)['hits']['hits']

    for h in trace_hits:
      context['traces'].append({
        'trace_id':h['_id'],
        'target':h['_source']['target'],
        'body':next((x for x in h['_source']['body'] if x['whg_id'] == id_), None),
        'bodycount':len(h['_source']['body'])
      })

    return context

placeFull(),尝试获取下载的JSON文件

呼叫

path('<int:id>/full', views.placeFull, name='place-full')

def placeFull(request,id):
  response = HttpResponse(content_type='text/json')
  response['Content-Disposition'] = 'attachment;filename="place-full.json"'

  #template_name = 'places/place_portal.html'

  def get_object(self):
    id_ = self.kwargs.get("id")
    print('args',self.args,'kwargs:',self.kwargs)
    es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
    q = {"query":{"bool": {"must": [{"match":{"_id": id_}}]}}}
    pid=es.search(index='whg', doc_type='place', body=q)['hits']['hits'][0]['_source']['place_id']
    self.kwargs['pid'] = pid
    return get_object_or_404(Place, id=pid)

  #def get_success_url(self):
    #id_ = self.kwargs.get("id")
    #return '/places/'+str(id_)+'/detail'

  def minmax(timespans):
    starts = sorted([t['start']['in'] for t in timespans])
    ends = sorted([t['end']['in'] for t in timespans])
    #minmax = {'start':min(starts), 'end':max(ends)}    
    minmax = [min(starts), max(ends)]

  def get_context_data(self, *args, **kwargs):
    context = super(placeFull, self).get_context_data(*args, **kwargs)
    es = Elasticsearch([{'host': 'localhost', 'port': 9200}])
    id_ = self.kwargs.get("id")
    pid = self.kwargs.get("pid")
    place = get_object_or_404(Place, id=pid)
    context['whg_id'] = id_
    context['payload'] = [] # parent and children if any
    context['traces'] = [] # 

    ids = [pid]
    # get child record ids from index
    q = {"query": {"parent_id": {"type": "child","id":id_}}}
    children = es.search(index='whg', doc_type='place', body=q)['hits']
    for hit in children['hits']:
      ids.append(int(hit['_id']))

    # database records for parent + children into 'payload'
    qs=Place.objects.filter(id__in=ids).order_by('-whens__minmax')
    for place in qs:
      ds = get_object_or_404(Dataset,id=place.dataset.id)
      record = {
        "whg_id":id_,
        "dataset":{"id":ds.id,"label":ds.label},
        "place_id":place.id,
        "src_id":place.src_id, 
        "purl":ds.uri_base+str(place.id) if 'whgaz' in ds.uri_base else ds.uri_base+place.src_id,
        "title":place.title
      }
      context['payload'].append(record)

    # get traces
    qt = {"query": {"bool": {"must": [{"match":{"body.whg_id": id_ }}]}}}
    trace_hits = es.search(index='traces', doc_type='trace', body=qt)['hits']['hits']

    for h in trace_hits:
      context['traces'].append({
        'trace_id':h['_id'],
        'target':h['_source']['target'],
        'body':next((x for x in h['_source']['body'] if x['whg_id'] == id_), None),
        'bodycount':len(h['_source']['body'])
      })

    response.write(context['payload'])
    response.write(context['traces'])
    return response

堆栈跟踪

Environment:

Request Method: GET
Request URL: http://localhost:8000/places/12392121/full

Django Version: 2.1.7
Python Version: 3.6.3
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.gis',
 'bootstrap_modal_forms',
 'django_celery_beat',
 'django_celery_results',
 'django_extensions',
 'djgeojson',
 'fontawesome',
 'leaflet',
 'mathfilters',
 'rest_framework',
 'rest_framework_datatables',
 'accounts.apps.AccountsConfig',
 'areas.apps.AreasConfig',
 'datasets.apps.DatasetsConfig',
 'main.apps.MainConfig',
 'maps.apps.MapsConfig',
 'places.apps.PlacesConfig',
 'search.apps.SearchConfig',
 'traces.apps.TracesConfig']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']



Traceback:

File "/Users/karlg/envs/whg/lib/python3.6/site-packages/django/core/handlers/exception.py" in inner
  34.             response = get_response(request)

File "/Users/karlg/envs/whg/lib/python3.6/site-packages/django/core/handlers/base.py" in _get_response
  137.                 "returned None instead." % (callback.__module__, view_name)

Exception Type: ValueError at /places/12392121/full
Exception Value: The view places.views.placeFull didn't return an HttpResponse object. It returned None instead.

1 个答案:

答案 0 :(得分:0)

如果您只想返回JSON表示形式,则可以使用从PlaceDetailView继承但覆盖render_to_response的类,以从上下文返回JSON响应,而不是渲染模板。

>
class PlaceFullView(PlaceDetailView):
    def render_to_response(self, context, **response_kwargs):
        return JsonResponse(context, **response_kwargs)