Flask - how to keep list index after form submit? - python

I have a list of images that I want to display on a page. These image names are formatted basically YYYYMMDD_HHMMSS.jpg. I want this single page to either list all images, or only list and show those taken on a certain date (meaning a main page, not like /index to show all images, /date-specific to show some images).
So far, I have been able to show all images, and click "next"/"previous" buttons to loop through all images. I also have a table below the image, showing all the images that are in the index.
Works great - no issues.
However, I am also trying to implement a date filter, where the user can select a date from the Calendar Picker, and have the site filter out and only show photos on that day. So far, I can successfully filter one time. However, when I click "next"/"previous" buttons, or choose an image from the table, it resets back to the full list of images.
How do I keep the filtered list? I thought I could do it by keeping the date chosen in the Input field, but after using the "next"/"previous" buttons, the whole page resets and it clears that field.
I also tried including the list in the HTML portion, but it still returns all the photos. (Also makes the URL ugly, since it includes the image list for each photo listed in the table):
<td> {{ image }} </td>
Here's a .gif of the page I'm working on.. First, you'll see I can successfully click around, navigate between all photos. Then, I can successfully filter to show photos on a specific date. However, anything past that keeps sending me back to the full image list.
Anyways, without further ado, here's the codes. (Note I try to keep it minimal, so might have omitted an important piece, so please let me know if I need to post something else here):
routes.py
import os
import random
from flask import render_template, url_for, request, Blueprint, redirect # noqa
from app import app
IMAGE_FOLDER = r"C:/MyPath/Test"
FAVORITE_LIST = os.path.join(IMAGE_FOLDER, "favorites.txt")
blueprint = Blueprint('images', __name__,
static_url_path='/static/images',
static_folder=IMAGE_FOLDER)
app.register_blueprint(blueprint)
images = os.listdir(IMAGE_FOLDER)
image_urls = ["20190411_123200.jpg", ... other images in a list]
class Photo_Index():
def __init__(self, index=0):
self.index = index
def increase_number(self, num_images):
if self.index == num_images:
self.index = 0
else:
self.index = self.index + 1
return self.index
def decrease_number(self, num_images):
if self.index == 0:
self.index = num_images
else:
self.index = self.index - 1
return self.index
def random_number(self, num_images):
self.index = random.randint(0, num_images)
return self.index
def set_number(self, number):
self.index = number
return self.index
# functions to create and edit Favorites. this works so I'm excluding]
def day_month_year(filename):
"""
Takes a string `20190212` and pulls out Year, Month, Date
"""
year = filename[:4]
month = filename[4:6]
day = filename[6:8]
return str(year + "-" + month + "-" + day)
def get_files_on(specific_date):
_files = []
print("\nLooking for files on:", specific_date, "\n")
for file in image_urls:
# print(file, day_month_year(file))
if day_month_year(file) == specific_date:
_files.append(file)
return _files
photo_index_obj = Photo_Index()
fav_photo_index = Photo_Index()
def update_index(rqst, indx_obj, num_images):
print("Updating index, have", num_images, "photos")
if num_images == 1:
indx_obj.set_number(0)
elif 'prev-photo' in rqst.form:
indx_obj.decrease_number(num_images)
elif 'next-photo' in rqst.form:
indx_obj.increase_number(num_images)
elif 'random-photo' in rqst.form:
indx_obj.random_number(num_images)
return indx_obj
#app.route("/<chosen_image>", methods=["GET", "POST"])
#app.route("/", methods=["GET", "POST"])
def default_template(date=None, image_list=None, chosen_image=None):
if image_list is None:
image_list = image_urls
num_images = len(image_list) - 1
if request.method == "POST":
if 'go-to-date' in request.form:
date = request.form['go-to-date']
image_list = get_files_on(date)
num_images = len(image_list) - 1
photo_index_obj.set_number(0)
if len(image_list) == 0:
image_list = ["no_images_for_date.jpg"]
elif 'prev-next-buttons' in request.form:
print("Updating index, have", num_images, "photos")
update_index(request, photo_index_obj, num_images)
elif 'favorite-photo' in request.form:
add_to_favorites(image_list[photo_index_obj.index])
elif 'un-favorite-photo' in request.form:
remove_from_favorites(image_list[photo_index_obj.index])
if chosen_image is None:
chosen_image = image_list[photo_index_obj.index]
elif chosen_image is not None:
photo_index_obj.set_number(image_list.index(chosen_image))
favorite = is_favorite(image_list[photo_index_obj.index])
print("Images:", image_list)
return render_template('index.html',
title="Local Image Viewer",
photo_index=photo_index_obj.index,
image=chosen_image,
image_list=image_list,
favorite=favorite)
#app.route("/<chosen_image>", methods=["GET", "POST"])
def chosen_image(chosen_image):
date = request.form['go-to-date']
return default_template(date=date,
chosen_image=chosen_image)
index.html (I omitted the Select list, as that's kind of superfluous for this post)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>{{ title }}</title>
<link rel="stylesheet" type="text/css" href= "{{ url_for('static',filename='styles/index.css') }}">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
</head>
<body>
{% extends "layout.html" %}
{% block content %}
<h3>Index: {{ photo_index }}</h3>
<h3>Filename: {{ image }}</h3>
<div id="calendar-selector">
{% include "/HTML Snippets/calendar.html" %}
</div>
<div class='image-container' id='image'>
{% include "/HTML Snippets/favorite_button.html" %}
<img src="{{ url_for('images.static', filename=image) }} " id="the-photo">
</div>
<div class='button-container' id='buttons'>
<form action="" method="post">
<input type="hidden" name="prev-next-buttons">
<input type="submit" value="Prev photo" name='prev-photo'>
<input type="submit" value="Next photo" name='next-photo'>
<input type="submit" value="Random photo" name='random-photo'>
<br/>
<button type='button' id='rotate-button' onclick="rotateMeCounterClockwise('#the-photo')">Rotate Photo CounterClockwise</button>
<button type='button' id='rotate-button' onclick="rotateMeClockwise('#the-photo')">Rotate Photo Clockwise</button>
</form>
</div>
<div class='table-container'>
<table id='image-list' name='select-from-table'>
{% for image_row in image_list | batch(3) %}
<tr>
{% for image in image_row %}
<td> {{ image }} </td>
{% endfor %}
</tr>
{% endfor %}
</table>
</div>
{% endblock %}
</body>
</html>
and the calendar bit, calendar.html
{% block topscripts %}
<link rel="stylesheet" type="text/css" href= "{{ url_for('static',filename='styles/calendar.css') }}">
<script>
$(function() {
$("#datepicker").datepicker({dateFormat: 'yy-mm-dd'});
});
</script>
{% endblock %}
{% block content %}
<form method="post" action="{{ url_for('default_template') }}">
<input type="hidden" name="calendar-form">
<p>
Date: <input type="text" id="datepicker" name='go-to-date'
{% if request.form['go-to-date'] is not none %}
value="{{request.form['go-to-date']}}"
{% endif %}
></p>
<input type="submit">
</form>
{% endblock %}
{% block endscripts %}
{% endblock %}

You need to pass along enough information in your next/previous form and in the table links to re-apply the date filter. Your calendar form is separate from the next/previous navigation form, the browser won't serialise information from one when submitting the other. Clicks on <a href="..."> links will not include the date input field value either.
Note that clicks on the table links generate GET requests, so you need to look for go-to-date in the request.values mapping to accommodate both query parameters and form data.
You need to look for this parameter not only when you receive a POST request, but for all requests:
if 'go-to-date' in request.values:
date = request.values['go-to-date']
image_list = get_files_on(date)
photo_index_obj.set_number(0)
if len(image_list) == 0:
image_list = ["no_images_for_date.jpg"]
else:
image_list = image_list or image_urls
num_images = len(image_list) - 1
if request.method == 'POST':
# ...
Then generate URLs that include the parameter:
{%- set url_params = {'go-to-date': request.values['go-to-date']} if request.values['go-to-date'] else {} -%}
{% for image in image_row %}
<td> {{ image }} </td>
{% endfor %}
For the next/previous form, just add a hidden input field with the current go-to-date value:
<form action="" method="post">
<input type="hidden" name="prev-next-buttons">
{%- if request.values['go-to-date'] -%}
<input type="hidden" name="go-to-date" value="{{ request.values['go-to-date'] }}">
{%- endif -%}
<input type="submit" value="Prev photo" name='prev-photo'>
<input type="submit" value="Next photo" name='next-photo'>
<input type="submit" value="Random photo" name='random-photo'>
<br/>
<button type='button' id='rotate-button' onclick="rotateMeCounterClockwise('#the-photo')">Rotate Photo CounterClockwise</button>
<button type='button' id='rotate-button' onclick="rotateMeClockwise('#the-photo')">Rotate Photo Clockwise</button>
</form>

Related

How to sort posts by date (FLASK, PYTHON, SQLALCHEMY)

I would like to know how sort the posts displayed on the home page by data uploaded, I have dates saved to each post in the database. At the moment they are displayed in alphabetical order.
this is the route for the page I would like to display the images
HOME ROUTE:
#views.route("/")
def home():
title = Post.query.get("title")
date = Post.query.get("date")
images = os.listdir(os.path.join(staticpath, "uploads"))
return render_template('home.html', images=images, user=current_user, title=title, date=date, Post=Post, User=User)
HTML for page I want to display images by date
HTML PAGE:
{% extends "base.html" %}
{% block title %}home{% endblock %}
{% block content %}
<section class="list">
{% for image in images %}
<p> title: {{ Post.query.filter_by(name=image).first().title }}</p>
<p> date: {{ Post.query.filter_by(name=image).first().date}}</p>
<p> OP ID: {{ Post.query.filter_by(name=image).first().user_id}}
<section class="col-md-3 col-sm-6" >
<img src="{{ url_for('static', filename='uploads/' + image) }}"width = 530>
</section>
<a href="{{ url_for('static', filename='uploads/' + image) }}" style="absolute: 600;" download>{{ image }}</a>
<p class="solid" style="border-style: solid;"></p>
{% endfor %}
</section>
{% endblock %}
this is the database that posts are stored, it includes date
DATABASE MODEL:
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(100))
date = db.Column(db.DateTime(timezone=True), default = func.now())
minetype = db.Column(db.Text, nullable=False)
name = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey("user.id"))
I would change the handler and the template as per below, which will allow you to achieve:
all Posts will be loaded in one query, and immediately sorted
you will not be making DB queries within the template, making cleaner separation of concerns
def home():
title = Post.query.get("title")
date = Post.query.get("date")
# images below are list of strings
images = os.listdir(os.path.join(staticpath, "uploads"))
# images below is a collection of `Post` instances (and it is sorted)
images = Post.query.filter(Post.name.in_(images)).order_by(Post.date)
return render_template('home.html', images=images, user=current_user, title=title, date=date, Post=Post, User=User)
and your template would change as below:
{% extends "base.html" %}
{% block title %}home{% endblock %}
{% block content %}
<section class="list">
{% for image in images %}
<p> title: {{ image.title }}</p>
<p> date: {{ image.date }}</p>
<p> OP ID: {{ image.user_id }}</p>
<section class="col-md-3 col-sm-6" >
<img src="{{ url_for('static', filename='uploads/' + image.name) }}" width = 530>
</section>
<a href="{{ url_for('static', filename='uploads/' + image.name) }}" style="absolute: 600;" download>{{ image }}</a>
<p class="solid" style="border-style: solid;"></p>
{% endfor %}
</section>
{% endblock %}

