I have the following:
models.py
class Person(models.Model):
full_name = models.CharField(...)
address = models.CharField(...)
views.py
def all_persons(request):
persons = Person.objects.all()
return render(
request,
'my_template.html',
{
'persons':persons
}
)
my_template.html
<table class="table table-striped">
<thead>
<tr>
<th>Person's Fullname</th>
</tr>
</thead>
<tbody>
{% for person in persons %}
<td>{{ person.full_name }}</td>
<td>{{ person.address }}</td>
Ok, so the code as it is will display an unordered list of persons in the template, of course I can manage to order by Person's name or address, I want to give the user the possibility to order by any field, I want to accomplish this with a button on each column of the table in the template. For example a button on top of full_name and a button on top of address, if any of those is pressed, then the list should be ordered depending on the pressed button.
Thank you very much for reading, hope you can help me.
Edit: I use Twitter Boostrap 2, so tablesorter and DataTables JS wont work.
Check out this JS plugin for HTML tables: Datatables. Comes with sorting, filtering, pagination, lots of plugins. Easy to get started, but you might consider it a bit bloated.
Another way is to have the view take an extra argument (an integer representing a field, for example), sort the queryset by this field and render the template.
Related
I have created a simple Django application to display individual articles. These articles have a number of fields that users can edit. I am using the package 'django-auditlog' to log changes to these article models. So far, I have simply followed the auditlog installation doc to setup model history tracking (as well as enabling the middleware to allow 'actor_id' to be tracked). I have also added the example code that displays the most recent changes on the individual model pages as such:
<!-- History display -->
<div class="table-responsive">
<table id="history" class="table table-striped table-bordered">
<thead>
<tr>
<th>Actor</th>
<th>Field</th>
<th>From</th>
<th>To</th>
</tr>
</thead>
<tbody>
<!-- Human readable - change to '.changes_dict.' for proper logs -->
{% for key, value in article.history.latest.changes_display_dict.items %}
<tr>
<td>{{ article.history.latest.author_id }}</td>
<td>{{ key }}</td>
<td>{{ value.0|default:"None"|striptags|safe }}</td>
<td>{{ value.1|default:"None"|striptags|safe }}</td>
</tr>
{% empty %}
<p>No history for this item has been logged yet.</p>
{% endfor %}
</tbody>
</table>
</div>
As my code may suggest, I am trying to add an additional column to the history table to show who made the changes that are being displayed.
Is there an easy way to do this through auditlog, or will I have to create some kind of sql query to my sqlite auditlog db table to retrieve the 'author_id' field?
Thank you!
I figured out the answer after looking through the models file for Django AuditLog. It is not possible to pull the actor out directly from the history field of the model if you have created the history field using the AuditlogHistoryField() method as described in the django-auditlog tutorial.
Instead, I did the following:
In the views.py file
from auditlog.models import LogEntry
...
dal_log = LogEntry.objects.get_for_object(article)
...
context = {'article': article, 'logs': dal_log}
return render(request, "detail.html", context)
Then in my template, I was able to work with the log entries for the specified object (in my case, these were 'article' models). There may be a cleaner way, but this worked for me.
I am following along an online Python tutorial and I am have to create an HTML template in which creates a table for the end user to see the movies in the inventory. I have followed the teachers instructions step-by-by step but when I refresh the browser page, it only shows the class attributes that I listed in the HTML. The code that I wrote is below:
index.html file:
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Genre</th>
<th>Stock</th>
<th>Daily Rate</th>
</tr>
</thead>
<tbody>
{% for movie in movies %}
<tr>
<td>{{ movie.title }}</td>
<td>{{ movie.genre }}</td>
<td>{{ movie.number_in_stock }}</td>
<td>{{ movie.daily_rate }}</td>
</tr>
{% endfor %}
</tbody>
</table>
and the views.py file:
from django.http import HttpResponse
from django.shortcuts import render
from .models import Movie
def index(request):
movies = Movie.objects.all()
return render(request, 'index.html', {' movies': movies})
Here is what results on my web browser:
enter image description here
If someone knows why this is not working, any help would be awesome!
You seem to have a space where you are passing the context:
return render(request, 'index.html', {' movies': movies})
You need to replace ' movies' with 'movies', otherwise the variable will not be available with the correct name while rendering the template.
As the other user #le.chris mentioned, you seem to have a space where you are passing the context.
This would be the right context : return render(request, 'index.html', {' movies': movies}).
However, in your views file, I highly suggest having Class-based views, start by importing the ListView in this case and create a post_list.html or specify a template_name and since you are using movies as your context object, you also need to specify that in the context_object_name attribute. Maybe like this :
class MovieListView(ListView):
model = Movie
template_name = 'appname/index.html' #appname is the name of your app
context_object_name = 'movies'
ordering = # optional
paginate_by = 3
in your urls.py file of the app :
path('', MovieListView.as_view(), name='movie-index') #adjust the name as you please
Currently i have a Django Form where i can add a new customer to the database. I also have a table showing all customers currently in this database. Now i would like to click on a customer name in the customer table to open the existing customer and have the option to edit the record and save.
Below is my current code parts, if more is needed please ask.
my navbar.html
<li><a href='{% url "customeradd" %}'>New Customer</a></li>
my urls.py
url(r'^customeradd/$', 'customer.views.customeradd', name='customeradd'),
my views.py
def customeradd(request):
form = CustomerAddForm(request.POST or None)
if request.method == 'POST':
if form.is_valid():
save_it = form.save(commit=False)
save_it.save()
messages.success(request, 'Customer added succesfully')
return HttpResponseRedirect('/customeroverview/')
else:
messages.error(request, 'Customer save error, please check fields below')
else:
form = CustomerAddForm()
return render_to_response("customer-add.html",
{"customer_add_form": form},
context_instance=RequestContext(request))
customeroverview.html which shows table of all customers (only three fields showing)
<td><a href='{% url "customeradd" %}'>{{ customer.customer_name }}</a></td>
<td>{{ customer.customer_type }}</td>
<td>{{ customer.customer_address }}</td>
So now i can click on the customer name in the customer table and the CustomerAddForm will open. Offcourse in the current situation empty as no arguments are given.
How would i pass the customer.id field as argument when clicking on the customer.customer_name hyperlink in the customeroverview.html?
How would i catch this customer.id in the view - how should urls.py look like?
When the form is opened with the existing customer.id, how should i save the current record instead of creating a new customer.id
Any help / suggestions on this situation would be very helpful in my understanding of Django GET / POST.
Maybe you should do:
In urls.py
url(r'^customeradd/(?P<id>\w+)$', 'customer.views.customeradd', name='customeredit'),
url(r'^customeradd/$', 'customer.views.customeradd', name='customeradd'),
in your views.py:
def customeradd(request, id = None):
if id:
customer = Customer.objects.get(pk = id)
else
customer = None
form = CustomerAddForm(request.POST, instance = customer)
.....
in your template
<td>< a href='{% url "customeredit" customer.id %}' >{{ customer.customer_name }}</a></td>
<td>{{ customer.customer_type }}</td>
<td>{{ customer.customer_address }}</td>
Basically, what you are talking about is called CRUD (Create, Read, Update and Delete).
If you are writing a simple webapp GUI (which seems so to me), an easy example can be found here on how to implement CRUD with Django.
If, however, you are writing a REST API, things get a little more complex. Django REST Framework could be helpful then.
I've read in the docs and stackoverflow but i cant figure out why my foreign key following isnt working, django just says that there is no such attribute as vote_story_set.all().
I have a table named story and one named vote_story and the story table has several foreign keys like a foreign to vote_story to get the number of votes for a news story.
According to the docs and the detailed answer here: *_set attributes on Django Models i created an object like this:
all_stories = Story.objects.all()
votes = all_stories.vote_story_set.all()
but this doesnt work since django says that there is no such attribute as "vote_story_set". The database table for story has the 'votes' attribute as a foreign key to the table Votes_story. From the examples ive seen this should be working so i dont understand why it doesnt. There is no foreign keys in the Votes_story table, just a primay key and the attribute 'votes' containing the number of votes.
Update:
Models and template is shown below for Story and Vote_story as well as the relevant view.
Models:
class Story(models.Model):
story_id = models.IntegerField(primary_key=True)
date_added = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
title = models.CharField(max_length=150)
description = models.CharField(blank=True, null=True, max_length=2000)
story_text = models.TextField()
picture = models.ImageField(blank=True, null=True, upload_to="story/images")
storyAccessLevelID = models.ForeignKey(StoryAccessLevel)
categoryID = models.ForeignKey(Category)
votes = models.ForeignKey(Vote_story, blank=True, null=True)
comments = models.ForeignKey(Comment, blank=True, null=True)
def __unicode__(self):
return self.title
class Vote_story(models.Model):
votes = models.IntegerField()
def __unicode__(self):
return self.votes
In the file Vote_story is defined above Story so it can find it.
In Vote_story i let django create the primary key automatically unlike Story.
There is currently one vote for one of the stories added.
Template code (the relevant portion):
<table class="table table-hover">
<thead>
<tr>
<th>Title</th>
<th>Description</th>
<th>Date added</th>
<th>Votes</th>
<th>Comments</th>
</tr>
</thead>
<tbody>
{% for story in all_stories %}
<tr>
<td>{{ story.title }}</td>
<td>{{ story.description }}</td>
<td>{{ story.date_added }}</td>
<td>{{ story.votes }}</td>
<td>{{ story.comments }}</td>
</tr>
{% endfor %}
</tbody>
</table>
The view is like this:
def list_all_stories(request):
""" Show all stories """
all_stories = Story.objects.all()
return render(request, "base/story/all_stories.html", {'all_stories': all_stories})
all_stories is a queryset, not an instance. vote_story_set is an attribute on each instance within the queryset, not the queryset itself.
Plus, you seem to be confused about the direction of relations. If your ForeignKey goes from Vote to VoteStory, you don't need the reverse relation, you need the forward one, which is just whatever you called the field. Again, though, this is an attribute of each instance, not the queryset.
I'm struggling to figure out how to accomplish unique form field instances that are associated with another element in a table. For a contrived example, here's the following code:
from flask import Flask, render_template, request
from flask.ext.wtf import Form
from wtforms import TextField, BooleanField
app = Flask(__name__)
app.debug = True
app.config['SECRET_KEY'] = 'secret'
class Person(Form):
fname = TextField('First Name')
phone = TextField('Phone Number')
email = TextField('Email Address')
active = BooleanField('Active')
#app.route("/", methods=['GET', 'POST'])
def guest():
names = ['Bob', 'Joe', 'Jason', 'John'] # this could be a list, or data returned from a db query, previous POST data, or whatever
form = Person()
if request.method == 'POST' and form.validate_on_submit():
return str(form.data)
return render_template('index.html', names=names, form=form)
if __name__ == "__main__":
app.run(host='0.0.0.0')
My template:
<html>
<body>
<form action="" method="post">
<table border="1">
<thead>
<tr>
<th>Name</th>
<th>Telephone Number</th>
<th>Email Address</th>
<th>Active</th>
</tr>
</thead>
<tbody>
{% for n in names %}
<tr>
<td>{{ n }}</td>
<td>{{ form.phone }}</td>
<td>{{ form.email }}</td>
<td>{{ form.active }}</td>
</tr>
{% endfor %}
</tbody>
</table>
It's obvious that in the HTML, the name parameters for each input element in each table row are all identical, because the same form field is being used, so on "POST", if one enters a phone number, that phone number is now populated for all the name rows in the table. Same goes for the "Activate" checkbox. I've also tried generating a list of form instances and passing that list into the template, but it doesn't appear to be working as I expected it would. It would seem as though my options at this point are:
Don't use WTForms for this (see note below)
Use the WTForms FieldList + FormField (I don't think this would work either as these require named keys vs arbitrary keys so I'd run into the exact same issue.)
Use HiddenFields in some fashion (Haven't even thought of how this would work).
I'm aware that I can just create the <input type> elements into the table manually via the template and assign them different names/id's based on w but this doesn't feel very idiomatic, plus I'd have to code in the validation on my own.
You normally would pass in a multi-dict object containing the form data as the first argument to the form:
form = UpdateWidgetForm(request.form)
this does require that the POST data matches the widgets in the form; each widget will inspect that multi-dict and pull out what it needs to render with some pre-populated data.
Alternatively, you can pass in values as keyword arguments, but that does require you've validated the input yourself, converting any values to the right types:
number = request.form.get('widget_number')
try:
number = int(number)
except ValueError:
abort(404)
policy = request.form.get('widget_policy')
if policy not in ('foo', 'bar'):
abort(404)
form = UpdateWidgetForm(widget_number=number, widget_policy=policy)
See How Forms get data in the documentation.
If you need to generate multiple forms within a page, each unique, from the same form object, you need to give them each a unique prefix with the Form(prefix=..) argument.