Database contents not showing up after render - python

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.

Related

context must be a dict rather than module

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.

Django create instance from views.py not working

I have a Django app that is basically a list app for tracking jobs that the user is applying for. Users have applications and applications have questions that the user wants to ask to the interviewers should they get an interview. So I have created a many to many relationship between the models 'Application' and 'Question' called 'Ask'. Models.py:
class Application(models.Model):
status_choices = (
('NS','Not Started'),
('IP','In Progress'),
('OH','On Hold'),
('CO','Complete'),
)
app_status = models.CharField(max_length=2,choices=status_choices)
position = models.CharField(max_length=255)
company = models.ForeignKey(Company)
applied_date = models.DateField(null=True)
isDeleted = models.BooleanField(default=False, blank=True)
user = models.ForeignKey(User)
def __str__(self):
return self.position
class Questions(models.Model):
question = models.CharField(max_length=255)
category = models.CharField(max_length=25)
isDeleted = models.BooleanField(default=False, blank=True)
class Ask(models.Model): #joining table
question = models.ForeignKey(Questions)
app = models.ForeignKey(Application)
isDeleted = models.BooleanField(default=False, blank=True)
So the idea is that the user creates a list of questions and then when they get an interview, they prepare for it by looking at their list of questions and assigning them to the application through a template. Questions.html:
{% extends 'base.html' %}
{% block body %}
<h1> Questions </h1>
<div class="table-responsive" align="center">
<table class="table-hover" width="75%">
<tr>
<th> Category </th>
<th> Question </th>
<th> Create Question</th>
<form method="POST">
{% csrf_token %}
<input type="text" name="app" value="{{ request.META.HTTP_REFERER }}">
<th><input type='submit' value='Add Selected'></th>
</tr>
{% for item in query %}
<tr>
<td> {{ item.category }} </td>
<td> {{ item.question }} </td>
<td> <input type="checkbox" name="selected_q" value="{{ item.id }}"></td>
<td> Delete </td>
<td> Edit </td>
</tr>
</form>
{% endfor %}
</table>
</div>
{% endblock %}
Which is called from views.py:
class QuestionView(TemplateView):
template_name = 'question.html'
def get(self, request):
query = Questions.objects.all().order_by('category')
args = {'query': query}
return render(request, self.template_name, args)
def post(self, request):
id_list = request.POST.getlist('selected_q')
return_url = request.POST.get('app')
app = int(return_url.rsplit('/')[-1])
myApp = Application.objects.get(pk=app)
if id_list != None:
for item in id_list:
myQuestion = Questions.objects.get(pk=int(item))
Ask.objects.create(app=myApp,question=myQuestion)
return HttpResponseRedirect(return_url)
else:
query = Questions.objects.all().order_by('category')
args = {'query': query}
return render(request, self.template_name, args)
The user can only get to the questions page by going through the Application view and when that happens Questions.html captures the link that the user came from. Users then select one or more questions through a checkbox on questions.html which is captured in the post as id_list - So this should give me the two keys I need to create an instance of Ask.
However, when trying to do this it looks like everything works properly, but no instance of Ask is created and I don't get any error messages. I have tried creating a record from the python shell and it works just fine. I have also tried other methods such as using a form and instantiating Ask to call .save() afterwards, but it does not insert a record. For testing, I took out the query in views.py to check to make sure valid values are getting passed to myApp and myQuestion, so I believe that the data is all there and accurate, but it isn't creating a record for some reason.
I appreciate any help you might offer, or maybe just different ideas on how to debug this problem so I can get some error messages.
Blurb was right - wrapping the table in the form tag resolved the issue. Thanks!

How to paginate a filtered queryset in listview