How to implement a next button in flask?

I am trying to use Flask to implement a basic query over a database. Each page should show up to 8 results, and if there are more than 8, it should have a next page button. Everything is working as intended except for the next page button, but I'm not sure what I'm doing wrong.
Here is the Python code I have:
#app.route("/results", methods=["POST"])
def results(result = None):
"""
result page
:return:
"""
query_text = request.form["query"] # Get the raw user query from home page
#~results processing code removed as it's not relevant
hasnext = False
if len(r)>1:
hasnext=True
return render_template("results.html", query=query_text, hits=h , result=r[0], page=1, start = 1, hasnext = hasnext) # add variables as you wish
#app.route("/results/<int:page_id>", methods=["POST"])
def next_page(page_id):
"""
"next page" to show more results
:param page_id:
:return:
"""
s = (page_id-1)*8+1 #numbering of results
next = False
if len(r) >= page_id:
next = True
return render_template("results.html", query=query_text, hits=h, result=r[page_id-1], page=page_id, start = s, hasnext = next)
and then here are the two ways I tried to implement the HTML I have for the button that isn't working:
This one doesn't work (even if I change the variable {{page_id}} to hard code a number)
<a href="{{ url_for('next_page', page_id={{page_id}}+1)}} ">Next
<span class="a-letter-space"></span>
<span class="a-letter-space"></span>
</a>
This one shows the button, and when I tried this code, I also added more to the Python:
Button:
{% if hasnext %}
<form method ="POST" action="/">
<input type="submit" name="Next" value="Next"/>
{% endif %}
</form>
added to Python:
if request.method == 'POST':
if request.form.get('Next') == 'Next':
return render_template("results.html"...)
Any advice on how to implement the next button would be appreciated, thanks!
It's an old post but let me give it a shot. Have you tried to paginate your results? Try this in your python file.
#app.route("/results")
def results():
page = request.args.get('page', 1, type=int)
query_text = Text.query.paginate(page=page,per_page=5)
return render_template('result.html', query_text =query_text)
Then at your results.html insert this code before {% endblock content %} :
{% for page_num in query_text.iter_pages(left_edge=1, right_edge=1, left_current=1, right_current=2) %}
{% if page_num %}
{% if query_text.page == page_num %}
<a class="btn btn-info mb-4" href="{{ url_for('results', page=page_num) }}">{{ page_num }}</a>
{% else %}
<a class="btn btn-outline-info mb-4" href="{{ url_for('results', page=page_num) }}">{{ page_num }}</a>
{% endif %}
{% else %}
...
{% endif %}
{% endfor %}

