Python Django edit data in database by forms (django v.1.9.4) - forms

My goal is add data to database via form and make them editable via edit form.
My error:
Exception Type: NoReverseMatch at /testtable/car/new/
Exception Value: Reverse for 'car_list' with arguments '()' and keyword arguments '{'pk': 2}' not found. 0 pattern(s) tried: []
and next problem is how to make a link to edit data
in template/car_list.html to car_edit.html.
<td>Delete</td>
<td>Edit Delete</td>
When I type manually in Explorer http://localhost:8000/testtable/car/1/ it works, I see details of first article in database, but forms with pk arguments doesnt work.
MyApp/testtable/models.py
from django.db import models
import datetime
from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
class TableParemeters(models.Model):
author = models.ForeignKey('auth.User')
car_brand = models.CharField(max_length=20)
car_type = models.CharField(max_length=20)
car_colour = models.CharField(max_length=20)
car_fuel = models.CharField(max_length=20)
car_trans = models.CharField(max_length=20)
car_license_plate = models.CharField(max_length=20)
created_date = models.DateTimeField(default=timezone.now)
def __str__(self):
return "%s %s" % (self.car_brand, self.car_type)
MyApp/testtable/views.py
from django.shortcuts import redirect, get_object_or_404, render_to_response, render
from django.http import HttpResponseRedirect, HttpResponse
from django.core.urlresolvers import reverse
from django.template import loader
from django.views import generic
from django.utils import timezone
from django.template import RequestContext
from django.core.context_processors import csrf
from django.contrib.auth.models import User
from .models import TableParemeters
from .forms import CarForm
def car_list(request):
cars = TableParemeters.objects.all().order_by('id')
return render(request, 'testtable/car_list.html', {'cars': cars})
def car_detail(request, pk):
car = get_object_or_404(TableParemeters, pk=pk)
return render(request, 'testtable/car_detail.html', {'car': car})
def car_new(request):
if request.method == "POST":
form = CarForm(request.POST)
if form.is_valid():
car = form.save(commit=False)
car.save()
return redirect ('car_list', pk=car.pk)
else:
form = CarForm()
return render(request, 'testtable/car_new.html', {'form': form})
def car_edit(request, pk):
car = get_object_or_404(TableParemeters, pk=pk)
if request.method == "POST":
form = CarForm(request.POST, instance=car)
if form.is_valid():
car = formsave(commit=False)
car.save()
return redirect('car_detail', pk=car.pk)
else:
form = CarForm(instance=car)
return render(request, 'testtable/car_edit.html', {'form': form})
MyApp/testtable/forms.py
from django import forms
from .models import TableParemeters
class CarForm(forms.ModelForm):
class Meta:
model = TableParemeters
fields = '__all__'
MyApp/testtable/urls.py
from django.conf.urls import include, url
from . import views
app_name = 'testtable'
urlpatterns = [
#login
#url(r'^$', views.login_page, name='login'),
#logout
#carlist url
url(r'^$', views.car_list, name='car_list'),
#detail car url
url(r'^car/(?P<pk>\d+)/$', views.car_detail, name='car_detail'),
#add new car to list url
url(r'^car/new/$', views.car_new, name='car_new'),
#edit car in the list
url(r'^car/(?P<pk>\d+)/edit/$', views.car_edit, name='car_edit'),
]
MyApp/testtable/template/testtable/car_list.html
{% extends 'testtable/base.html' %}
{% block content %}
<table class="table table-striped">
<tbody>
<tr>
<th>ID</th>
<th>Brand</th>
<th>Type</th>
<th>Colour</th>
<th>Fuel</th>
<th>Transmition</th>
<th>License Plate</th>
<th>Created Date</th>
<th>Author</th>
<th></th>
</tr>
{% for testtable in cars %}
<tr>
<td>{{ testtable.car_id }}</a></td>
<td>{{ testtable.car_brand }}</a></td>
<td>{{ testtable.car_type }}</td>
<td>{{ testtable.car_colour }}</td>
<td>{{ testtable.car_fuel }}</td>
<td>{{ testtable.car_trans }}</td>
<td>{{ testtable.car_license_plate }}</td>
<td>{{ testtable.created_date }}</td>
<td>{{ testtable.author }}</td>
<td>Delete</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}

I mean, that car_list not need pk and django can't found any url for car_list with parameter.
Maybe you can try replace line:
return redirect ('car_list', pk=car.pk)
with:
return redirect ('car_list')