i am trying to add a search bar on my listview page. it will get all the post items first time, and if a query put in search box, and submitted, it will return a filtered queryset. it renders fine, but only has problem with pagination. for non-filtered queryset, the next page will get the next two posts without any problem, but for filtered queryset, i can see the queryset is correctly reflected by see less pages, but the next page gets me the second page of non-filtered queryset not the filtered queryset. Can anyone give me some pointers on what i am doing wrong here. Thanks
My template looks like this:
{% block content %}
.....
<form action="" method="get">
<input type="text" name='q'>
<input type="submit" value="Search">
</form>
{% for post in object_list %}
....
{% endfor %}
{% if is_paginated %}
<div class="pagination">
<span class="page-links">
{% if page_obj.has_previous %}
<<
{% endif %}
<span class="page-current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}
</span>
{% if page_obj.has_next %}
>>
{% endif %}
</span>
</div>
{% endif %}
I have a listview like below.
class Postlist(ListView):
model=post
paginate_by = 2
query_string = ''
def get_queryset(self):
if ('q' in self.request.GET) and self.request.GET['q'].strip():
query_string = self.request.GET['q']
entry_query = get_query(query_string, ['title', 'body',]) ## call get_query() function
queryset = post.objects.filter(entry_query).order_by('-created')
else:
queryset=post.objects.all().order_by('-created')
return queryset
def get_context_data(self):
context = super(ListView, self).get_context_data(**kwargs)
context['q'] = query_string
## do sth here to pre-populate the input text box
return context
Let me close this. Two options: using hidden field to save the user search terms, and get this to filter off queryset on each request; or using session. Here is the session code sample. The only drawback i could think of using session cache is it caches a whole queryset in memory, so it will kill the memory for high traffic website. Since i am using it for personal website, it doesnt hurt at all.
View file
class Postlist(ListView):
model=post
paginate_by = 2
def get_queryset(self):
query_string = ''
if ('search' in self.request.GET) and self.request.GET['search'].strip():
query_string = self.request.GET['search']
entry_query = get_query(query_string, ['title', 'body',]) ## call get_query to clean search terms
queryset = post.objects.filter(entry_query).order_by('-created')
self.request.session['searchset']=queryset
else:
if self.request.session.get('searchset') and ('page' in self.request.GET):
queryset=self.request.session['searchset']
else:
queryset=post.objects.all().order_by('-created')
if self.request.session.get('searchset'):
del self.request.session['searchset']
return queryset
form file
from django import forms
class SearchForm(forms.Form):
search = forms.CharField(max_length=30)

WTForms display foreignkey fields' name in dropdown

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)

django ModelForm save issue with ManyToManyField

I'm new to Django and was needing some help on a view error i am getting.
I wrote a view that will display a data table of "Groups" if the request method is GET, or display a form to edit a particular "Group" if the request method is POST (item to edit is passed with POST data).
Also, if POST on an existing item, i'd like the form to be pre-populated with the data i already have in the table for that item. I've pretty much got it all down, except when i goto save an edited form, i keep getting this error:
"Cannot set values on a ManyToManyField which specifies an intermediary model"
Any help would be greatly appreciated. Also, I'm new to all this web dev stuff, so if i'm doing something completely silly or am missing a concept, please feel free to flame me accordingly. ;-)
Model
class Alias(models.Model):
def __unicode__(self):
return unicode(self.alias)
alias = models.CharField(max_length=32)
class Octet(models.Model):
def __unicode__(self):
return unicode(self.num)
num = models.IntegerField(max_length=3)
class Group(models.Model):
def __unicode__(self):
return unicode(self.name)
name = models.CharField(max_length=32) #name of the group
id = models.AutoField(primary_key=True) #primary key
octets = models.ManyToManyField(Octet, through='OctetAssignment', blank=True) #not required
aliases = models.ManyToManyField(Alias, through='AliasAssignment', blank=True) #not required
class OctetAssignment(models.Model):
octet = models.ForeignKey(Octet) #octet
group = models.ForeignKey(Group) #group that octet is assigned to
class AliasAssignment(models.Model):
alias = models.ForeignKey(Alias)
group = models.ForeignKey(Group)
View
def index(request):
if request.method == 'GET':
groups = Group.objects.all().order_by('name')
return render_to_response('groups.html',
{ 'groups': groups, },
context_instance = RequestContext(request),
)
elif request.method == "POST":
g = Group.objects.get(id=request.POST['id'])
form = GroupEditForm(instance=g)
return render_to_response('groups.html',
{ 'form': form, },
context_instance = RequestContext(request),
)
def save(request):
if request.method == "POST":
form = GroupEditForm(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect('/tradedesk/groups/') # Redirect after POST
To make it complete, here is the form template code i'm using that renders the table and edit page.
Template
<h1>Group Information</h1>
{% if groups %}
<table border=1>
{% for group in groups %}
<tr>
<td>{{group.name}}</td>
<td>{% for octet in group.octets.all %} {{octet}} {% endfor %}</td>
<td>{% for alias in group.aliases.all %} {{alias}} {% endfor %}</td>
<td>{{group.analyst}}</td>
</tr>
{% endfor %}
</table>
<br></br>
<form method="post" action="/groups/">{% csrf_token %}
<select name="id" >
{% for group in groups %}
<option value="{{group.id}}">{{group.name}}</option>
{% endfor %}
</select>
<input type="submit" value="Edit">
</form>
{% endif %}
{% if form %}
<form method="post" action="/groups/save/">{% csrf_token %}
{{form}}
<br></br>
<input type="submit" value="Save">
<form>
{% endif %}
</div>
Try to remove the intermediary models OctetAssignment and AliasAssignment. They should be used only when you want to add custom fields to them. Otherwise Django creates them and uses them transparently by itself.

Categories

Resources