How to get dynamic html table entries in a form to flask?

I am trying to create a form with an embedded table that the user can dynamically add and remove table rows while entering content into the cell inputs.
HTML
<form id="myForm" action="{{ url_for('hello_world') }}" method="POST">
<div class="form-row text-left">
<div class="col-1 text-left">
<input type="checkbox" id="skills" name="skills" value="Yes">
</div>
<div class = "col-11 text-left">
<h2>TECHNICAL SKILLS</h2>
</div>
</div><!--form-row-->
<div class="form-row">
<table id="myTable" name="skillsTable">
<tr>
<th>Category</th>
<th>Entries</th>
</tr>
</table>
</div><!--form-row-->
<br>
<button type="button" onclick="addSkill()">Add Row</button>
<button type="button" onclick="deleteSkill()">Delete row</button>
<hr>
<input type="submit" value="Submit" onclick="submit()" />
</form>
As you can see in the screenshot [![screenshot of the user form][1]][1] the name attribute is correctly being appended to added cell.
The goal is to have a way to get the table values dynamically created by the user over to the flask template where they can be displayed.
Javascript
<script>
var c1=0;
var c2=0;
function addSkill() {
var table = document.getElementById("myTable");
var row = table.insertRow(-1);
var cell1 = row.insertCell(0);
var cell2 = row.insertCell(1);
cell1.innerHTML = "<input type='text' value=' ' name=cell1_"+c1.toString()+"> ";
cell2.innerHTML = "<input type='text' value=' ' name=cell2_"+c2.toString()+"> ";
c1++;
c2++;
}
function deleteSkill() {
document.getElementById("myTable").deleteRow(-1);
}
</script>
I have tried setting the name attribute for each newly created cell using a counter, but this still does not show up rendered in the flask template:
flask
#app.route('/hello_world', methods=['GET', 'POST'])
def hello_world():
if request.method == 'POST':
result = {}
try:
skills = request.form['skills']
result['skills'] = skills
result['value'] = request.form['cell1_1']
except:
pass
return render_template("result.html",result = result)
result.html
{% if result.skills %}
<p>{{ result.value }}</p>
{% endif %}
In this example, I would expect to see "Language" show up on rendered after submitting the form if the checkbox is selected.
How can I refer to the table in the form from flask and loop through the <input> elements if they are dynamically created? Thx
[1]: https://i.stack.imgur.com/samhG.png
result.html
{% if result.skills %}
{% set skillsTable = result.skillsTable %}
<h2>TECHNICAL SKILLS</h2>
<table>
{% for skill in skillsTable %}
{% if loop.index|int % 2 == 0 %}
<tr><td>{{ skillsTable.pop(0) }}:</td><td>{{ skillsTable.pop(0) }}</td></tr>
{% else %}
<tr><td>{{ skillsTable.pop(0) }}:</td><td>{{ skillsTable.pop(0) }}</td></tr>
{% endif %}
{% endfor %}
{% endif %}
flask
#app.route('/hello_world', methods=['GET', 'POST'])
def hello_world():
if request.method == 'POST':
result = {}
try:
skills = request.form['skills']
result['skills'] = skills
result['skillsTable'] = []
form = request.form
for key, value in form.items():
if key.startswith("cell"):
result['skillsTable'].append(value)
except:
pass
return render_template("result.html",result = result)