Related

Using Django, how do I set a ModelForm field value dynamically in the template?

I'm trying to utilize a checkbox field to create a model instance for a user selected favorite. The last piece I need in order for this to work properly is to set the default value in one of the form fields equal to the value in a loop. Would I do this with the initialize argument, in the views.py file, in the form itself, or in the template? Here is the associated code:
Apologies for the HTML class tags
models.py
class ReportDirectory(models.Model):
report_name = models.CharField(max_length=300, unique=True, blank=False)
report_desc = models.TextField()
report_type = models.CharField(max_length=300)
report_loc = models.TextField()
slug = models.SlugField(unique=True, max_length=300)
last_update = models.DateTimeField(null=True)
main_tags = models.CharField(max_length=300)
# Renames the item in the admin folder
def __str__(self):
return self.report_name
class Favorite(models.Model):
directory_user = models.ForeignKey(User, on_delete=models.CASCADE)
user_report = models.ForeignKey(ReportDirectory, on_delete=models.CASCADE)
favorited = models.BooleanField(default=False)
def __str__(self):
return str(self.directory_user)+" - "+str(self.user_report)
forms.py
from django import forms
from .models import Favorite
class FavoriteForm(forms.ModelForm):
class Meta:
model = Favorite
fields = '__all__'
widgets = {
'favorited': forms.CheckboxInput(attrs={
'type':'checkbox',
'name':'checkbox',
'onchange':'submit()'
})
}
views.py
from django.shortcuts import render,redirect
from django.views import generic
from .models import ReportDirectory, Favorite
from django.contrib.auth.models import User
from .forms import FavoriteForm
def report_directory(request):
favorite = Favorite.objects.filter(directory_user=request.user.id, favorited=True)
reports = ReportDirectory.objects.exclude(favorite__directory_user=request.user.id, favorite__favorited=True)
favform = FavoriteForm(initial={'directory_user':request.user},)
context = {
'reports':reports,
'favorite':favorite,
'favform':favform
}
if request.method == 'POST':
form = FavoriteForm(request.POST)
if form.is_valid():
form.save()
return redirect('/report_directory')
return render(request, 'counter/report_directory.html',context)
html
<thead>
<tr>
<th class="gls-table-expand">Favorite</th>
<th onclick="sortTable(1)" class="gls-table-expand">Report Type</th>
<th onclick="sortTable(2)" class="gls-table-expand">Report Name</th>
<th class="gls-table-expand">Report Description</th>
<th onclick="sortTable(3)" class="gls-table-expand">Last Updated</th>
<th class="gls-table-expand">Main Tags</th>
<th onclick="sortTable(4)" class="gls-table-expand">View Count</th>
</tr>
</thead>
<tbody id="myTable">
{% for r in reports.all %}
<tr report-name="{{ r.report_name }}">
<td>
<form method="POST">
{% csrf_token %}
{{ favform.favorited }}
</form>
</td>
<td><span><img img width="20" height="20"
{% if r.report_type == 'Tableau' %}
src=" {% static 'images/tableau_icon.svg' %}"
{% elif r.report_type == 'Excel' %}
src=" {% static 'images/excel_icon.svg' %}"
{% elif r.report_type == 'Box' %}
src=" {% static 'images/excel_icon.svg' %}"
{% elif r.report_type == 'Internal Report' %}
src=" {% static 'images/www_icon.svg' %}"
{% endif %}
></span> {{ r.report_type }}</td>
<td>{{ r.report_name }}</td>
<td>{{ r.summary }}</td>
<td><p class="gls-text-meta gls-margin-remove-top">{{ r.last_update_format }}</p></td>
<td>{{ r.main_tags }}</td>
<td>{% get_hit_count for r %}</td>
</tr>
{% endfor %}
</tbody>
I found a solution to dynamically iterate through the template and complete the ForeignKey (selection) field. I needed to set the for iterator equal to the selection option
<form method="POST" id="{{ r.report_name }}">
{% csrf_token %}
<p hidden>
{{ favform.directory_user }}
<select name="user_report" required="" id="id_user_report">
<option value="{{ r.id }}" selected></option>
</select>
</p>
{{ favform.favorited }}
</form>
I feel like I'm working against Django forms, however, and not with the infrastructure...

How to update multiple objects by one html request?

