Django - ModelForm - UpdateView -pk - django

I would like to implement UpdateView in order to update selected objects of my Model.
Currently I have:
views.py
def fd_detail(request, fdslug):
fddetail = Fd.objects.get(slug=fdslug)
cffilter = CashFlowFilter(request.GET, queryset=CashFlow.objects.filter(feeder__slug=fdslug))
return render(request, 'fd/fd_detail.html',
{'fddetail': fddetail,
'cffilter': cffilter,
})
class CashFlowUpdate(UpdateView):
model = CashFlow
fields = ['amount', 'description']
url.py
path('<slug:fdslug>/updatecashflow/', views.CashFlowUpdate.as_view(),name = "update_cashflow"),
path('<slug:fdslug>/', views.fd_detail, name="fd_detail")
update_cashflow.html
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update">
</form>
I get the following error : " Generic detail view CashFlowUpdate must be called with either an object pk or a slug in the URLconf." , which means i need to pass-through the primary key of the object I want to Update... What is the best way to do it? Currently all my objects are displayed via a table (see below)? i could add a column with a url link "Edit", but how to put the pk in it?
<table class="table table-bordered">
<thead>
<tr>
<th>Amount</th>
<th>Description</th>
<th>Edit</th>
</tr>
</thead>
<tbody>
{% for cashflow in cffilter.qs %}
<tr>
<td> {{cashflow.amount}} </td>
<td> {{cashflow.description}} </td>
<td> ?????? </td>
</tr>
{% empty %}
<tr>
<td colspan="5"> No cashflow matches your search criteria</td>
</tr>
{% endfor %}
</tbody>
</table>
many thanks

Like the error says:
Generic detail view CashFlowUpdate must be called with either an object pk or a slug in the URLconf.
An update view usually needs some kind of URL parameter to determine which object to update. It implicitly aims to check for two fields: the slug and the primary key. But here in your urls.py, you used fdslug as a URL parameter.
This can easily be resolved by specifying a slug_url_kwarg [Django-doc] yourself, like:
class CashFlowUpdate(UpdateView):
model = CashFlow
fields = ['amount', 'description']
slug_url_kwarg = 'fdslug'
As for an edit link, you can add a {% url ... %} template tag, like:
<td>edit</td>

Related

Bootstrap Table not sending selected checkbox values in POST request in Django app

