django pass response context none - python

In my browser, everything is fine. Until I make a test
here is my polls/views.py
from django.shortcuts import render
from polls.models import Poll
def index(request):
latest_poll_list = Poll.objects.all().order_by('-pub_date')
context = {'latest_poll_list':latest_poll_list}
return render(request,'polls/index.html',context)
polls/templates/polls/index.html
{% if latest_poll_list %}
<ul>
{% for poll in latest_poll_list %}
<li>{{poll.question}}</li>
{% endfor %}
</ul>
{% else %}
<p>No Poll Available</p>
{% endif %}
and my polls/tests.py
from django.test import TestCase
from django.core.urlresolvers import reverse
class SimpleTest(TestCase):
def test_this(self):
response = self.client.get(reverse('polls.views.index'))
print response.context
print response.content
as you can see, my response.context['latest_poll_list'] is always []
So I wonder where is my fault?

If in the browser you get your objects this means that your view is ok, if your test does not return any object maybe you have to create them (tests make use of an empty database automatically created from the scratch by Django). I usually create sample objects in setUp() method:
class SimpleTest(TestCase):
def setUp(self):
self.poll = Poll.objects.create()

Related

Template include tag: Choose another template if it does not exist

I would like to include a different template depending request. For example:
Suppose that request has:
request.country = 'Spain'
request.city = 'Madrid'
I want to include "index.html" view but:
---- If myapp/index_madrid.html exist
{% include "myapp/index_madrid.html" %}
---- elif myapp/index_spain.html exist
{% include "myapp/index_spain.html" %}
---- else go to default version
{% include "myapp/index.html" %}
How can I achieve this behaviour in a transparent way? I mean, I would like to do something like:
{% my_tag_include "myapp/index.html" %}
{% my_tag_include "myapp/another_view.html" with p='xxx' only%}
{% my_tag_include "myapp/any_view.html" with p='sss' a='juan' %}
and achieve the cascading loading that I explained before.
Thanks
One possibility is to implement this kind of logic in the view:
# views.py
from django.template.loader import select_template
class MyView(View):
def get(self, request):
include_template = select_template([
'myapp/index_{}.html'.format(request.city),
'myapp/index_{}.html'.format(request.country),
'myapp/index.html'
])
ctx = {
'include_template': include_template
}
return render(request, 'myapp/base.html', ctx)
# myapp/base.html
{% include include_template %}
select_template() will return the first template in the passed list that exists. The include tag supports including compiled templates beginning from Django 1.7, so this should work fine if you are on 1.7 or above.
Update: Reuse across multiple views
# utils.py
from django.template.loader import select_template
def get_approriate_template(tokens, app_name):
templates = ['{}/index_{}.html'.format(app_name, x) for x in tokens]
templates.append('{}/index.html'.format(app_name))
return select_template(templates)
# views.py
from .utils import get_approriate_template
class MyView(View):
def get(self, request):
tokens = [request.city, request.country]
ctx = {
'include_template': get_appropriate_template(tokens, app_name='myapp')
}
return render(request, 'myapp/base.html', ctx)
Update: Rendering template from a template tag
# templatetags/myapp_extras.py
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def my_tag_include(context):
from django.template.loader import select_template
include_template = select_template([
'myapp/index_{}.html'.format(context['request'].city),
'myapp/index_{}.html'.format(context['request'].country),
'myapp/index.html'
])
return include_template.render(context)
# myapp/base.html
{% load myapp_extras %}
{% my_tag_include %}
you can implement a custom template tag to check the existence of the template:
from django import template
register = template.Library()
def template_exists(template_name):
try:
django.template.loader.get_template(template_name)
return True
except template.TemplateDoesNotExist:
return False
register.filter('template_exists', template_exists)
And in your template :
{% if template_exists "myapp/index_"add:request.city|add:".html" %}
{% include "myapp/index_"add:request.city|add:".html" %}
{% elif template_exists "myapp/index_"add:request.country|add:".html" %}
{% include "myapp/index_"add:request.country|add:".html" %}
{% else %}
{% include "myapp/index.html" %}
Edit :
You can do all your logic through the template tag:
from django import template
register = template.Library()
#register.simple_tag(takes_context=True)
def existing_template(context):
request = context["request"]
if django.template.loader.get_template("myapp/index_"+ request.city+".html"):
return "myapp/index_"+ request.city+".html"
elif django.template.loader.get_template("myapp/index_"+ request.country+".html"):
return "myapp/index_"+ request.country+".html"
else:
return "myapp/index.html"
And in your template :
{% include required_template %}
You can do this by writing your own template tag which returns the valid template which exists.
Method-1 Using assignment_tag:
some_app/templatetags/some_app_extras.py
from django import template
from django.template.loader import select_template
register = template.Library()
#register.assignment_tag(takes_context=True)
def get_valid_template(context):
city_template = 'myapp/index_{}.html'.format(context['request'].city)
country_template = 'myapp/index_{}.html'.format(context['request'].country)
index_template = 'myapp/index.html'
templates_list = [city_template, country_template, index_template]
valid_template = select_template(templates_list)
return valid_template.name
In your template:
{% load some_app_extras %}
{% get_valid_template as valid_template %}
{% include valid_template %}
We use assignment tag for it and pass the context to it by passing takes_context=True argument when registering the tag. Since we have the context, we can access the request to get the city and country. After this, we use the select_template() function of django and pass it a list of templates which will return the first template found in the list.
Then in our template, we can use this template tag to get the valid template and use this variable to render the valid template.
Method-2 Using simple_tag:
If you want to do the rendering in 1 line only as you mentioned in the comments, then you can use simple_tag. You don't need to assign the template name in a variable then for the rendering to be done by include built-in template tag later. get_template_tag will automatically display the necessary template since it has been already been rendered in the template tag code.
some_app/templatetags/some_app_extras.py
from django import template
from django.template.loader import select_template
register = template.Library()
#register.simple_tag(takes_context=True)
def get_valid_template(context):
city_template = 'myapp/index_{}.html'.format(context['request'].city)
country_template = 'myapp/index_{}.html'.format(context['request'].country)
index_template = 'myapp/index.html'
templates_list = [city_template, country_template, index_template]
valid_template = select_template(templates_list)
return valid_template.render(context)
In your template:
{% load some_app_extras %}
{% get_valid_template %}
Finally I solved the problem by creating a custom simple tag, such as:
#register.simple_tag(takes_context=True)
def my_own_include(context, *args):
#I get the request and create a list of possible template views
return select_template(list_of_posible_views).render(context)
On the .html file I would call this tag like:
{% my_own_include 'index.html' %}
Thanks to all of you for your help.