I have a problem and can't find a decision.
I need to update a value for several objects by one form. If I did it one by one, without submit button it works fine. But I want to do it by click to one button.
My HTML form:
<form method="post" action="{% url 'installmentreport-update' %}">
{% for installmentreport in installment.installmentreport_set.all %}
<tr>
<td class="align-middle" style="text-align:center">{{installmentreport.title}}</td>
<td class="align-middle" style="text-align:center">
{% csrf_token %}
<input type="number" name='spent' value={{installmentreport.spent}} placeholder={{installmentreport.spent}} size="8">
<input type="hidden" name='id' value={{installment.id}}></td>
<input type="hidden" name='pk' value={{installmentreport.id}}>
</tr>
{% endfor %}
<td></td>
<td class="align-middle" style="text-align:center"><input type="submit" class="btn btn-warning" name="submit" value="Update"></form>
Views:
class InstallmentReportUpdate(LoginRequiredMixin,PermissionRequiredMixin,UpdateView):
model = InstallmentReport
permission_required = 'catalog.can_change_program'
fields = ['spent']
def get_object(self):
pks = self.request.POST.getlist('pk')
for pk in pks:
return InstallmentReport.objects.get(pk=pk)
def form_valid(self, form):
if self.request.method == 'POST':
spents = self.request.POST.getlist('spent')
if form.is_valid():
for spent in spents:
instance = form.save(commit=False)
form.instance.spent = spent
instance.save()
return super().form_valid(form)
def get_success_url(self):
id = self.request.POST.get('id')
return reverse('installment-detail-owner', args=[str(id)])
I use Python3.7 and Django2.2
I did it!
Views:
def get_object(self):
pks=self.request.POST.getlist('pk')
spents = self.request.POST.getlist('spent')
for pk, spent in zip(pks,spents):
print(pk)
print(spent)
InstallmentReport.objects.filter(pk=pk).update(spent=spent)
return InstallmentReport.objects.get(pk=pk)

Bottle.py - split string array (CSV)