Multiple forms with Flask keeps saying I haven't defined forms

I am trying to set up two different forms on the same Flask page with validators, but it keeps telling me my forms are not defined. I get error:
The code is designed to allow users to input a number and check if it is abundant, perfect, or deficient, and then with a separate form to allow users to define a range and get how many abundant, perfect or deficient numbers there are within that range.
My code is as follows:
from flask import Flask, render_template, request
from flask_wtf import Form
from wtforms import IntegerField
from wtforms.validators import InputRequired
from perfect_numbers import classify, listInRange
app = Flask(__name__)
app.config['SECRET_KEY'] = 'DontTellAnyone'
class PerfectForm(Form):
inputNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
class PerfectRangeForm(Form):
startNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
endNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
#app.route('/', methods=['GET', 'POST'])
def index():
form1 = PerfectForm(request.form, prefix="form1")
num = 1
Classify = classify(num)
if form.validate_on_submit() and form.data:
num = request.form1['inputNumber']
Classify = classify(form1.inputNumber.data)
return render_template('index.html', form1=form1, num=num, classify=Classify)
return render_template('index.html', num=1, form1=form1, classify=Classify)
#app.route('/aliRange', methods=['GET', 'POST'])
def aliRange():
form2 = PerfectRangeForm(request.form2, prefix="form2")
startNumber = 1
endNumber = 1
aliquot = 'abundant'
Classify = classify(num)
ListInRange = listInRange(startNumber, endNumber, aliquot)
if form2.validate_on_submit() and form2.data:
startNumber = request.form2['startNumber']
endNumber = request.form2['endNumber']
aliquot = request.form2['aliquot']
ListInRange = listInRange(startNumber, endNumber, aliquot)
return render_template('index.html', form2=form2, startNumber=startNumber, endNumber=endNumber, ListInRange=listInRange)
return render_template('index.html', form2=form2, startNumber=startNumber, endNumber=endNumber, ListInRange=listInRange)
if __name__ == '__main__':
app.run(debug=True)
index.html:
{% from "_formhelpers.html" import render_field %}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>WTForms</title>
</head>
<body>
<div>
<form action="/" method="POST">
<dl>
{% if form1 %}
{{ form1.csrf_token }}
{{ render_field(form1.inputNumber) }}
{% endif %}
<input type="submit" value="submit1">
</dl>
</form>
</div>
<div>
{{ num }} is {{ classify }}
</div>
<div></div>
<div>
<form action="/aliRange" method="POST">
<div class="form-group">
<p>Input a start number and an end number to return a list of...</p>
<select class="form-control" action="/aliRange" name="aliquot" method="POST">
<option value = 'abundant'>Abundant</option>
<option value = 'perfect'>Perfect</option>
<option value = 'deficient'>Deficient</option>
</select>
<p>...numbers within that range</p>
<form action="/aliRange" method="POST">
<dl>
{% if form2 %}
{{ form2.csrf_token }}
{{ render_field(form2.startNumber) }}
{{ render_field(form2.endNumber) }}
{% endif %}
<input class="btn btn-primary" type="submit" value="submit">
</dl>
</form>
</div>
</form>
The {{ aliquot }} numbers between {{ startNumber }} and {{ endNumber }} are:
{{ listInRange }}
</div>
</body>
</html>
Error I get atm is: AttributeError: 'Request' object has no attribute 'form1'
EDIT:
You can simplify your code using a single view, using the submit value to differentiate the handling of the first form and the second one.
The modified code is:
class PerfectForm(Form):
inputNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
class PerfectRangeForm(Form):
startNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
endNumber = IntegerField('input a number', default=1, validators=[InputRequired(message='Please input an integer')])
aliquot = StringField('input a kind', default='perfect')
#app.route('/', methods=['GET', 'POST'])
def index():
form1 = PerfectForm(request.form, prefix="form1")
form2 = PerfectRangeForm(request.form, prefix="form2")
num = 1
Classify = classify(num)
startNumber = 1
endNumber = 1
aliquot = 'abundant'
ListInRange = listInRange(startNumber, endNumber, aliquot)
if request.form.get('submit') == 'submit-1':
if form1.validate_on_submit() and form1.data:
num = form1.data['inputNumber']
Classify = classify(num)
elif request.form.get('submit') == 'submit-2':
if form2.validate_on_submit() and form2.data:
startNumber = form2.data['startNumber']
endNumber = form2.data['endNumber']
aliquot = form2.data['aliquot']
ListInRange = listInRange(startNumber, endNumber, aliquot)
return render_template('index.html',
num=num, classify=Classify,
startNumber=startNumber, endNumber=endNumber, aliquot=aliquot, ListInRange=ListInRange,
form1=form1, form2=form2)
if __name__ == '__main__':
app.run(debug=True)
and the modified template index.html is:
{% from "_formhelpers.html" import render_field %}
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>WTForms</title>
</head>
<body>
<div>
<form action="/" method="POST">
<dl>
{{ form1.csrf_token }}
{{ render_field(form1.inputNumber) }}
<input type="submit" name="submit" value="submit-1">
</dl>
</form>
</div>
{% if num %}
<div>
{{ num }} is {{ classify }}
</div>
{% endif %}
<hr />
<div>
<form action="/" method="POST">
{{ form2.csrf_token }}
<div class="form-group">
<p>Input a start number and an end number to return a list of...</p>
<select class="form-control" action="/aliRange" name="aliquot" method="POST">
<option value = 'abundant'>Abundant</option>
<option value = 'perfect'>Perfect</option>
<option value = 'deficient'>Deficient</option>
</select>
<p>...numbers within that range</p>
<dl>
{{ render_field(form2.startNumber) }}
{{ render_field(form2.endNumber) }}
</dl>
<input class="btn btn-primary" type="submit" name="submit" value="submit-2">
</div>
</form>
<div>
The {{ aliquot }} numbers between {{ startNumber }} and {{ endNumber }} are:
{{ listInRange }}
</div>
</div>
</body>
</html>
OLD:
You are using form1 in the template but passing form inside the template context:
render_template('index.html', form=form1, num=num, classify=Classify)
You can either change form1 to form inside the template, or pass form1=form1 in the above line.
If you are rendering multiple forms inside the same template, you have to pass all the respective form variables: form1, form2, ... from all the views rendering that template. Otherwise the template rendering will raise the error you are seeing.
If you are interested in having a single form rendered among all the possible ones inside the template, you can use conditional rendering using
{% if form1 %}
<div>
<form action="/" method="POST">
<dl>
{{ form1.csrf_token }}
...
</dl>
</form>
</div>
{% endif %}
{% if form2 %}
<form action="/aliRange" method="POST">
...
</form>
{% endif %}
...
Also, your html seems incorrect to me, because you have a form nested inside another form. Not sure about what you are trying to obtain there.

