1

I´m trying to show detail information of products within a Bootstrap modal in a Django app.

I´m taking this topic as reference: Stack Overflow question .

  • The HTML is correctly calling the AJAX function
  • The AJAX function is opening the modal
  • The modal calls the URL

But I´m getting an 500 internal server error. The response is:

NoReverseMatch at /catalog/product-detail/
'system' is not a registered namespace

Any clue on what I´m doing wrong or any suggestion on how to achieve my abjective?

Thanks!

HTML - AJAX function call

<div class="row">
        {% for y in productos %}
            {% if y.categoria_producto|stringformat:"s" == objetivo %}
                    <button data-id="{{y.id}}" type="button" class="btn btn-warning margin-bottom delete-company" >delete</button>   
            {% endif %}
        {% endfor %}
        {% csrf_token %}
</div>

AJAX code

$(document).on('click','.delete-company',function(){
    var id = $(this).data('id');

    $.ajax({
        url:'/catalog/product-detail/',
        type:'POST',
        data:{
            'id':id,
            'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
        },
        success:function(data){
            $('#modalQuickView .modal-dialog').html($('#modalQuickView .modal-dialog',data));
            $('#modalQuickView').modal('show');
        },
        error:function(){
            console.log('error')
        },
    });
});

HTML Modal

<div class="modal fade" id="modalQuickView" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
    <div class="modal-content">
        <div class="modal-body">
            <div class="row">
                <div class="col-lg-5">
                    <!--Carousel Wrapper-->
                    <div id="carousel-thumb" class="carousel slide carousel-fade carousel-thumbnails" data-ride="carousel">
                        <!--Slides-->
                        <div class="carousel-inner" role="listbox">
                            <div class="carousel-item active">
                                  <img class="d-block w-100" src="{% static 'img/Cinta1.jpg' %}" alt="Kinemed - ">
                            </div>
                            <div class="carousel-item">
                                  <img class="d-block w-100" src="{% static 'img/Cinta2.jpg' %}" alt="Kinemed - ">
                            </div>
                        </div>
                        <!--/.Slides-->
                        <!--Controls-->
                        <a class="carousel-control-prev" href="#carousel-thumb" role="button" data-slide="prev">
                            <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                            <span class="sr-only">Previous</span>
                        </a>
                        <a class="carousel-control-next" href="#carousel-thumb" role="button" data-slide="next">
                            <span class="carousel-control-next-icon" aria-hidden="true"></span>
                            <span class="sr-only">Next</span>
                        </a>
                          <!--/.Controls-->
                    </div>
                    <!--/.Carousel Wrapper-->
                </div>
                <div class="col-lg-7" style="padding-left: 10px; margin-top: 1rem;">
                    {% if company %} <!-- this company instance will come from AJAX -->
                        <form method="post" action="{% url 'system:company_delete' id=company.id %}">
                        {% csrf_token %}
                            <div class="modal-content">
                                <div class="modal-body">
                                    <input type="text" name="name" maxlength="100" required="" id="id_name" value="{{ company.id }}">
                                    <input type="submit" class="btn btn-primary" value="Delete">
                                </div>
                            </div>
                        </form>
                    {% endif %}
                </div>
                <div style="padding-top: 1.5rem;">
                    <button type="button" class="btn btn-outline-info waves-effect ml-auto" data-dismiss="modal">Cerrar</button>
                </div>
            </div>
        </div>
    </div>
</div>

View

def companyListView(request):
    context = {}
    companys = ProductosBase.objects.all()
    if request.method == 'POST' and request.is_ajax():
        ID = request.POST.get('id')
        company = companys.get(id=ID) # So we send the company instance
        context['company'] = company
    context['companys'] = companys
    return render(request,'catalog/artista.html',context)

URL