I have a small web demo pulling data from into a CSV file, which I want to display on a web page. I plan to use Bottle.py, but I cannot split the string into an array. There will be multiple lines in the CSV file, which I will read in split and then create a table.
from bottle import run, debug, template, get, redirect, request, response, static_file, route, os, sys
LOG_FILENAME = "data.csv"
#route('/hello/<name>')
def index(name):
readfiledata()
print(reader)
array = reader.split(',')
return template('<b>Hello {{name}}</b>!', name=reader)
Maybe something like this (using csv module from the Standard Library):
import csv
from bottle import route, jinja2_template
#route('/csv')
def show_csv():
with open('data.csv') as fo:
csv_reader = csv.reader(fo)
table = [row for row in csv_reader]
return jinja2_template('templ.html', table=table)
templ.html (I'm using Jinja2 templates which I prefer over Bottle's built-in templating language):
<table style="width:100%">
<tr>
{# Table header #}
<th>Foo</th>
<th>Bar</th>
<th>Baz</th>
</tr>
{% for row in table %}
<tr>
{% for cell in row %}
<td>{{ cell }}</td>
{% endfor %}
</tr>
{% endfor %}
</table>

Django form for querying database. Is form.py needed and how to leave fields empty for query?

I would like to have an input form where a user inputs either an incident_id or a equipment_id or both. The problem I have now is for example, if I fill in incident_id and leave equipment_id blank, the query will return no hits even when incident_id finds a match, because my query uses blank equipment_id in the search. How can I set it up so that when I leave a field blank, it doesn't use it in the query? Do I need to validate this data? I'm not inserting any of it into the db.
I know Django forms uses POST, but in this instance I feel that GET is more appropriate, which means I don't have to use Django forms, but does that mean I also don't have to validate the data? Or should I just use POST anyway and validate that data with Django forms? I'm sorry this is so conceptual. I'm not finding many good answers online.
model.py
from django.db import models
class Incident(models.Model):
incident_id = models.CharField(max_length=1000, blank=True)
equipment_id = models.ForeignKey(Equipment, blank=True)
class Equipment(models.Model):
equipment_id = models.CharField(primary_key=True, max_length=100)
manufacturer = models.ForeignKey(Manufacturer)
equipment_category = models.ForeignKey(Equipment_Category)
validated= models.BooleanField(default=True)
in_service_date = models.DateTimeField('in service date', default=timezone.now)
view.py
#login_required
def search_incidents_query(request):
if request.method == 'GET':
incident_id_query = request.GET.get('incident_id')
equipment_id_query = request.GET.get('equipment_id')
try:
incident_id = str(incident_id_query)
except ValueError:
incident_id = None
try:
equipment_id = str(equipment_id_query)
except ValueError:
username = None
list = [incident_id,equipment_id]
if all(x is None for x in list): #check if `list` contains only None
incident_list = None #this in case the query comes back empty
else: #perform query
incident_list = Incident.objects.filter(incident_id=incident_id, equipment_id=equipment_id)
)
return render(request, 'search_incidents_query.html', {
'incident_list' : incident_list
})
search_incidents_query.html
{% extends "base.html" %}
{% load widget_tweaks %}
{% block content %}
<br>
<div class="container-fluid">
<!-----INPUT FORM------------------->
<form method='GET' action='/search_incidents/'>
<div class="row">
<div class="form-group col-md-3">
<label>Incident ID</label>
<input type="text" name="incident_id" value="{{ incident_id_query }}" class="form-control"/>
</div>
<div class="form-group col-md-3">
<label>Equipment ID</label>
<input type="text" name="equipment" value="{{ equipment_id_query }}" class="form-control"/>
</div>
</div>
</form>
</div>
{% endblock %}
The query
You should use a Q object for similar queries.
from django.db.models import Q
Incident.objects.filter(
Q(incident_id=incident_id) | Q(equipment_id=equipment_id)
)
More on Q objects.
Also, IMO this code needs to live in some Form class. If it was me, I would have put this code in some
The form
class IncidentSearchForm(forms.Form):
incident = forms.CharField(required=False)
# ModelChoiceField because we want django to do the validation for us
# TextInput because the default widget is a select tag
equipment = forms.ModelChoiceField(Equipment.objects.all(), required=False, widget=forms.TextInput) # TextInput because
def clean(self):
# I'd use the clean method to force the user to provide either an incident or equipment value
def search(self):
return Incident.objects.filter(
Q(incident_id=self.cleaned_data['incident']) |
Q(equipment_id=self.cleaned_data['equipment'])
)
The view
Why aren't you using Class Based Views already?
username = None. Wat?
You should use a form because never trust user input.
#login_required
def search_incidents_query(request):
form = IncidentSearchForm(request.GET or None)
incident_list = None
if 'equipment' in request.GET or 'incident' in request.GET:
incident_list = None # Or maybe Incident.objects.none()
if form.is_valid():
incident_list = form.search()
return render(request, 'search_incidents_query.html', {'form' : form})
The template
<form method='GET' action='/search_incidents/'>
<div class="row">
<div class="form-group col-md-3">
{{ form.incident }}
</div>
<div class="form-group col-md-3">
{{ form.equipment }}
</div>
</div>
<input type="submit" />
</form>
You can use a widget on the form to add form-control class to the fields.

Variable 'name' in a django template form

I have the following template, which has both an "add" and "delete" button:
<tr>
<td>Position</td>
<td>{{ form.position }}<input type="submit" value="add" , name='add'/></td>
</tr>
<tr>
<td> </td>
<td>
{% for position in positions %}
{{ position}}<input type="submit" value="Delete", name="delete-position.{{ position }}"/>
{% endfor %}
</td>
</tr>
How would I construct the views.py function to find the name value of the Delete submit button? I currently have:
try:
request.POST['add']
positions.append(request.POST['position'])
return render_to_response('registration/getting_started_info1.html', {'form': form, 'positions': positions}, context_instance = RequestContext(request))
except:
if 'delete-position' in request.POST:
positions.remove(### how to get name of Delete submit? ###)
return render_to_response('registration/getting_started_info1.html', {'form': form, 'positions': positions}, context_instance = RequestContext(request))
Also, is there a better way to construct the view/template so I can use an if...else instead of a try...except ?
First, you should probably do this:
if request.method == "POST":
if 'add' in request.POST.keys():
positions.append(...)
return render_to_response(...)
else:
for k, v in request.POST.items():
if k.startswith('delete-position'):
positions.remove(k)
return render_to_response(...)
That should help with what you're asking... however, I'm not sure if it's the easiest method to do what you're trying to do.
Save the positions in the session.
Your try-catch is kind of weird. You should probably be submitting delete requests to a different view.
But as to how you can get the delete-position vars, it's easy:
def delete(request):
if request.method == "POST":
for key in request.POST.keys():
if key.startswith('delete-position'):
positions.remove(request.POST[key])