Django parallel arrays in a template

I have 2 arrays that I would like to render in a template, one is the data to be output, the other is a formset for deleting items. since it seems django does not support boolean operators in the template tag, I have tried packaging the items, but they return the first item and the first form in 2 rows only.
How does one package such items so that they are rendered in one for loop.
my view
#login_required
def forums(request ):
post = list(forum.objects.filter(child='0')&forum.objects.filter(deleted='0'))
user = UserProfile.objects.get(pk=request.session['_auth_user_id'])
newpostform = PostForm(request.POST)
deletepostform = PostDeleteForm(request.POST)
DelPostFormSet = modelformset_factory(forum, exclude=('child','postSubject','postBody','postPoster','postDate','childParentId'))
readform = ReadForumForm(request.POST)
if newpostform.is_valid():
topic = request.POST['postSubject']
poster = request.POST['postPoster']
newpostform.save()
newpostform = PostForm(initial = {'postPoster':user.id})
post = list(forum.objects.filter(child='0')&forum.objects.filter(deleted='0'))
else:
newpostform = PostForm(initial = {'postPoster':user.id})
if request.method == 'POST':
delpostformset = DelPostFormSet(request.POST)
if delpostformset.is_valid():
delpostformset.save()
else:
delpostformset = DelPostFormSet(queryset=forum.objects.filter(child='0', deleted='0'))
"""if readform.is_valid():
readform.save()
else:
readform = ReadForumForm()"""
return render_to_response('forum.html', {'post':( post,delpostformset.forms), 'newpostform': newpostform, })
my Template
<table class="results">
<tr class="inner_results_header"><td >Title</td><td>Date/Time</td><td>Poster</td> <td>Body</td><td><form method="post" id="form" action="" class="usertabs accfrm"><input type="submit" value="Delete" /></td></tr>
{{formset.management_form}}
{% for p, form in post %}
{% url forum_view p.postID as post_url%}
<tr class="inner_results {% if forloop.counter|divisibleby:2 %}evens{% else %}odds{% endif %}"><span onclick="document.location.href='{{post_url}}';"><td>{{ p.postSubject}}</td><td>{{p.postDate}}</td><td>{{ p.postPoster}}</td><td>{{ p.postBody|truncatewords:50}}</td></span><td>
{{ form.as_p }}
</td></tr>
{% endfor %}
<tr class="inner_results_header"><td >Title</td><td>Date/Time</td><td>Poster</td> <td>Body</td><td><input type="submit" value="Delete" /></form></td></tr>
Use zip builtin. If both post and delpostformset.forms are iterables, zip will return a list of tuples. In view:
post_and_form = zip(post, delpostformset.forms)
and in template:
{% for post, form in post_and_form %}
{% endfor %}

Categories

Resources