url(r'^product-detail/$', views.companyListView, name="companyListView"),
Francisco Ghelfi
  • 872
  • 1
  • 11
  • 34
  • 1
    Your ajax `url:'',` is empty? perhaps you want `url:'/handle-my-ajax-url/',` Then, the view.py can handle the request? – WayBehind Nov 11 '18 at 19:52
  • Thanks @WayBehind. I updated the question information. Added an url in the AJAX code and in the urls.py. Getting a 500 now and the modal won´t open. – Francisco Ghelfi Nov 11 '18 at 20:18
  • 500 error is very likely your view error. Your console should provide more details on the error. Also, while I'm not even sure if that is correct, I usually use `if request.method == 'PUT'` and then convert JSON to Python objects by doing `data = QueryDict(request.body)`. Perhaps, Django REST my be a better option for you. More info: https://stackoverflow.com/questions/4994789/django-where-are-the-params-stored-on-a-put-delete-request – WayBehind Nov 11 '18 at 21:22
  • Thanks. I was trying not to get into Rest Framework but I guess you are right and that´s the thing. I´ll get to it. – Francisco Ghelfi Nov 11 '18 at 21:47
  • @WayBehind I´m still struggling here. I updated the info on the 500 error. The response is: NoReverseMatch at /catalog/product-detail/ 'system' is not a registered namespace – Francisco Ghelfi Nov 14 '18 at 15:43
  • I think you have incorrectly set your URLs. Please note that each Django "app" has its own url.py and you need to import those into your main URL.py file. This may help you https://stackoverflow.com/questions/41883254/django-is-not-a-registered-namespace – WayBehind Nov 14 '18 at 16:26
  • One more link here: https://stackoverflow.com/questions/48161676/django-noreversematch-at-myapp-is-not-a-registered-namespace – WayBehind Nov 14 '18 at 16:29
  • I have url('catalog/', include('catalog.urls', namespace='system')), defined in my main URL.py but when I launch the server it says: "Specifiyng a namespace in include() without providing an app_name is not supported. Set the app_name attribute in the included module, or pass a 2-tupple containing the list of patterns and app_name instead." – Francisco Ghelfi Nov 14 '18 at 16:53
  • in your main project URLs try: `url(r'^catalog/', include('catalog.urls', namespace='catalog', app_name='catalog')),`. Please also make sure that you have `__init.py__` in your project URLS folder and that you have the app listed in your settings.py under INSTALLED_APPS – WayBehind Nov 14 '18 at 18:39
  • Look up this: https://docs.djangoproject.com/en/2.1/topics/http/urls/#reversing-namespaced-urls – WayBehind Nov 14 '18 at 18:41

1 Answers1

8

I think the most important info about this problem would be in your project's urls.py file in which you included the catalog urls and used a namespace there. You gave this info in the comments. It looks like that you did not defined the app on the top of the catalog urls.py file, above the urlpatterns list and that is causing the problem. So check the following.

in catalog urls.py file:

app_name = 'system' # if your namespace is 'system.

urlpatterns = [
...]

If you give the namespace='catalog'

Then you should define that in your catalog urls.py file

app_name = 'catalog'

AN EASIER SOLUTION in this particular case:

Since this namespace does not have relevance yet in your project, then you should just delete the namespace='system' from you main urls.py file after include, so it should just look like this:

url(r'^catalog/', include('catalog.urls')),

(notice: it is better to use path() since url() will be deprecated most probably) so:

from django.urls import path

path('/catalog/', include('catalog.urls')),

And that way you can ignore my suggestion above (so you do not have to define any app anywhere) and your problem also should be solved.

Then a bit later as you proceed with your project you should study a bit more how and when to use namespaces for urls, since it's many times redundant.

And if still have problems with urls:

You can just define the url of the view in your main project urls.py file, just to see if the ajax call is received, so:

url(r'^catalog/product-detail/', views.companyListView, name='companylist'),

In this last case, do not forget to import the views in your main urls.py file too, otherwise it's also not working, so:

from catalog import views # in main urls.py file, if catalog is your app name

And finally, the main problem was an opening backslash /... in the AJAX call url (it caused a no Reverse Match error). So, the simple conclusion: if someone define an url in urlpatterns with opening backslash then in the ajax call it should be the same way, otherwise without opening backslash/. Well, yeah... to be continued...

UPDATE - SOLVING THE ORIGINAL QUESTION OF HOW TO PASS DATA TO HTML MODAL USING AJAX IN DJANGO

So, let's see. A lot of things were basically misunderstood here, I tried to clear that with a working approach. With using AJAx/jQuery/javascript, you actually bypass a big part of use of Django template tags/variables. That is the whole point of using jQuery/javascript.

First, I still suggest you to use path() and re-path() and not url() when you are defining urlpatterns in Django. url() will be deprecated as I mentioned above. And there are other important reasons to use path().

So your main urls.py should look something this:

# main project urls.py
from django.contrib import admin
from django.urls import include, path
from django.conf.urls import url

