Question

In my Django app, the user is presented a simple form, on validation the view searches the data (some web scraping) and returns a template in the context of which we added a list of the results, we present them to the user and he/she chooses one and (this is my problem) I want to get that choice back to another view (now we want to add the selected object to the database).

I identified my problem, but I really think I'm missing something and not using Django the right way. For now this is how I display the data and put it back in a form: (jade template. Of course I do this with many more attributes so the template is quite big and I have to add an hidden input for each value I want back)

for b in result_list
      h4
        for aut in b.authors
          div {{ aut }}   

      form(action='/add/', method='post') {% csrf_token %}
        {% csrf_token %}
        input(type='hidden', value="{{ b.authors }}", name='authors')

edit2: there is one button per book. I am just trying to return one book.

It works fine when authors has a single element, but with more than once the template doesn't return a valid json. I could give you the structure but I tend to think this is not the point.

What am I missing ? How to display search results and get the selected one to another view ?

Do I miss something about forms ? Shall I use a session variable, a context processor with middleware ? I guess the hidden input is wrong: how can I do differently ?

many thanks


edit: below I show where my problem is. However, maybe I shouldn't fix that problem but use Django the right way instead.

1- my 1st view renders a template and feeds it with the search results:

    return render(request, "search/search_result.jade", {
        "return_list": book_list,
        })

book_list is a list of dicts where authors is a list of unicode str:

retlist[0]["authors"]
>>> [u'Ayroles, Alain']

2- my template is above. It displays a form and a hidden input. The goal is to send back a book: a dictionnary with the title, the editor… and a list of authors.

3- now the users clicks "Add this book", we are in the "add" view. Let's inspect the authors:

req = request.POST.copy()
authors = req["authors"]
>>> u"[u'Ayroles']"  # note the u after the [
# this is not a valid json, I can't get a list out of it
import json
json.loads(req["authors"])
>>> *** ValueError: No JSON object could be decoded

So I passed a list from the first view to the template, I parsed it and displayed it, but the template doesn't return a valid list/json to the second view in the POST parameters and I can't extract my authors. I don't know what to think:

  • else what I want to do is fine and I just have to better handle my data structure
  • else I shouldn't be doing like that and use more of Django: use more forms ? sessions ?
Was it helpful?

Solution 2

I finally got it: we can easily share data between views using the session.

The session is activated in the default Django install. We just have to choose a session engine: in a temporary file, in memory,…

SESSION_ENGINE = 'django.contrib.sessions.backends.file'  

Now in my search/ url I can add a variable in request.session, a dictionnary-like object:

search_results = compute_and_get_data()
request = search_results()

I feed my template with the search_results list. In my template, I iterate on it and I use a single hidden input field to return the counter of the for loop.

for b in search_results
  table
    tr
      td
        h4 {{b.authors}}


  form(action='/add/', method='post') {% csrf_token %}
    {% csrf_token %}
    input(type='hidden', value="{{ forloop.counter0 }}", name='forloop_counter0')
    input.btn.btn-primary(type='submit', value='add book', title="add that book to my collection")

On submit, we enter the add/ view. Here I can get the book the user selected:

forloop_counter0 = int(request.POST["forloop_counter0"])
book = request.session["search_result"][forloop_counter0]

Now my book is a dictionnary with a lot of information. I didn't have to handle json formatting and the like.

This question helped me:

OTHER TIPS

This is how I see it. It is not really an answer, but it's already too much code to put into comments

Template:

for b in result_list
  h4
    for aut in b.authors
      div {{ aut }}   
      form(action='/add/', method='post')
          {% csrf_token %}
          input(type='hidden', value="{{ b.authors }}", name='authors')
          input(type='submit', value="Add book")

View:

if request.method == 'POST':
    authors = request.POST.get['authors']
    #do something with authors, e.g. create a JSON string:
    authors_JSON = json.dumps(authors)

Same logic, using Django forms:

View:

if request.method == 'POST':
    book = BookForm(request.POST)
    #do something with authors, e.g. create a JSON string:
    authors_JSON = json.dumps(book.authors)

Forms.py:

class ContactForm(forms.Form):
    authors = forms.CharField(max_length=100)
    #etc, possibly including custom __init__ logic

That 'u' thing, it happens because you do json.loads() on an object. If you want to serialize, it should be json.dumps(), otherwise array converted to string and then treated as JSON, that is why Python unicode mark got there (i.e. not a template bug)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top