Unit test on custom django admin template

No clue how to deal with this situation.
Recently start unit test with django.
In my project, i have a custom change_list.html to add a button on the admin page.
I'm looking for a unit test which can verify this custom button.
Here is my code in admin.py :
class LocationAdmin(OSMGeoAdmin):
def get_urls(self):
urls = patterns('', url(
r'^import/$',
self.admin_site.admin_view(self.import_process)
))
super_urls = super(LocationAdmin, self).get_urls()
return urls + super_urls
def import_process(self, request):
pass
admin.site.register(Location, LocationAdmin)
This code automaticaly load the template in app/admin/app/app/change_list.html
Which is :
{% extends "admin/change_list.html" %}
{% load staticfiles %}
{% block extrahead %}
<link rel="stylesheet" href="{% static "css/custom_upload.css" %}">
{% endblock %}
{% block object-tools-items %}
{{ block.super }}
<li><a role="button" href="import/" class="btn btn-primary btn-margin-left">Import</a></li>
{% endblock %}
But how about when you want to proove that work's with a unit test?
I'm able to test template when i can use a view and the function render_to_string
Like this :
response = my_view(HttpRequest())
expected_html = render_to_string(
'template.html',
{'arg_key': arg}
)
self.assertEqual(response.content.decode(), expected_html)
But here, i don't figure it out how to call the admin view with the associate template part.
Here a start of what i found to add unit test on admin page.
class MockRequest(object):
pass
class MockSuperUser(object):
def has_perm(self, perm):
return True
request = MockRequest()
request.user = MockSuperUser()
class ModelAdminTests(TestCase):
def setUp(self):
self.site = AdminSite()
def test_admin_import_button_on_location_admin_page(self):
ma = ModelAdmin(Location, self.site)
#Here the correct assert ?
Thank you all.
This might not be a good idea (probably a better alternative: using the test client). But for reference, here is how you can render the changelist_view programmatically directly from the admin method:
from django.contrib.admin import AdminSite, ModelAdmin
from django.test.client import RequestFactory
from django.contrib.admin.templatetags.admin_urls import admin_urlname
from django.shortcuts import resolve_url
class MockUser:
is_active = True
is_staff = True
def has_perm(self, *args):
return True
url = resolve_url(admin_urlname(MyModel._meta, "changelist"))
request = RequestFactory().get(url)
request.user = MockUser()
class MyAdmin(ModelAdmin):
change_list_template = "path/to/custom/template/if/needed"
admin = MyAdmin(Work, AdminSite())
html = admin.changelist_view(request).rendered_content

Django request.user in model self function