urlpatterns = [
    path('catalog/', include('catalog.urls')),
    path('admin/', admin.site.urls),
]

Your catalog urls.py should be like this:

# catalog urls.py
from django.conf.urls import url
from django.urls import include, path
from . import views

urlpatterns = [
    url(r'^$', views.index, name='index'),
]

urlpatterns += [
    url(r'^marcas/(?P<person_id>[\d\D]+)/$', views.MarcasView, name="marcas"),
    url(r'^categorias_productos/(?P<person_id>[\d\D]+)/$', views.CategoriasView, name="categoria"),
    url(r'^your-name/$', views.create_user, name="create_user"),
    path('product-detail/', views.companyListView, name="companylist"),
]

The javascript/ajax call and the response handling had to be structured again, and changed here and there. But again, the correct urls.py is also very important for the ajax call to work. And the view function too (I'll place it after the template).

This is at the bottom of base_generic.html template

{% block scripts %}

    <script>

        $(function(){
            $('.show_product').on('click', function (e) {
                e.preventDefault();
                let product_id = $(this).attr('id');

                $.ajax({
                    url:'/catalog/product-detail/',
                    type:'POST',
                    data: $('#form_have_product_'+product_id).serialize(),
                    success:function(response){
                        console.log(response);
                        $('.show_product').trigger("reset");
                        openModal(response);
                    },
                    error:function(){
                        console.log('something went wrong here');
                    },
                });
            });
        });

        function openModal(product_data){
          $('#product_name').text(product_data.company.producto);
          $('#marcas_name').text(product_data.marca);
          $('#category_name').text(product_data.categoria_producto_id);
          $('#sizes').text(product_data.company.largo);
          $('#color_name').text(product_data.company.color);
          $('#packaging').text(product_data.company.packaging);
          $('.description1 > p:eq(0)').html(product_data.company.descripcion);
          $('#product_target').text(product_data.usos);
          $('#modal_img_1').attr('src', '/static/img/'+product_data.company.foto_1 );
          $('#modal_img_2').attr('src', '/static/img/'+product_data.company.foto_2 );
          $('#modalQuickView').modal('show');
        };

    </script>

{% endblock %}

The template called artista.html had to be a bit reformulated.

{% extends "base_generic.html" %}

{% load static %}

{% block content %}

<!-- Productos por categoría -->

<!-- Modal: modalQuickView -->

<div class="modal fade" id="modalQuickView" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel"
  aria-hidden="true">
  <div class="modal-dialog modal-lg" role="document">
    <div class="modal-content">
      <div class="modal-body">
        <div class="row">
          <div class="col-lg-5">
            <!--Carousel Wrapper-->
            <div id="carousel-thumb" class="carousel slide carousel-fade carousel-thumbnails" data-ride="carousel">
              <!--Slides-->

                      <div class="carousel-inner" role="listbox">
                        <div class="carousel-item active">
                          <img id="modal_img_1" class="d-block w-100" src="{% static 'img/Cinta1.jpg' %}" alt="Kinemed - ">
                        </div>
                        <div class="carousel-item">
                          <img id="modal_img_2" class="d-block w-100" src="{% static 'img/Cinta2.jpg' %}" alt="Kinemed - ">
                        </div>

              </div>
              <!--/.Slides-->
              <!--Controls-->
              <a class="carousel-control-prev" href="#carousel-thumb" role="button" data-slide="prev">
                <span class="carousel-control-prev-icon" aria-hidden="true"></span>
                <span class="sr-only">Previous</span>
              </a>
              <a class="carousel-control-next" href="#carousel-thumb" role="button" data-slide="next">
                <span class="carousel-control-next-icon" aria-hidden="true"></span>
                <span class="sr-only">Next</span>
              </a>
              <!--/.Controls-->

            </div>
            <!--/.Carousel Wrapper-->

          </div>

          <!--This popup modal will be opened by the ajax call - Important-->

          <div class="col-lg-7" style="padding-left: 10px; margin-top: 1rem;">

              <h1 id="product_name">Product name</h1>
              <h3 id="marcas_name"><a href="" class="artist-style" style="color: #21518A; font-size: 1rem; margin-top: 1rem; padding-left: 0px;">SpiderTech</a></h3>
              <h4 id="category_name"><p class="artist-info" style="font-size: 1rem; color: black; padding-left: 0; margin-top: 0.5rem; margin-bottom: 5px;">Cintas kinesiológicas</p></h4>
              <h4 id="sizes"><p class="artist-info" style="font-size: 1rem; color: black; padding-left: 0; margin-top: 1rem; margin-bottom: 5px;">3,8 cms X 5,0 mts</p></h4>
              <h4 id="color_name"><p class="artist-info" style="font-size: 1rem; color: black; padding-left: 0; margin-top: 1rem; margin-bottom: 5px;">Beige</p></h4>
              <h4 id="packaging"><p class="artist-info" style="font-size: 1rem; color: black; padding-left: 0; margin-top: 1rem; margin-bottom: 5px;">Retail PET box</p></h4>
              <h4 id=""><p class="artist-info" style="font-size: 1rem; color: black; padding-left: 0; margin-top: 1rem; margin-bottom: 5px;"></p></h4>
              <div id="description1" class="description1" style="color: #21518A;">
                  <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
                      Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.</p>
                  <h6 id="product_target_label" style="color: black;">Usos: </h6>
                  <p id="product_target">Protección muscular, Recuperación</p>
              </div>

          </div>

            <div style="padding-top: 1.5rem;">
                     <button type="button" class="btn btn-outline-info waves-effect ml-auto" data-dismiss="modal">Cerrar</button>
            </div>
        </div>
      </div>
    </div>
  </div>
</div>

<!-- Fin Modal product detail -->

<!-- Productos por categoría -->

    {% for x in categorias %}

            {% if x.categoria_producto|stringformat:"s" == objetivo %}

                <div class="jumbotron" style="background-color: #1986E6">
                  <div class="container">
                    <div class="row">
                        <div class="barra" style="background-color: white;"></div>
                          <div class="col-12 text-center">
                              <h1 style="color: #FCFCFC">{{ objetivo }}</h1>
                          </div>

                            <div class="col-sm-12 col-md12 col-lg-12 col-xl-6 text-center" style="padding-top: 1rem;">
                              <h6 style="color: #FCFCFC">{{ x.descripcion_brief }}</h6>
                          </div>
                    </div>

                  <div style="padding-top: 1rem;">
                      <button type="button" class="btn btn-secondary btn-sm" data-toggle="collapse"
                               data-target="#demo"><i class="fas fa-info-circle"></i> Más información</button>
                  </div>


                  </div>

                <div class="container collapse" id="demo">
                    <div class="row" style="padding-top: 40px; padding-bottom: 20px;">
                        <div class="col-lg-6 col-lg-6-custom col-sm-12">
                                <div class="videoWrapper">
                                    <!-- Copy & Pasted from YouTube -->
                                    <iframe src="{{ x.video }}" width="640" height="360" frameborder="0" webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>
                                </div>

                            <div class="row">
                                <div class="col-lg-6 col-md6 col-sm-6 col-xl-6 text-center">
                                   <img style="width: 100%; position: relative;" border="0"alt="{{ objetivo }}" src=" {{ x.foto_1.url }} " class="esconder">
                                  </div>

                                <div class="col-lg-6 col-md63 col-sm-6 col-xl-6 text-center">
                                    <img style="width: 100%; position: relative;" border="0" alt="{{ objetivo }}" src=" {{ x.foto_2.url }} " class="esconder">
                                </div>
                            </div>

                        </div>

                        <div class="col-lg-6 col-lg-6-custom col-sm-12">
                            <div class="texto-brief">
                                <p>{{ x.descripcion_long }}  </p>
                                <h6 style="color: white;">Usos</h6></br>
                                <p>{{ x.usos }}  </p>
                            </div>
                        </div>


                    </div>
                    <div style="padding-top: 1rem;">
                      <button type="button" class="btn btn-secondary btn-sm" data-toggle="collapse"
                               data-target="#demo"><i class="fas fa-info-circle"></i> Menos información</button>
                  </div>
                 </div>
            </div>

            {% endif %}
    {% endfor %}



<div class="jumbotron" style="background-color: white;">
     <div class="container">
          <div class="row">
            {% for y in productos %}
                {% if y.categoria_producto|stringformat:"s" == objetivo %}
                    <div class="col-sm-6 col-md-4 col-lg-2 col-xl-2 text-center" style="padding-bottom: 20px;">

                        <form name="form" action="#" id="form_have_product_{{y.id}}" method="POST">
                          {% csrf_token %}
                          <input name="id" id="product_id_submit" type="text" value="{{y.id}}" hidden="true"/>
                        <button id="{{y.id}}" "type="button" class="btn btn-warning margin-bottom show_product">Product details</button>
                        </form>
                         <!--<a id="" href="" data-toggle="modal" data-target="#modalQuickView"><img border="0" alt="W3Schools" src="{{ y.foto_1.url }}" class="artist-foto"></a> we don't need this-->
                           <div>
                            <a href="" id="{{y.id}}" data-id="{{y.id}}" class="artist-title show_product" style="color: black; padding-left: 0;" data-toggle="modal" >{{ y.producto }}</a> <!--data-target="#modalQuickView"-->
                        </div>
                        <div><a href="{% url 'marcas' person_id=y.marca %}" class="artist-style" style="color: #21518A; padding-left: 0;">{{ y.marca }}</a></div>
                        <div><p class="artist-info" style="color: #21518A; padding-left: 0; margin-bottom: 5px; margin-top: 5px;">{{ y.packaging }}</p></div>
                        <div><p class="artist-info" style="color: #21518A; padding-left: 0; margin-bottom: 5px;">{{ y.color }}</p></div>
                        <div><p class="artist-info" style="color: #21518A; padding-left: 0; margin-bottom: 5px;">{{ y.ancho }} cms. X {{ y.largo }} mts.</p></div>
                     </div>
                {% endif %}
            {% endfor %}

          </div>
     </div>
</div>

<div class="jumbotron" style="background-color: lightgrey;">
     <div class="container">
                 <div class="row">
                        <div class="barra" style="background-color: #21518A;"></div>
                          <div class="col-12 text-center">
                              <h1 style="color: #21518A">Más productos</h1>
                          </div>


                </div>

                  <div class="row" style="margin-top: 1rem;">
                      <div class="col-sm-12 col-md-12 col-lg-12 col-xl-12 text-center" style="padding-bottom: 20px;">
                        {% for z in categorias %}
                                {% if z.categoria_producto|stringformat:"s" != objetivo %}

                                    <h3><a  style="color: #21518A;" href=" {% url 'categoria' person_id=z.categoria_producto %} ">  {{ z.categoria_producto }}</a></h3>

                                {% endif %}
                        {% endfor %}
                      </div>
                  </div>
     </div>
</div>

{% endblock %}

And finally, one of the most important thing, the views.py file where we have the view which is handling the ajax call and giving back all of the products data which will be filled in the pop up modal at every product, using javascript/jQuery (that I gave above).

from django.shortcuts import render
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.urls import reverse
from .models import ProductosBase, Marcas, Categorias_Producto
from .forms import FormularioContacto
from django.http import JsonResponse
import copy
import json
from django.forms.models import model_to_dict
from django.core import serializers

## other views functions are here.... ##

def companyListView(request):

    context = {}
    companys = ProductosBase.objects.values()
    context[companys] = ProductosBase.objects.all()

    if request.method == 'POST' and request.is_ajax():

        ID = request.POST.get('id')
        company = companys.get(pk=ID)  # So we send the company instance
        marca_name = ProductosBase.objects.get(pk=ID).marca # to have the related fields - marca
        marca_name = model_to_dict(marca_name) # better in dict
        marca_name = marca_name['marca'] # to define marca for the product
        usos_product = ProductosBase.objects.get(pk=ID).categoria_producto  # we need usos field from categories
        usos_product = model_to_dict(usos_product)
        usos_product = usos_product['usos']
        return JsonResponse({ 'company' : company, 'marca' : marca_name, 'usos' : usos_product })
    else:
        return render(request, 'catalog/artista.html', context)

And finally the visual which shows how the modal is working with any products providing all of the needed data to the clicked product:

So, you did a good job with your app, very nice basics and template work, but you should study more the role and power of jQuery/javascript in Django projects. They are really powerful together.

I hope that you will use and study the above codes and you can use it for your later projects too. Cheers. :)

Zollie
  • 1,171
  • 7
  • 14
  • Thanbk you so much @Zollie. The problemn I have now is that pictures won´t show. I guess it has something with the PATH / URL change. I´ll have a great look at your changes and try to fiogure it out. THANKS! – Francisco Ghelfi Nov 17 '18 at 23:42