I am using Bootstrap Table (https://bootstrap-table.com/) to display a product list in a Django app. I would like the user to select some products and click the button to submit. Using Bootstrap Table seems to prevent the checked checkboxes being sent in the POST request.
views.py
class ProductProcessView(View):
def post(self, request):
products = request.POST.getlist('product_checkboxes')
# process the chosen products
return redirect('product-list')
html template
<form method="post">
{% csrf_token %}
<table class="table-striped"
data-toggle="table"
>
<thead>
<tr>
<th data-field="product_id" data-checkbox="true"></th>
<th data-field="product">Product</th>
</tr>
</thead>
{% for product in product_list %}
<tr>
<td><input type="checkbox" name="product_checkboxes" value="{{ product.id }}"></td>
<td>{{ product.short_name }}</td>
</tr>
{% endfor %}
</table>
<button onclick="location.href='{% url 'process-products' %}'">Select Products</button>
</form>
If I remove the line data-toggle="table" this correctly sends the selected product IDs in the POST request, but with that line included it does not send any IDs at all. Bootstrap Table requires the data-toggle="table" attribute to initialise the table so without it there is no formatting.
This is the request.body with data-toggle="table" included:
<QueryDict: {'csrfmiddlewaretoken': ['fOma6gtvG2ETw1hrVYMdIuSUWuE1RA2jpX2Tae7ntipMPGX4yKNYEGgkHD0Jcuco'], 'btSelectItem': ['on', 'on']}>
This is without it:
<QueryDict: {'csrfmiddlewaretoken': ['Si6UyiTZ4yAJNYKKQ9FtA8dk0gNPGTPp2rMDCgxRROlC6DqntVGewkBKLp9x1NZu'], 'product_checkboxes': ['43004', '43006']}>
I would be very grateful for any ideas about how I can use the Bootstrap Table framework with it's formatting and widgets, but still be able to use checkboxes to collect the product data.
You can't rely on your HTML because it is dynamically replaced by BootstrapTable.
So you need to use its API to retrieve the values. The simplest way is to add script to the page which will get values from table and assign on some (hidden) element in the form.
Then - on Python side you will read this field and process the data.
See example (uses JQuery but can be converted to plain JS):
<script>
$(document).ready(function () {
$('#product-form').on('submit', function () {
const table = $('#products').bootstrapTable('getSelections')
$('#checkboxes').val(JSON.stringify(table))
})
})
</script>
Some corrections to the template:
Add ID to form
Include product ID as hidden column
Add hidden element which will pass content via form
html template:
<form method="post" id="product-form">
{% csrf_token %}
<table id="products" class="table-striped" data-toggle="table">
<thead>
<tr>
<th data-field="product_check" data-checkbox="true"></th>
<th data-field="product_id" data-visible="false">ID</th>
<th data-field="product">Product</th>
</tr>
</thead>
<input id="checkboxes" name="product_checkboxes" style="display: none">
{% for product in product_list %}
<tr>
<td><input type="checkbox" data-id="{{ product.id }}" value="{{ product.id }}"></td>
<td>{{ product.id }}</td>
<td>{{ product.short_name }}</td>
</tr>
{% endfor %}
</table>
<button id="select-products" onclick="location.href='{% url 'process-products' %}'">Select Products</button>
</form>
And finally - getting the data in views.py:
def post(self, request):
products = json.loads(request.POST.get('product_checkboxes'))
# process the chosen products
return redirect('product-list')
Note that in this case products will be a list of objects. Each object has values that are correspondent to columns

Django Form Not Validating my Date fields

I have a Search form that includes the query box, some checkbox items, and a start and end date. I am getting my information when I enter a query, so I know it is performing the search_results action, but the start and end date is not getting validated at all. I have yet to add the code to handle the start and end date in my results, but the issue is there is no client side validation happening on the form.
My form looks like this:
class SearchForm(forms.Form):
q = forms.CharField(max_length=64,required=False)
service_choices = forms.MultipleChoiceField(
required=True,
widget=forms.CheckboxSelectMultiple,
choices=CustomUser.SERVICE_CHOICES,
)
start_date = forms.DateField(required=False)
end_date = forms.DateField(required=False)
I tried using Class Based View, but did not get any fields at all, so I
tried using a function based view to get my search criteria.
The view looks like:
def get_search(request):
form = SearchForm()
return render(request, 'get_search.html', {'form':form})
My template is:
<!-- templates/get_search.html -->
{% extends "base.html" %}
{% block title %}Search{% endblock title %}
{% block content %}
{% if user.is_authenticated %}
<br><br>
<TABLE BORDER="0" WIDTH="100%">
<TR>
<TD ALIGN="Left"><B>Track X - search</B></TD>
<TD ALIGN="Center"><B>User: {{ user }}</B></TD>
<TD ALIGN="Right"><B>Service: {{ user.service }}</B></TD>
</TR>
</TABLE>
<form action="{% url 'search_results' %}" method="get"">
{% csrf_token %}
<TABLE BGCOLOR="#66CCCC" Border="2" WIDTH="100%">
<TR>
<TD ALIGN="Left" WIDTH="100"> Services:</TD>
<TD ALIGN="Right">Search expression:</TD>
<TD ALIGN="Left">
{{ form.q }}
<button type="submit" name="submit">Search TrackX</button>
</TD>
</TR>
<TR>
<TD WIDTH="100"> {{ form.service_choices }} </TD>
<TD COLSPAN="2" ALIGN="Center"> Start Date: {{ form.start_date }}
End Date: {{ form.end_date }}</TD>
</TR>
</TABLE>
</form>
{% else %}
<p>You are not logged in</p>
Log In |
Sign Up
{% endif %}
{% endblock content %}
The Search_results view just uses the query to build some Q Filter
queries, and it seems to be working correctly.
It originally used a GET Method, and was passing the parameters into the search results view just fine. It just doesn't validate the dates (or anything else I assume) before passing the parameters into the view.
Can anyone tell me what am I missing here?
As I see on the view that your posted, you are not actually checking if the form is valid, you can do that by using:
if request.method == 'POST':
form = SearchForm(request.POST)
form.is_valid()
This method will validate all your fields, and return the boolean value representing if its valid or not.

Django:The QuerySet value for an exact lookup must be limited to one result using slicing

I am working on a project where admin can assign team to manager. But it is not working and i have no idea how it will work. Because it is raising an error saying "The QuerySet value for an exact lookup must be limited to one result using slicing."
Here is my model.py
class manager(models.Model):
name = models.CharField(max_length= 500)
designation = models.CharField(max_length= 500)
user = models.ForeignKey(User,on_delete=models.CASCADE)
class Meta:
permissions = [
("edit_task", "can edit the task"),
]
here is my views.py file for the teams of manager
#login_required (login_url= 'have the url where it will go')
#permission_required('have the permission that is assigned by me')
def supervisor(request):
return render(request, 'manager/index-3.html')
def supervisor_team(request):
print(request.user.email)
email=request.user.email
obj= Create_Team.objects.filter(status='Accept',
managers=manager.objects.filter(user__email=email))
return render(request, "manager/accept_team.html", {"object": obj})
here is my template
<div class="body table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>S No.</th>
<th>COMPANY NAME</th>
<th>TEAM MEMBER</th>
<th>EMAIL</th>
</tr>
</thead>
<tbody>
{%for object in team%}
<tr>
<form id="form_id" method="POST" action = "#">
{% csrf_token %}
<th scope="row"> {{ forloop.counter }}</th>
<td>{{object.company_name}}</td>
<td>{{object.team_member}}</td>
<td>{{object.email}}</td>
<td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
I have no idea where i am wrong.
I think this is the problem:
obj= Create_Team.objects.filter(status='Accept',
managers=manager.objects.filter(user__email=email))
if you want to filter by one manager you have to use get instead of filter:
obj= Create_Team.objects.filter(status='Accept',
managers=manager.objects.get(user__email=email))
But if you want to filter by several managers you need to use __in:
obj= Create_Team.objects.filter(status='Accept',
managers__in=manager.objects.filter(user__email=email))
Also you are passing {"object": obj}) to template but in templare you are trying to iterate over team. So change it to pass team variable:
return render(request, "manager/accept_team.html", {"team": obj})