I want to get current logged user in my model self function.
I tried this.
class My_model(models.Model):
user = models.OneToOneField(User)
image = models.ImageField(upload_to='uploads/',default='uploads/no-img.jpg')
#other fields
def show_photo(self,request):
show_photo = False
if Photo_request.objects.filter(who=request.user,whose=self.user).exists():
my_request = Photo_request.objects.get(who=request.user,whose=self.user)
request_accepted = my_request.accepted
if request_accepted:
show_photo = True
return show_photo
show_photo = property(show_photo)
In my template
{% for profile in profiles %}
{% if profile.show_photo %}
<img src="{{MEDIA_URL}}{{ profile.image }}" alt="image" />
{% endif %}
{% endfor %}
but this function not working. I tried without request parameter and custom id, thats working. Is there any problem in my code?
Write the custom tag:
my_app/templatetags/my_app_tags.py
from django.template import Library
register = Library()
#register.assignment_tag(takes_context=True)
def show_photo(context):
request = context['request']
profile = context['profile']
return profile.show_photo(request) # Instead of passing request I suggest to pass request.user here
Use it in template by loading the template_tags:
{% load my_app_tags %}
{% for profile in profiles %}
{% show_photo as show %}
{% if show %}
<img src="{{MEDIA_URL}}{{ profile.image }}" alt="image" />
{% endif %}
{% endfor %}
I used current_thread function in threading package.
Add a new middleware in utils/request_utiles.py file as following:
utils/request_utiles.py
from threading import current_thread
from django.utils.deprecation import MiddlewareMixin
_requests = {}
def get_current_request():
t = current_thread()
if t not in _requests:
return None
return _requests[t]
class RequestMiddleware(MiddlewareMixin):
def process_request(self, request):
_requests[current_thread()] = request
Add the middleware in settings.py file
settings.py
MIDDLEWARE = [
...
'utils.request_utils.RequestMiddleware',
]
Use get_current_request() function in any models.
In your code, you can use as following:
from utils.request_utils import get_current_request
class My_model(models.Model):
user = models.OneToOneField(User)
image = models.ImageField(upload_to='uploads/',default='uploads/no-img.jpg')
...
def show_photo(self):
request = get_current_request() # you can get current request in here.
show_photo = False
if Photo_request.objects.filter(who=request.user,whose=self.user).exists():
my_request = Photo_request.objects.get(who=request.user, whose=self.user)
request_accepted = my_request.accepted
if request_accepted:
show_photo = True
return show_photo
show_photo = property(show_photo)

Django Template Page Outputting Nothing

Can someone help me figure out why my Django template pages won't render anything?
I'm using Python Requests (http://docs.python-requests.org/en/latest/) to retrieve JSON data from the external urls. I decode the data by using .json(). This works as I would expect when executing this from command line, but when it does nothing in the view.
When I run the server, the page is blank. It has no title, no 'testing' printed, nothing.
My Template:
<html>
<head><title>Offer List</title></head>
<body>
<p>Testing</p>
{% load dictparser %}
{% for offers in network1_offers %}
{% autoescape off %}
<div>
<p>name: {{ offers|lookup:"name" }}</p>
<p>pay: {{ offers|lookup:"payout" }}</p>
<p>description: {{ offers|lookup:"description" }}</p>
</div>
{% empty %}
<li>Sorry, no surveys available.</li>
{% endautoescape %}
{% endfor %}
</body>
</html>
My View:
class OffersList(View):
template_name="generic_app/offers.html"
def load_offers(request):
"""
import example network offers.
"""
user = request.user
user_agent = request.META['HTTP_USER_AGENT']
amparams = {'user_subid':user.sub_id, 'useragent':user_agent, 'user_ip':user.ip_address}
examplenetwork = requests.get('http://example.com/api-get.php?pubid=00000&key=000000000000&mode=offers&incent=1', data=amparams)
exampleoffers= examplenetwork.json()
"""
import example network 2 offers.
"""
clparams = {'subid':user.sub_id, 'ua':user_agent, 'geoip':user.ip_address}
examplenetwork2 = requests.get('http://www.examplenetwork2.com/blahblah', data=clparams)
exampleoffers2 = examplenetwork2.json()
render(request, 'generic_app/offers.html', {'network1_offers':exampleoffers, 'network2_offers':exampleoffers2})
The url:
url(r'^dashboard/offers$', OffersList.as_view(), name="offers"),
You're seeing this because you haven't defined how to get to the load_offers() method in your view, currently your load_offers() method is just a method floating around in your class.
Using the base class View comes with it's methods that you need to implement, for example
class OfferView(View):
template_name = "generic_app/offers.html"
def get(self, request, *args, **kwargs):
return load_offers(request)
or much better change this to a TemplateView(because that's what it really is).
class OfferView(TemplateView):
template_name = "generic_app/offers.html"
def get_context_data(self, **kwargs):
context = super(OfferView, self).get_context_data(**kwargs)
context['offers'] = load_offers(self.request)
return context

How to render placeholders from a django-cms custom templatetag?

I've made a simple template tag to list child pages in a django-cms site.
It's working fine except for the fact that I have not been able to render the child pages placeholders in the template tag itself.
The following is my code for the template tag.
subpages.py
from cms.models import Page
from cms.utils.page_resolver import get_page_from_path
from django import template
register = template.Library()
#register.inclusion_tag('subpages.html', takes_context = True)
def get_news_items( context ):
request = context['request']
subpages = request.current_page.children.filter(published=True)
return {'subpages':subpages}
subpages.html
{% load cms_tags menu_tags placeholder_tags %}
<ul>
{% for item in subpages %}
<li>{{ item.get_title }}
{% render_placeholder subtitle %}
</li>
{% endfor %}
</ul>
I've tried some alternatives to *render_placeholder* but without luck.
How would be the correct way to get the placeholder rendered?
This is only a (untested) suggestion, but try passing the context along to the template:
#register.inclusion_tag('subpages.html', takes_context = True)
def get_news_items( context ):
request = context['request']
subpages = request.current_page.children.filter(published=True)
context.update({'subpages':subpages})
return context

Categories