When I am filtering for my search bar I am getting this error. I am not sure what I am doing wrong here
Watching this tutorial: https://www.youtube.com/watch?v=llbtoQTt4qw&t=3399s
views.py
class pplList(LoginRequiredMixin,ListView):
model = People
context_object_name = 'people'
def get_context_data(self, **kwargs):
search_input = self.get.GET.get('search-area') or ''
if search_input:
context['people'] = context['people'].filter(name__icontains=search_input)
return context
people_list.html
{%if request.user.is_authenticated %}
<p>{{request.user}}</p>
Logout
{% else %}
Login
{% endif %}
<hr>
<h1>Interviewee Dashboard {{color}}</h1>
Add Candidates
<form method="get">
<input type = 'text' name = 'search-are'>
<input type = 'submit' value = 'Search'>
</form>
<table>
<tr>
<th> Item</th>
<th> </th>
</tr>
{% for people in people %}
<tr>
<td>{{people.name}}</td>
<td>View</td>
<td>Edit</td>
<td>Delete</td>
</tr>
{% empty %}
<h3>No items in list</h3>
{% endfor %}
</table>
There are some minor mistakes such as it should be self.request.GET.get('search-area'), also you haven't called the super() method, so try this view:
class pplList(LoginRequiredMixin,ListView):
model = People
context_object_name = 'people_list'
def get_context_data(self, **kwargs):
context=super().get_context_data(**kwargs)
search_input = self.request.GET.get('search-area', False)
if search_input:
context['people']= People.objects.filter(name__icontains=search_input)
return context
In the Html, the field name search-are and you are accessing in the view as self.request.GET.get('serach-area', False) kindly change its name to search-area` in the input tag of Html.
Also, class based views are generally written in PascalCase as they are classes of Python and requires their name to be written as model name as prefix and actual view name as suffix, so it should be PeopleListView.
Related
So, I try to display a list of items from database, but after calling return render(...) it behaves as if there were no objects in the database. I am new to django and after a second day of trial and error I have no idea what to do with it
Affected view:
class DropDownList(ListView):
context_object_name = 'drop_down'
template_name="browse.html"
model=ServiceList
asd = ''
def post(self, request):
name = request.POST.get('selected')
obj = ServiceList.objects.get(sourceFile=name)
print(obj)
print(request.POST) #some prints for debugging
context = {'asd': obj}
return render(request, self.template_name, context)
Models:
class ServiceList(models.Model):
version = models.IntegerField()
location = models.CharField(max_length=500)
services = models.ManyToManyField(Service)
drms = models.ManyToManyField(Drm)
sourceFile = models.CharField(max_length=500)
class Service(models.Model):
uid = models.CharField(max_length=255, unique=True)
locations = models.ManyToManyField(Location)
names = models.ManyToManyField(Name)
category = models.CharField(max_length=500)
drm = models.CharField(max_length=500)
description = models.CharField(max_length=500)
html fragment:
<p>
<br/>
<form action="/browse/" id="tableform" method="POST">{% csrf_token %}
<select class="form-select" aria-label="Default select example" form="tableform" name="selected">
<option selected>-----------------</option>
<option >One</option>
<option >Two</option>
<option >Three</option>
{% for obj in drop_down %}
<option name={{obj.sourceFile}}>{{obj.sourceFile}}</option>
{% endfor %}
</select>
</form>
<button id="add-list" type="submit" class="btn btn-success pull-left" class="button1" form="tableform">+</button>
</p>
<table class="table table-bordered table-dark">
<tr>
<th>UID</th>
<th>Category</th>
</tr>
{% for obj in drop_down %}
adasdasd
{% if obj.sourceFile == asd %}
<br/>fghfghfgh
{% for service in obj.services.all %}
<tr>
<td>{{service.uid}}</td>
<td>{{service.category}}</td>
</tr>
{% endfor %}
{% endif %}
{% endfor %}
</table>
There are a few things wrong in your code, I'm going to list them, so it is easier to understand.
1 - context_object_name = 'drop_down' is not being used, 'drop_down' is not being declared in your class.
2 - You don't need to assign 'asd' as an empty variable, since you are only using as a namespace for the obj variable in your context set.
3 - Your return function is wrong, you should only be returning the context there, since you are using a class based view.
4 - You are using a ListView to get only one object
I don't know if this is going to work(I don't have a lot of experience in class based views) but try to make your code look like this:
class DropDownList(DetailView):
template_name="browse.html"
model=ServiceList
def post(self):
name = request.POST.get('selected')
obj = ServiceList.objects.get(sourceFile=name)
context = {'asd': obj}
return context
you can delete the context_object_name line as I mentioned, so if you want to render your ServiceList object version field in and HTML page for example, you should use {{ asd.version }}
Also, try to look for function based views, they are better to use, im assuming that you are using this view to get an object from your database, if you were using a function based view here, your code would be much simpler, it would look like this
def get_object(request, object_id):
template = 'browse.html'
obj = ServiceList.objects.get(pk=object_id)
context = { 'youcandecideanamehere': obj }
return render(request, template, context)
but you would need to pass the object_id parameter in your url(I'm going to create some here, since you didn't give yours)
urlpatterns = [
...
path('get_object/<object_id>/', get_objects, name='get_objects')
...
]
And the a tag for that page, should be like this:
Text
Hope I've helped, but if you still have some problems, feel free to contact me.
I have the following models defined:
class Item(models.Model):
rfid_tag = models.CharField()
asset = models.OneToOneField('Assets', default=None, null=True,
on_delete=models.SET_DEFAULT,)
date = models.DateTimeField(name='timestamp',
auto_now_add=True,)
...
class Assets(models.Model):
id = models.AutoField(db_column='Id', primary_key=True)
assettag = models.CharField(db_column='AssetTag', unique=True, max_length=10)
assettype = models.CharField(db_column='AssetType', max_length=150)
...
class Meta:
managed = False
db_table = 'Assets'
ordering = ['assettag']
def __str__(self):
return f"{self.assettag}"
def __unicode__(self):
return f"{self.assettag}"
For which I have created the following form and formset:
class ItemDeleteForm(forms.ModelForm):
asset = forms.CharField(required=True,
help_text= "Item asset tag",
max_length=16,
label="AssetTag",
disabled=True,
)
delete = forms.BooleanField(required=False,
label="Delete",
help_text='Check this box to delete the corresponding item',
)
class Meta:
model = Item
fields = ['asset']
ItemDeleteMultiple = forms.modelformset_factory(model=Item,
form=ItemDeleteForm,
extra=0,
)
managed by the view:
class DeleteMultipleView(generic.FormView):
template_name = '*some html file*'
form_class = ItemDeleteMultiple
success_url = reverse_lazy('*app_name:url_name*')
def form_valid(self, form):
return super().form_valid(form)
And rendered in the template:
{% extends "pages/base.html" %}
{% block title %}
<title>Delete Multiple</title>
{% endblock %}
{% block content %}
<h1>Delete Multiple Items</h1>
<br>
<form class="ManualForm" action ="." method="POST"> {% csrf_token %}
{{ form.management_form }}
<table border="2">
<tr><th colspan="3" scope="row">Select Items to Delete</th></tr>
{% for item_form in form %}
<tr>
<td><label for="{{ item_form.asset.id_for_label }}">AssetTag {{forloop.counter}}:</label>
{% if item_form.non_field_errors %}
{{ item_form.non_field_errors }}
{% endif %}
{% if item_form.asset.errors %}
{{item_form.asset.errors}}
{% endif %}
</td>
<td>{{item_form.asset}}</td>
<td>{{item_form.delete}}
{% if item_form.delete.errors %}
{{item_form.delete.errors}}
{% endif %}
</td>
</tr>
{% endfor %}
</table>
<br>
<input class = "btn btn-success" type="submit" value="Delete Selected" />
Cancel
</form>
<form class="AutoForm" action ="." method="POST"> {% csrf_token %}
{{form.as_table}}
<input class = "btn btn-success" type="submit" value="Delete Selected" />
Cancel
</form>
{% endblock %}
When I submit AutoForm, everything is great. It takes me to app_name:url_name, but if I sumbit ManualForm I don't get redirected. It will simply clear all data and reload the form page with empty fields.
The HTTP POST response status code for AutoForm is 302, while for ManualForm is 200.
I don't understand how the template could influence the behavior of the url redirection. What am I doing wrong in the manual rendering of the formset?
It seems that adding:
{% for field in item_form.hidden_fields %}
{{field}}
{% endfor %}
under {% for item_form in form %} will solve the issue.
I didn't understand very well from the docs:
Looping over hidden and visible fields
If you’re manually laying out a form in a template, as opposed to
relying on Django’s default form layout, you might want to treat
< input type="hidden"> fields differently from non-hidden fields. For
example, because hidden fields don’t display anything, putting error
messages “next to” the field could cause confusion for your users – so
errors for those fields should be handled differently.
I just thought this is about errors, so I didn't care. But one of the first thing it says about forms is this:
As an example, the login form for the Django admin contains several
< input> elements: one of type="text" for the username, one of
type="password" for the password, and one of type="submit" for the
“Log in” button. It also contains some hidden text fields that the
user doesn’t see, which Django uses to determine what to do next.
It also tells the browser that the form data should be sent to the URL
specified in the < form>’s action attribute - /admin/ - and that it
should be sent using the HTTP mechanism specified by the method
attribute - post.
Maybe it will help someone else.
Right now I am using Class-based delete view, and my URL contains two arguments which are the primary keys of my 2 models: Post and Lesson. However, I am encountering an Attribute Error: Generic detail view LessonDeleteView must be called with either an object pk or a slug in the URLconf.
These are my two models Lesson and Post:
class Post(models.Model):
title = models.CharField(max_length=100)
image = models.ImageField(default = 'default0.jpg', upload_to='course_image/')
description = models.TextField()
price = models.DecimalField(decimal_places=2, max_digits=6)
date_posted = models.DateTimeField(default=timezone.now)
author = models.ForeignKey(User, on_delete=models.CASCADE)
rating = models.IntegerField(default = 0)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post-detail', kwargs={'pk' : self.pk})
class Lesson(models.Model):
title = models.CharField(max_length=100)
file = models.FileField(upload_to="lesson/pdf")
date_posted = models.DateTimeField(default=timezone.now)
post = models.ForeignKey(Post, on_delete=models.CASCADE, null=False, blank=False)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('lesson_upload', kwargs={'pk': self.pk})
This is my URLs.py:
path('post/<int:post_id>/lesson_uploaded/<int:lesson_id>', LessonDeleteView.as_view(), name='lesson_delete'),
Right now this is how I am trying to insert the parameters in my html template:
{% block content %}
<div id="main">
<table class="table mb-0">
<thead>
<tr>
<th>Title</th>
<th>Author</th>
<th>Download</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{% for l in Lesson %}
<tr>
<td>
{% if l.file %}
{{ l.title }}
{% else %}
<h6>Not available</h6>
{% endif %}
</td>
<td>{{ l.post.author }}</td>
<td>{% if l.file %}
Download
{% else %}
<h6>Not available</h6>
{% endif %}
</td>
<td> <a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'lesson_delete' post.id l.id %}">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
{% endblock %}
This is my class-based view:
class LessonDeleteView(DeleteView):
model = Lesson
success_url = '../'
template_name = 'lesson_confirm_delete.html'
As you are deleting Lesson, you don't need to provide Post ID. You can simply use Lesson ID here. So try like this:
# url
path('post/lesson_uploaded/<int:pk>/', LessonDeleteView.as_view(), name='lesson_delete'), # using pk instead of lession_id, it will resolve the error you are facing
# template
<td> <a class="btn btn-danger btn-sm mt-1 mb-1" href="{% url 'lesson_delete' l.id %}">Delete</a>
</td>
Update
from comment section, you can override the delete method like this:
class LessonDeleteView(DeleteView):
model = Lesson
success_url = '../'
template_name = 'lesson_confirm_delete.html'
def delete(self, request, *args, **kwargs):
self.object = self.get_object()
self.object.file.delete() # <-- added file delete code
success_url = self.get_success_url()
self.object.delete()
return HttpResponseRedirect(success_url)
Why are you passing the lesson id.
Since Post gets deleted by default lesson would get deleted as well. Check this video to better understand how to pass the id and details on Delete View.
DeleteView(Class Based Views)
Im trying to display some objects from django. When I use the administrator my objects are created but when I try to display it is impossible.
I tryed to make a render but when I initialize the screen never is called, then i tryed to make it with a GET button, now the function is called but when arrives to alumnos = Alumno.objects.all() throws
'function' object has no attribute 'objects'.
models.py
class Alumno(models.Model):
dni = models.CharField(max_length=9,primary_key=True)
nombre = models.CharField(max_length=100)
apellido1 = models.CharField('Primer apellido',max_length=50)
apellido2 = models.CharField('Segundo apellido',max_length=50)
email = models.EmailField("Correo electronico",null=True)
repetidor = models.BooleanField()
curs = models.ManyToManyField(Curso, blank=True, related_name="Historico_de_cursos")
Nivel = models.ManyToManyField('Nivel', through = 'Completado',through_fields=('Alumno','Nivel'))
Practica = models.ManyToManyField('Practica', through = 'Nota',through_fields=('Alumno','Practica'))
Curso = models.ManyToManyField('Curso',through = 'Curso_alumno',through_fields=('Alumno','Curso'))
objects = models.Manager()
def __str__(self):
return self.dni
class Meta:
db_table = "Alumno"
verbose_name = 'Alumno'
verbose_name_plural = 'Alumnos'
unique_together = ("nombre", "apellido1", "apellido2")
view.py
def mostrar_alumnos(request):
alumnos = Alumno.objects.all()
return render(request, 'mostrar_alumnos.html', {'alumnos': alumnos}
mostrar_alumnos.html
{% if alumnos %}
<ul>
{% for alumno in alumnos %}
<td>{{ alumno.dni }}</td>
<td>{{ alumno.nombre }}</td>
<td>{{ alumno.apellido1 }}</td>
<td>
<a class="btn btn-secondary" href="{% url 'actualizar_alumno' alumno.dni %}"> Editar</a>
<a class="btn btn-danger" href="{% url 'eliminar_alumno' alumno.dni %}"> Esborrar</a> </td>
{% endfor %}
</ul>
{% else %}
<p>No hay alumnos disponibles.</p>
{% endif %}
url.py
url(r'^mostrar_alumnos/$', TemplateView.as_view(template_name='mostrar_alumnos.html'),name='mostrar_alumnos'),
url(r'^mostrar_alumnos/$', views.mostrar_alumnos,name='mostrar_alumnos'),
url(r'^mostrar_alumnos2/$', views.mostrar_alumnos2,name='mostrar_alumnos2')
Based on the error message, and your comment, you have constructed a view function with the name Alumno, as in:
# app/views.py
from app.models import Alumno
def Alumno(request):
# ...
pass
def mostrar_alumnos(request):
alumnos = Alumno.objects.all()
return render(request, 'mostrar_alumnos.html', {'Alumno': alumnos})
This means that if you write Alumno.objects, you are referring to the Alumno function, even if you imported the model, since you simply have set the Alumno identifier to that function when you defined it.
The simplest way to solve this is to rename your Alumno view to alumno, which is, according to PEP-8 the recommended way to name your function. In that case Alumno will thus refer to your imported model.
# app/views.py
from app.models import Alumno
def alumno(request):
# ...
pass
def mostrar_alumnos(request):
alumnos = Alumno.objects.all()
return render(request, 'mostrar_alumnos.html', {'alumnos': alumnos})
The name of the template variable probably should be 'alumnos' instead of Alumno, in your template you can then render this with:
{% if alumnos %}
<ul>
{% for alumno in alumnos %}
<td>{{ Alumno.dni }}</td>
<td>{{ Alumno.nombre }}</td>
<td>{{ Alumno.apellido1 }}</td>
<td>
<a class="btn btn-secondary" href="{% url 'actualizar_alumno' alumno.dni %}"> Editar</a>
<a class="btn btn-danger" href="{% url 'eliminar_alumno' alumno.dni %}"> Esborrar</a> </td>
{% endfor %}
</ul>
{% endif %}
Note that you do not have to define an objects = models.Manager() in your models. If you do not specify another manager, Django will automatically add a manager named objects to it.
I am using appengine webapp2 as wsgihandler, jinja2 as the template engine and wtforms as the form module for its support to app engine models.
Following is my simple model:
class TaskCategory(db.Model):
title = db.StringProperty()
description = db.TextProperty()
class TaskList(db.Model):
title = db.StringProperty()
description = db.TextProperty()
category = db.ReferenceProperty(TaskCategory)
start_date = db.DateProperty()
target_finish_date = db.DateProperty()
Inside my handlers i write stuff as follows:
from wtforms.ext.appengine.db import model_form
model_dict = {'category': TaskCategory,
'task': TaskList}
class CreateForm(webapp2.RequestHandler):
def get(self, slug):
form = model_form(model_dict[slug]) # slug can either be category or task.
self.render_template('index.html', {'form': form()})
Following is my template:
<form method="POST" action"">
<table>
{% for field in form %}
<tr>{{ field.label }}</tr>
<tr>{{ field()|safe }}</tr>
<tr>
{% if field.errors %}
<td>
<ul class=errors>
{% for error in field.errors %}
<li>{{ error }}</li>
{% endfor %}
</ul>
</td>
{% endif %}
{% endfor %}
</table>
<input type="submit" class="btn" value="Submit Form"/>
</form>
Everything renders perfectly in the template, except the dropdown for the foreign key the values listed over there are something like:
<tr><label for="category">Category</label></tr>
<tr><select id="category" name="category"><option selected value="__None"></option><option value="ahhkZXZ-bmV3LXByb2plY3QtdGVtcGxhdGVyEgsSDFRhc2tDYXRlZ29yeRgCDA"><models.TaskCategory object at 0xb22d74c></option>
<option value="ahhkZXZ-bmV3LXByb2plY3QtdGVtcGxhdGVyEgsSDFRhc2tDYXRlZ29yeRgDDA"><models.TaskCategory object at 0xb22dbec></option>
<option value="ahhkZXZ-bmV3LXByb2plY3QtdGVtcGxhdGVyFgsSDFRhc2tDYXRlZ29yeSIEdGVzdAw"><models.TaskCategory object at 0xb22d74c></option></select></tr>
As is visible the names are not being displayed for the category, instead the objects are displayed, how can i rectify it, in a generic manner?
Well this has got nothing to do with, WTForm or jinja or webapp2.
Change your database file to return the title in your case, instead of the object using repr as follows:
class TaskCategory(db.Model):
title = db.StringProperty()
description = db.TextProperty()
def __repr__(self):
return unicode(self.title)