Inspired by this blog post, I am trying to make a views that handles profiles searches by saving the search parameters into session so that the query can be preserved through pagination.
Here is the views:
def profile_search(request):
args = {}
qs=[]
if not request.method == 'POST':
if 'search-profiles-post' in request.session:
request.POST = request.session['search-profiles-post']
request.method = 'POST'
if request.method == "POST":
form = AdvancedSearchForm(request.POST)
request.session['search-profiles-post'] = request.POST
if form.is_valid():
cd = form.cleaned_data
s_country=cd['country']
s_province=cd['province']
s_city = cd['city']
if s_city: qs.append( Q(city__in=s_city))
if s_country: qs.append(Q(country__icontains = s_country))
if s_province: qs.append( Q(province__icontains=s_province))
f = None
for q in qs:
if f is None:
f=q
else: f &=q
print f
if f is not None:
profiles = UserProfile.objects.filter(f).order_by('-created_at')
else:
form = AdvancedSearchForm()
profiles = UserProfile.objects.all().order_by('-created_at')
paginator = Paginator(profiles,12)
page= request.GET.get('page')
try:
results = paginator.page(page)
except PageNotAnInteger:
results = paginator.page(1)
except EmptyPage:
results = paginator.page(paginator.num_pages)
args.update(csrf(request))
args['form'] = form
args['results'] = results
return render_to_response('userprofile/advanced_search.html', args,
context_instance=RequestContext(request))
Here is the form:
<form action="/search/" method="post">{% csrf_token %}
<ul class="list-unstyled">
<li><h3>Country</h3></li>
<li>{{form.country}}</li><br>
<h4>Province</h4>
<li>{{form.province}}</li>
<h4>City</h4>
<li>{{form.city}}</li>
</ul>
<input type="submit" name="submit" value="search" />
</form>
Search Results:
{% for p in results %}
<div">
<div>
<br>
<strong><a href="/profile/{{p.username}}" >{{p.username}}</a></strong>
{{p.country}} <br>
{{p.province}} <br>
{{p.city}} <br>
</div>
</div>
{% endfor %}
<div>
<div class="pagination">
{% if results.has_previous %}
<< Prev  
{% endif %}
{% if results.has_next %}
Next >>
{% endif %}
</div>
</div>
</div>
and the urls.py
url(r'^search/', 'userprofile.views.profile_search'),
This is the mysterious error theat I get:
Traceback:
File "/home/supermario/.djenv/local/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
204. response = middleware_method(request, response)
File "/home/supermario/.djenv/local/lib/python2.7/site-packages/debug_toolbar/middleware.py" in process_response
89. new_response = panel.process_response(request, response)
File "/home/supermario/.djenv/local/lib/python2.7/site-packages/debug_toolbar/panels/request.py" in process_response
31. 'post': [(k, request.POST.getlist(k)) for k in sorted(request.POST)],
Exception Type: AttributeError at /search/
Exception Value: 'dict' object has no attribute 'getlist'
I got stock on this for a while so really appreciate your hints.
request.POST should be the dict-like QueryDict but not the simple python dict:
from django.http import QueryDict
request.POST = QueryDict('').copy()
request.POST.update(request.session['search-profiles-post'])
Related
I have a session variable for the name of a company saved in my django view from a user input form. When I try and use this in a later view, no matter what I try it pulls the {key: value} pair rather than just the value
Views:
def start(request):
if request.method == 'POST':
# create a form instance and populate it with data from the request:
form = QuizTakerForm(request.POST )
# check whether it's valid:
if form.is_valid():
# process the data in form.cleaned_data as required
post = form.save(commit=False)
post.user = request.user
post.save()
request.session['obj_id'] = post.id
request.session['company_name'] = form.cleaned_data
# redirect to a new URL:
return HttpResponseRedirect('industry/')
....
def Gov_q1(request):
company_name = request.session.get('company_name')
print(company_name)
question = Question.objects.get(pk=24)
context = {'question': question, 'company_name': company_name}
return render(request, 'ImpactCheck/detail.html', context)
html:
<h1> Hi my name is {{ company_name }} </h1>
<h1>{{ question.text }}</h1>
<form action="." method="post">
{% for answer in question.answer_set.all %}
<input type="radio" name="answer" id="answer" value="{{ answer.id }}">
<label for="answer">{{ answer.answer_text }}</label><br>
{% endfor %}
<input type="submit" value="Submit">
</form>
Ive also tried company_name=request.session['company_name'], but both then render as {'company_name': 'test_company'} rather than test_company.
FYI If anyone has a similar issue I've circumvented using
def Gov_q1(request):
id=request.session.get('obj_id')
company_name= QuizTakers.objects.get(pk=id)
question = Question.objects.get(pk=24)
context = {'question': question, 'company_name': company_name, 'cn': cn}
return render(request, 'ImpactCheck/detail.html', context)
I am tried but i am not getting the desired output for lazy loading
views.py
def post_detail(request, pk):
post = get_object_or_404(Post, pk=pk)
content_type = ContentType.objects.get_for_model(Post)
obj_id = post.id
comments = Comment.objects.filter(
content_type=content_type, object_id=obj_id)
parent_id = request.POST.get("parent_id")
csubmit = False
if parent_id:
content_type = ContentType.objects.get_for_model(Comment)
Comment.objects.create(content_type=content_type,
object_id=parent_id,
parent_id=parent_id,
user=request.user,
text=request.POST.get("text"))
if request.method == 'POST':
form = CommentForm(data=request.POST)
if form.is_valid():
new_comment = form.save(commit=False)
new_comment.content_type = content_type
new_comment.user = request.user
new_comment.save()
csubmit = True
else:
form = CommentForm()
paginator = Paginator(comments, 10)
try:
comments = paginator.page(page)
except PageNotAnInteger:
comments = paginator.page(1)
except EmptyPage:
comments = paginator.page(paginator.num_pages)
return render(request, 'post_detail.html', {'post': post,
'comments': comments, 'csubmit': csubmit, 'form': form})
I want to apply lazy loading in the above view and want to apply on template.Above i added pagination and rendered in template
post_details.html
{%for comment in comments %}
<br>
{{comment.text}}<br/>
by {{comment.user}}<br>
<a href='#' class="rep_cmt" data-parentid="
{{comment.id}}">Reply</a><br>
{% for comment in comment.children.all %}
{{comment}}
{% endfor %}
{%endfor%}
{% if comments.has_next %}
<a class="infinite-more-link" href="?page={{ comments.next_page_number
}}">More</a>
{% endif %}
<div class="loading" style="display: none;">
Loading...
</div>
<script>
var infinite = new Waypoint.Infinite({
element: $('.rep_cmt')[0],
onBeforePageLoad: function () {
$('.loading').show();
},
onAfterPageLoad: function ($items) {
$('.loading').hide();
}
});
</script>
In above i added script to render data in lazy loading process but it is not rendering
for some reason im unable to display the comments of a category_request and i have now idea why, is smb. maybe able to have an eye on that, praticaly i should work but i dont see the mistake here.
as far as i see I'm using category_request_comment from the view to get a releated comment objects from a category_request... any idea?
Template Snippet:
{% for category_request_comment in category_request_comments %}
<div class="comment">
<p>{{ category_request_comment.content|readmore:15 }}</p>
{% if category_request_comment.content.published_date %}
<div class="date">
<a>Comment by: {{ category_request_comment.author }}</a><br>
<a>Commented at: {{ category_request_comment.published_date }}</a>
</div>
{% endif %}
{% if request.user == category_request_comment.author %}
<a class="commentoption" href="{% url 'comment_edit' pk=category_request_comment.pk %}">Edit</a><a> | </a>
<a class="commentoption" href="{% url 'comment_delete' pk=category_request_comment.pk %}">Delete</a>
{% endif %}
</div>
{% endfor %}
views.py
def category_request_detail(request, pk):
category_request = get_object_or_404(CategoryRequests, pk=pk)
list_category_request = CategoryRequests.objects.get_queryset().filter(id=pk).order_by('-pk')
paginator = Paginator(list_category_request, 20)
page = request.GET.get('page')
category_request_comment = paginator.get_page(page)
return render(request, 'myproject/category_request_detail.html', {'category_request': category_request, 'category_request_comment': category_request_comment})
views.py (only for Reference)
def category_request_comment_new(request, pk):
if request.method == "POST":
form = CategoryRequestsCommentForm(request.POST)
if form.is_valid():
category_request = get_object_or_404(CategoryRequests, pk=pk)
requests_comment = form.save(commit=False)
requests_comment.author = request.user
requests_comment.published_date = timezone.now()
requests_comment.category_request = category_request
requests_comment.save()
return redirect('category_request_detail', pk=requests_comment.category_request.pk)
else:
form = CategoryRequestsCommentForm()
return render(request, 'myproject/comment_new.html', {'form': form})
urls.py
url(r'^categories/requests/$', myproject_views.category_request_list, name='category_request_list'),
Thanks in advance
Your template is looking for an object called category_request_comments, but you have not sent anything with that name to the template.
def category_request_detail(request, pk):
category_request = get_object_or_404(CategoryRequests, pk=pk)
list_comments = CategoryRequests_Comment.objects.get_queryset().filter(category_request_id=pk).order_by('-pk')
paginator = Paginator(list_comments, 10)
page = request.GET.get('page')
comments = paginator.get_page(page)
return render(request, 'myproject/category_request_detail.html', {'category_request': category_request, 'comments': comments})
I have a form field like this
class FeedForm(ModelForm):
files=form.FileField(validators=[validate_file_extension])
class Meta:
model=Feed
fields=('text','auth','files',)
with the validator used to allow specific file types:
validator.py
def validate_file_extension(value):
ext = os.path.splitext(value.name)[1] # [0] returns path+filename
valid_extensions = ['.pdf', '.doc', '.docx', '.jpg', '.png', '.xlsx', '.xls']
if not ext.lower() in valid_extensions:
raise ValidationError(u'Unsupported file extension.')
I want to raise the above Validation Error in my template,how can I go about it?
views.py that generate form:
def post_feed(request):
form_class = FeedForm
if request.method == 'POST':
form = form_class(request.POST,request.FILES)
if form.is_valid():
feed = form.save(commit=False)
feed.user = User.objects.get(pk=7)
feed.pub_date=timezone.now()
#instance = Feed(files=request.FILES['files'])
# feed.files=request.FILES['files']
feed.save()
return redirect('home')
else:
form = form_class()
concern='Concern'
feeds=Feed.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
paginator = Paginator(feeds,5) # Show 25 contacts per page
page = request.GET.get('page')
try:
feedz = paginator.page(page)
except PageNotAnInteger:
feedz = paginator.page(1)
except EmptyPage:
feedz = paginator.page(paginator.num_pages)
#return redirect('home')
return render_to_response('index.html', {"feeds":feeds,"feedz": feedz,'form':FeedForm(),'feed_detail':feed_detail,})
views that the form is on using an include tag:
def home(request):
concern='Concern'
feeds=Feed.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
paginator = Paginator(feeds,5) # Show 25 contacts per page
page = request.GET.get('page')
try:
feedz = paginator.page(page)
except PageNotAnInteger:
# If page is not an integer, deliver first page.
feedz = paginator.page(1)
except EmptyPage:
# If page is out of range (e.g. 9999), deliver last page of results.
feedz = paginator.page(paginator.num_pages)
return render_to_response('index.html', {"feeds":feeds,"feedz": feedz,'form':FeedForm(),'feed_detail':feed_detail,},context_instance=RequestContext(request))
html that generates the form:post_feed.html
<form role="form" action="{% url 'post_feed' %}" enctype="multipart/form-data" method="post">
{% csrf_token %}
<div class="mdl-textfield mdl-js-textfield ">
{{form.text}}
<label class="mdl-textfield__label" for="{{form.text.id_for_label}}">Cheated on?Blow the whistle here</label>
</div>
<div class="mdl-select mdl-js-select mdl-select--floating-label">
<label class="mdl-select__label" for="{{form.auth.id_for_label}}">Authority addressed to:<br/></label>
{{form.auth}}
</div><br/>
{{form.files}}
<br/> {{form.files2}}
<br/> {{form.files3}}
<br/><br/> <button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--raised mdl-button--colored">Post</button>
{% if form.errors %}
{% for field in form %}
{% for error in field.errors %}
<div class="alert alert-error">
<strong>{{error|escape}}</strong>
</div>
{% endfor %}
{% endfor %}
{% endif %}
</form>
The html that has the above form on using an include tag
{% include "post_feed.html" %}
<h2>Feed Stream</h2>
{% for feed in feedz %}
<strong> {{feed.full_name_of_poster|title}} </strong> |
{% if feed.resolved == True %}
RESOLVED
{% else %}
UNRESOLVED
{% endif %}
<p> To:{{feed.auth}} </p>
<p>{{feed.text}} </p>
Full details
<p id='count'> {{feed.total_concerns}} concern{{feed.total_concerns|pluralize:'s'}}   {{feed.no_of_comments}} comment{{feed.no_of_comments|pluralize:'s'}} </p>
<p> {{feed.pub_date|naturaltime|capfirst}} </p>
<hr/>
{% endfor %}
<div class="pagination">
<span class="step-links">
{% if feedz.has_previous %}
previous
{% endif %}
<span class="current">
Page {{ feedz.number }} of {{ feedz.paginator.num_pages }}.
</span>
{% if feedz.has_next %}
next
{% endif %}
</span>
</div>
{% endblock %}
I have gone through the docs but no breakthrough,Kindly help me out.Thanks in advance
The usual format for a function based view that handles a form is:
def post_feed(request):
form_class = FeedForm
if request.method == 'POST':
form = form_class(request.POST,request.FILES)
if form.is_valid():
# process the form then redirect
...
return redirect('home')
else:
# You don't actually need this else statement here
print form.errors
else:
# create blank form for GET requests
form = form_class()
# Now return a response for GET requests and invalid POST requests
concern='Concern'
feeds=Feed.objects.filter(pub_date__lte=timezone.now()).order_by('-pub_date')
return render(request , 'index.html' ,{'feeds':feeds,'form':FeedForm(),'feed_detail':feed_detail,})
So you just need to change the indentation at the end of the view, so that you return a response for invalid POST requests as well.
Django will automatically display any validation errors if you use {{ form }} in your template. If you render the fields individually, then see the docs for rendering fields manually for how to include errors manually.
I have a view that filters out results for a posted search form:
def profile_advanced_search(request):
args = {}
if request.method == "POST":
form = AdvancedSearchForm(request.POST)
qs=[]
if form.is_valid():
cd = form.cleaned_data
s_country=cd['country']
s_province=cd['province']
s_city = cd['city']
if s_country: qs.append(Q(country__icontains = s_country))
if s_province: qs.append( Q(province__icontains=s_province))
if s_city: qs.append( Q(city__icontains=s_city))
f = None
for q in qs:
if f is None:
f=q
else: f &=q
list = UserProfile.objects.filter(f).order_by('-created_at')
else:
form = AdvancedSearchForm()
list = UserProfile.objects.all().order_by('-created_at')
paginator = Paginator(list,10)
page= request.GET.get('page')
try:
results = paginator.page(page)
except PageNotAnInteger:
results = paginator.page(1)
except EmptyPage:
results = paginator.page(paginator.num_pages)
args.update(csrf(request))
args['form'] = form
args['results'] = results
return render_to_response('userprofile/advanced_search.html', args,
context_instance=RequestContext(request))
the urls.py part is:
url(r'^search/$', 'userprofile.views.profile_advanced_search'),
The template is:
<form action="/search/" method="post">{% csrf_token %}
<ul class="list-unstyled">
<li><h3>Country</h3></li>
<li>{{form.country}}</li><br>
<h4>Province</h4>
<li>{{form.province}}</li>
<h4>City</h4>
<li>{{form.city}}</li>
</ul>
<input type="submit" name="submit" value="search" />
</form>
Search Results:
{% for p in results %}
<div">
<div>
<br>
<strong><a href="/profile/{{p.username}}" >{{p.username}}</a></strong>
{{p.country}} <br>
{{p.province}} <br>
{{p.city}} <br>
</div>
</div>
{% endfor %}
<div>
<div class="pagination">
{% if results.has_previous %}
<< Prev  
{% endif %}
{% if results.has_next %}
Next >>
{% endif %}
</div>
</div>
</div>
These work fine for the first page, but to deal with the later pages, it is suggested that I need to implement Post/Redirect/Get .
However I have had difficulty to make such views/template/urls to deal with GET pages regarding that all of the search parameters are arbitrary. So I appreciate a complete solution.
Do you need 2 views. First one for form search and second one to show results. You have not implemented redirect in any way in your sample code!
urls
...
url(r'^search/$',
'userprofile.views.profile_advanced_search'),
url(r'^show/(?P<country>\w+)/(?P<province>\w+)/(?P<site>\w+)/(?P<page>\d+)',
'userprofile.views.profile_advanced_show'),
...
profile_advanced_search
def profile_advanced_search(request):
args = {}
if request.method == "POST":
form = AdvancedSearchForm(request.POST)
qs=[]
if form.is_valid():
cd = form.cleaned_data
s_country=cd['country']
s_province=cd['province']
s_city = cd['city']
return HttpResponseRedirect(
reverse('userprofile.views.profile_advanced_show',
args=(s_country, s_province, s_city, 0, )))
return HttpResponseRedirect(
reverse('userprofile.views.profile_advanced_show',
args=('+', '+', '+', 0, )))
profile_advanced_show
def profile_advanced_show(request, s_country='',
s_province='', s_city='', page=0):
f = some filters with s_country, s_province and s_city
list = UserProfile.objects.filter(f).order_by('-created_at')
paginator = Paginator(list,10)
try:
results = paginator.page(page)
except PageNotAnInteger:
results = paginator.page(1)
except EmptyPage:
results = paginator.page(paginator.num_pages)
args.update(csrf(request))
form = AdvancedSearchForm(initial={ 's_country': s_country, ... } )
args['form'] = form
args['results'] = results
return render_to_response('userprofile/advanced_search.html', args,
context_instance=RequestContext(request))
Notice: improve it for not valid form submissions. Remember you can send parameters to second view via GET as key value instead route values.