Django : Access model data in template using Class-based generic views

I'm trying to display the model data in the template.
When I don't have any filtering, it works fine!
class UserLogList(ListView):
context_object_name = 'data'
queryset = UserLog.objects.all().values('user_id__username','event_id','time')
But if I want to have some filtering, example if I want to get the details based on the user_id where user_id = 1. I can get the user id from the request object or self.request object.
So to achieve this, I did the following in my views.py
class DisplayUserActivity(ListView):
template_name = 'user_activity.html'
uid = self.request.user.id
def get_object(self):
uid = self.request.user.id
object = super(DisplayUserActivity,self).get_object()
object.data = UserLog.objects.filter(user_id = uid).values('user_id__username','event_id','time')
return object
and my template file:
{% block content %}
<h2> Logs </h2>
<table border="1" style="width:50%">
<tr>
<th> User Name </th>
<th> Description </th>
<th> Time </th>
</tr>
{% for user in data %}
<tr>
<td> {{user.user_id__username}}</td>
<td> {{user.event_id}}</td>
<td> {{user.time}} </td>
{% endfor %}
</tr>
</table>
{% endblock %}
What am I missing?
I think you need a method called get_queryset instead of get_object when extending the generic ListView.
EDIT:
Regarding your edit, theres an issue with your template
{% for user in data %}
should be
{% for user in object_list %}
But I suspect there are deeper problems here which are hard to decipher. My advice is to look through your code and the Django documentation more carefully, and possibly switch to a custom written view until you are more comfortable. :)

Creating Form element ids in the form template in Django

Im new to Django and I am trying to create a form that contains a table of drop downs. This is for generating a script based on user selections in these drop downs when submit is clicked.
The problem is the following form template is creating duplicate form element ids
How do I create unique ids in the form template even though the drop downs are going to be repeated.
The following is the code of the drop down.
<html>
<table border="1">
<form action="/PrintTestScript/" method="post">
{% csrf_token %}
<tr>
<th>Action</th>
<th>Endpoint</th>
<th>Status</th>
<th>Box Type</th>
</tr>
{% for i in 0123456789|make_list %}
<tr>
<td>
{{form.action}}
</td>
<td>
{{form.series}}
</td>
<td>
{{form.epstatus}}
</td>
<td>
{{form.boxtype}}
</tr>
{% endfor %}
<tr>
<td>
<input type="submit" value="Submit" />
</td>
</tr>
</form>
</table>
</html>
The following is the form class definition.
class TestForm(ModelForm):
action = forms.ModelChoiceField(queryset=actions.objects.all(), empty_label="")
series = forms.ModelChoiceField(queryset=endpoints.objects.all(), empty_label="")
epstatus = forms.ModelChoiceField(queryset=status.objects.all(), empty_label="")
boxtype = forms.ModelChoiceField(queryset=boxtype.objects.all())
class Meta:
model = endpoints
exclude = ('end_point_alias', 'dial_num', 'ip_address')
This is where the view is getting created
def getvals(request):
form = TestForm()
return render_to_response('main.html', {'form':form}, context_instance=RequestContext(request))
Thanks for your help.
You need to put the <form> tag within the for loop, so that you are actually creating 10 different forms instead of 10 copies of the same form elements. But you still have the problem that you would need 10 separate submit buttons. If you're actually looking for a list of forms, check out the Django FormSet documentation.