Search code examples
jsondjangodjango-viewsadminltedjango-3.1

How to add custom view in django adminlte?


I created an environment using pycharm & installed adminlte by git clone from https://github.com/app-generator/django-dashboard-adminlte.git. And installed adminlte3 , django3.1 & all requirements. Then run python manage.py runserver and registered a new user & was able to login ,view all pages, added new link to a html page. But I am unable to add view with jsonresponse to a button click on new page, geting Error 500 - Server Error.

My new html page is

{% extends "layouts/base.html" %}
{% block title %} Layout Boxed {% endblock %} 
<!-- Element injected in the BODY element -->
{% block body_class %} sidebar-mini layout-boxed {% endblock body_class %} 
<!-- Specific Page CSS goes HERE  -->
{% block stylesheets %}
  <!-- Google Font: Source Sans Pro -->
  <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700&display=fallback">
  <!-- Font Awesome -->
  <link rel="stylesheet" href="/static/assets/plugins/fontawesome-free/css/all.min.css">
  <!-- Theme style -->
  <link rel="stylesheet" href="/static/assets/css/adminlte.min.css">
  <link rel="stylesheet" href="/static/assets/css/mapstyle.css">
  <link rel="stylesheet" href="/static/assets/js/pages/gis/dist/map.css">
<style>
   .map {
        margin: 0;
        padding: 0;
        width: 900px;
        height: 500px;
        background:white !important;
    border:1px solid #ccc;
      }
</style>
{% endblock stylesheets %}
{% block content %}
  <div class="content-wrapper">
    <div id="lyrDiv"></div>
    <div id="map" class="map"></div>
    <button id="search">Search</button>
  </div>
{% endblock content %}
<!-- Specific Page JS goes HERE  -->
{% block javascripts %}
  <!-- jQuery -->
  <script src="/static/assets/plugins/jquery/jquery.min.js"></script>
  <!-- Bootstrap 4 -->
  <script src="/static/assets/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
  <!-- AdminLTE App -->
  <script src="/static/assets/js/adminlte.min.js"></script>
  <!-- AdminLTE for demo purposes -->
  <script src="/static/assets/js/demo.js"></script>
  <script src="/static/assets/js/pages/map.js"></script>
  <script src="/static/assets/js/pages/search.js"></script>
{% endblock javascripts %}

search.js

$( "#search" ).click(function() {
    $.get('/search/',{'csrfmiddlewaretoken':csrftoken},function(data){
        alert(data); // here getting Error 500 - Server Error
    });
});

I added below line to /django-dashboard-adminlte/app/urls.py

re_path(r'^search/$', search.spatial_srch, name='search'), 

and search.py

from app.models import *
from django.views.decorators.csrf import csrf_exempt
from django.http import JsonResponse

@csrf_exempt
def spatial_srch(request):
    data= Demotable.objects.all() 
    searchArr = []
    output = {}

    for c in data:
        searchArr.append({'type': 'Feature', 'properties': {'id':c.id,'name': str(c.name)},'geometry': {'type': 'Point', 'coordinates': [c.the_geom.x, c.the_geom.y]}})
    output = {'type': 'FeatureCollection', 'features': searchArr}
    return JsonResponse(output)

When I click on the 'Serach' button the request is not going to the view search.py What is wrong in my code ? what configuration did I miss?

The post shows enter image description here

The Error 500 shows only adminlte Error page. Nothing more enter image description here


Solution

  • The problem is in the (not so nice) way they generate the error. It's anti-pattern hell there, but in short it means there's an except thrown in either:

    • finding the template
    • loading the template
    • or rendering the template

    and they catch it and don't let you see what happened. Not very nice code and you're have to modify that file to even begin debugging it:

    @login_required(login_url="/login/")
    def pages(request):
        context = {}
        # All resource paths end in .html.
        # Pick out the html file name from the url. And load that template.
        try:
            
            load_template = request.path.split('/')[-1]
            html_template = loader.get_template( load_template )
            return HttpResponse(html_template.render(context, request))
            
        except template.TemplateDoesNotExist:
    
            html_template = loader.get_template( 'page-404.html' )
            return HttpResponse(html_template.render(context, request))
    
        # Remove or comment these lines:
        #except:
        #
        #   html_template = loader.get_template( 'page-500.html' )
        #    return HttpResponse(html_template.render(context, request))
    

    Also I'm not sure this the specific spot where the error is generated, they might be doing similar things in other places.

    Edit

    This is very .... unprofessional code:

        # Matches any html file
        re_path(r'^.*\.*', views.pages, name='pages'),
    

    No, it doesn't not match any "html" file - it matches everything cause they don't get regular expressions:

    ^ - start of string
    .* - anything or nothing
    \.* - >>>zero<<< or more dots
    

    Result: \.* is ignored as it is irrelevant so it matches everything and if you placed your re_path below it, it will never be consulted, because Django uses first match wins approach.

    So your url matches theirs, which then routes it to pages view:

    load_template = request.path.split('/')[-1]
    

    Since request.path is '/search/', '/search/'.split('/')[-1] gives the empty string and that creates your problem.

    I highly suggest fixing their url path:

        # Matches any html file
        re_path(r'\.html$', views.pages, name='pages'),
    

    Or put your re_path above theirs.