Friday, July 28, 2017

Django form needs pagination and saved data - how????

I use the latest versions of Django, python, bootstrap3, and crispy forms for this project.

I am trying to present a list of flashcards to a user, sorted by category (e.g., Math, Vocabulary, etc.). Then, I want the user to check either the full category or individual flashcards to be added to their practice account. 

To maintain user inputted checkboxes on multiple pages, I must use POST. But, pagination only uses GET. So, a hack on pagination is to wrap the Next/Previous buttons in a sub-form and POST using the buttons. This works for pagination, but then my normal "I'm done, submit this session and process the updates" button - my submit button - does nothing: no GET, no POST, nothing. 

How can I enable pagination, multiple screen data accumulation across pages, and final submission of the session when complete? 

Just FYI - for me, session data and hidden forms haven't worked because the data doesn't come back to the Django server. So, request.POST.get('CAT') returns NULL even though the web page has a value in the tag 'CAT'. Session data doesn't work because I can't get the data to the server.

Here are sub-sections of my code. The "hidden" fields (cat and crd) are visible during my testing. They are filled with the IDs of any/all selected categories (cat) or flashcards (crd) - comma separated.

Views.py:
class CardsCreate(TemplateView):
    template_name = 'sel_cards_add.html'
    model = FlashCard

    def dispatch(self, request, *args, **kwargs):
        print('DISPATCH:')
        student_id = kwargs.get('student_id')

        try:
            flashcards = FlashCard.objects.all().order_by('category', 'front')
        except FlashCard.DoesNotExist:
            flashcards = None
        except Exception as e:
            print('type=%s args=%s (%s)' % (type(e), e.args, e))
            raise Http404

        flashcard_paginator = paginator.Paginator(flashcards, 2)
        try:
            page = int(request.GET.get('page', '1'))
        except ValueError:
            page = 1
        try:
            flashcards = flashcard_paginator.page(page)
        except (paginator.EmptyPage, paginator.InvalidPage):
            flashcards = flashcard_paginator.page(flashcard_paginator.num_pages)

        context = {'flashcards': flashcards, 'id': student_id, 'title': 'Available Flashcards By Category'}
        print('End of DISPATCH:')
        return render(request, self.template_name, context)

Template (sel_cards_add.html):
{% extends 'base.html' %}
{% load crispy_forms_tags %}

<form id="myForm" action="{% url 'add_cards' id %}" method="POST">
    {% block content %}
    {% csrf_token %}
        
    <div class = "row">
      <div class="col-sm-8 col-sm-offset-1">


        <h1>{{ title }}</h1>
        {% for flashcard in flashcards %}
            {% ifchanged flashcard.category %}
                </table>
                <h3><input type="checkbox" onchange="chkcat(this)" name="chkcat{{ flashcard.category_id }}" /> &nbsp;&nbsp;Category:  {{ flashcard.category }}</h3>
        <table>
            <tr>
              <th>Select?</th>
              <th>Flashcard</th>
              <th>Answer</th>
              <th>Easy Factor</th>
            </tr>
            {% endifchanged %}
            <tr>
                <td><input type="checkbox" onchange="chkid(this)" name="chkid{{ flashcard.id }}" /></td>
                <td>{{ flashcard.front }}</td>
                <td>{{ flashcard.answer }}</td>
                <td>{{ flashcard.easy_factor }}</td>
            </tr>
        {% empty %}
            <tr><td align="center" colspan="4">No flashcards to select yet.</td></tr>
        {% endfor %}
        </table>
        <br>
        <input type="text" id="cat" name="CATS" value="{{ CATS }}" />
        <input type="text" id="crd" name="CRDS" value="{{ CRDS }}" />
      <br>
        <div class="pagination">
            <span class="step-links">
                <table class="pagination" style="border: none;"><tr style="border: none;"><td style="border: none;">
                {% if flashcards.has_previous %}
                <span>
                    <form action="?page={{ flashcards.previous_page_number }}" method="POST">
                     {% csrf_token %}
                        <button type="submit">Previous</button>
                    </form></span>
                {% endif %}
            </td><td style="border: none;">
                    <span>Page {{ flashcards.number }} of {{ flashcards.paginator.num_pages }}</span>
            </td><td style="border: none;">
                {% if flashcards.has_next %}
                <span>
                    <form action="?page={{ flashcards.next_page_number }}" method="POST">
                     {% csrf_token %}
                        <button type="submit">Next</button>
                    </form></span>
                {% endif %}
            </td></tr></table>
            </span>
        </div>
        <br>
        <button type="submit" class="btn btn-default">Add Selections to User</button>
        &nbsp;&nbsp;
        <a href="{% url 'home' %}" class="btn btn-primary" role="button" padding="15px">Cancel</a>
      </div>
      </div>


<script type="text/javascript">
  function chkcat(element) {
      var x = $(element).attr('name');
      var num = x.substring(6,12);
      var categorys = document.getElementById("cat").value;
      var array = strToArray(categorys);
      var checked = document.getElementsByName(x)[0].checked;
      if (checked) {
          if ((array.indexOf(num)) == -1) {
              array.push(num.concat(","));
          }
      }
      else {
          array = valueRemove(num,array);
      }
      document.getElementById("cat").value = array;
  }

  function chkid(element) {
      var x = $(element).attr('name');
      var num = x.substring(5,11);
      var cards = document.getElementById("crd").value;
      var array = strToArray(cards);
      var checked = document.getElementsByName(x)[0].checked;
      if (checked) {
          if ((array.indexOf(num)) == -1) {
              array.push(num.concat(","));
          }
      }
      else {
          array = valueRemove(num,array);
      }
      document.getElementById("crd").value = array;
  }
  
function valueRemove(obj, array) {
    var hold = [];
    var objLoc = array.indexOf(obj);
    if (objLoc == -1) {
    return array;
}
    else {
      for (var i=(array.length-1); i >= 0; i--) {
        if (i == a) {
            array.pop();
            }
            else {
            hold.push(array.pop());
            }
        }
        return hold;
    }
}

function strToArray(txt) {
var array = [];
var i = 0;
var j = 0;
var len = txt.length;
for (i=0; i < len; i++) {
if (txt[i] == ",") {
array.push(txt.substring(j, i));
j = i+1;
}
}
    return array;
}
</script>

{% endblock content %}

</form>

Thanks for any help with this issue. Is there a much better approach using Django?

Jim Illback

No comments:

Post a Comment