I have Python 3.2 set up with Apache via mod_wsgi. I have CherryPy 3.2 serving a simple "Hello World" web page. I'd like to start templating using Jinja2 as I build out the site. I'm new to Python and therefore don't know much about Python, CherryPy, or Jinja.
Using the code below, I can load the site root (/) and the products page (/products) with their basic text. That at least lets me know I've got Python, mod_wsgi, and CherryPy set up somewhat properly.
Because the site will have many pages, I'd like to implement the Jinja template in a way that prevents me from having to declare and render the template in each page handler class. As far as I can tell, the best way to do that is by wrapping the PageHandler, similar to these examples:
http://docs.cherrypy.org/dev/concepts/dispatching.html#replacing-page-handlers
http://docs.cherrypy.org/stable/refman/_cptools.html#cherrypy._cptools.HandlerWrapperTool
I've implemented the code in the second example, but it doesn't change anything.
[more details after code]
wsgi_handler.py - A mash-up of a few tutorials and examples
import sys, os
abspath = os.path.dirname(__file__)
sys.path.append(abspath)
sys.path.append(abspath + '/libs')
sys.path.append(abspath + '/app')
sys.stdout = sys.stderr
import atexit
import threading
import cherrypy
from cherrypy._cptools import HandlerWrapperTool
from libs.jinja2 import Environment, PackageLoader
# Import from custom module
from core import Page, Products
cherrypy.config.update({'environment': 'embedded'})
env = Environment(loader=PackageLoader('app', 'templates'))
# This should wrap the PageHandler
def interpolator(next_handler, *args, **kwargs):
template = env.get_template('base.html')
response_dict = next_handler(*args, **kwargs)
return template.render(**response_dict)
# Put the wrapper in place(?)
cherrypy.tools.jinja = HandlerWrapperTool(interpolator)
# Configure site routing
root = Page()
root.products = Products()
# Load the application
application = cherrypy.Application(root, '', abspath + '/app/config')
/app/config
[/]
request.dispatch: cherrypy.dispatch.MethodDispatcher()
core module classes
class Page:
exposed = True
def GET(self):
return "got Page"
def POST(self, name, password):
return "created"
class Products:
exposed = True
def GET(self):
return "got Products"
def POST(self, name, password):
return "created"
Based on what I read on a Google Group I figured I might need to "turn on" the Jinja tool, so I updated my config to this:
/app/config
[/]
tools.jinja.on = True
request.dispatch: cherrypy.dispatch.MethodDispatcher()
After updating the config, the site root and products pages display an CherryPy generated error page "500 Internal Server Error". No detailed error messages are found in the logs (at least not in the logs I'm aware of).
Unless it came pre-installed, I know I probably need the Jinja Tool that's out there, but I don't know where to put it or how to enable it. How do I do that?
Am I going about this the right way, or is there some better way?
Edit (21-May-2012):
Here is the Jinja2 template I'm working with:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
I figured it out.
In the interpolator function, the next_handler function call the original PageHandler (Page.GET or Products.GET in this case). Those original PageHandlers return strings while the interpolator function is treating the response like a python dict (dictionary), hence the double asterisk when it's passed to template.render as **response_dict.
The Jinja template has a placeholder for title, so it needs a title to be defined. Passing a plain string to the render function doesn't define what title should be. We need to pass an actual dict to the render function (or nothing at all, but what good is that?).
Note: For either of these fixes, the jinja tool does need to be enabled, as shown in the question by setting tools.jinja.on to True in the config.
Quick Fix
Define the title as the render function is called. To do this I need to change this line:
return template.render(**response_dict) # passing the string as dict - bad
to this:
return template.render(title=response_dict) # pass as string and assign to title
Like this, the template renders with my PageHandler text as the page title.
Better Fix
Because the template will grow to be more complex, one render function probably won't always be able to correctly assign the necessary placeholders. It's probably a good idea to let the original page handler return an actual dict with the template's many placeholders assigned.
Leave the interpolator function as it was:
def interpolator(next_handler, *args, **kwargs):
template = env.get_template('base.html')
response_dict = next_handler(*args, **kwargs)
return template.render(**response_dict)
Update Page and Products to return actual dicts that define the value's for the template's placeholders:
class Page:
exposed = True
def GET(self):
dict = {'title' : "got Page"}
return dict
def POST(self, name, password):
# This should be updated too
# I just haven't used it yet
return "created"
class Products:
exposed = True
def GET(self):
dict = {'title' : "got Products"}
return dict
def POST(self, name, password):
# This should be updated too
# I just haven't used it yet
return "created"
Like this, the template renders with my PageHandler title text as the page title.
There's also an updated Jinja2 tool found on a repository of various recipes the community has contributed to.
Related
I have three view-functions in views.py in django project that using a same three arguments in them:
paginator = Paginator(post_list, settings.POSTS_LIMIT)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
How can I put em in a single function (make an utility) to use one string of code in my view-functions, instead of repeat using three?
Thats my first question here, thank you :)
As you note, you can create a single function to handle this, taking the info it needs as arguments. You can include this as a helper function in your views.py or separate it out into a utils.py and then import it. Assuming the latter, for tidiness and future-proofing
utils.py
from django.core.paginator import Paginator
from django.conf.settings import POSTS_LIMITS #you may have another place for your settings
from .utils import make_pagination #utils.py file in same directory
def make_pagination(request, thing_to_paginate, num_per_page=POSTS_LIMITS)
paginator = Paginator(thing_to_paginate, num_per_page)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return page_obj
views.py
from .utils import make_pagination
def records(request):
...
#we'll use the provided settings-based default for num_per_page
page_obj = make_pagination(request, post_list)
return render(request, 'template.html', {'page_obj': page_obj})
If you wanted more than just the page_obj for some reason, you can return more than the one value, eg,
utils.py
...
return page_obj, paginator
views py
...
page_obj, paginator = make_pagination(request, post_list)
I've gotten the page number in the function itself, but you can also do that either in the view itself, or even in the function call in the view eg,
make_pagination(request.GET.get('page') or 1, post_list)
(If you go this path, don't forget to change the function to accommodate the different argument)
from django.contrib import admin
from .models import Shop
#admin.register(Shop)
class ShopAdmin(admin.ModelAdmin):
#admin.display(description='Name')
def upper_case_name(self,obj):
return("%s" % (obj.name)).upper()
Using the answer from Jermaine, you can create your own decorator and monkey patch it to the admin module. This would allow you to use the #admin.display(description="...") decorator.
# Monkey patch admin to include the display decorator (available in future Django versions)
if not hasattr(admin, "display"):
def display(description):
def decorator(fn):
fn.short_description = description
return fn
return decorator
setattr(admin, "display", display)
Complete example:
from django.contrib import admin
from .models import Shop
# Monkey patch admin to include the display decorator (available in future Django versions)
if not hasattr(admin, "display"):
def display(description):
def decorator(fn):
fn.short_description = description
return fn
return decorator
setattr(admin, "display", display)
#admin.register(Shop)
class ShopAdmin(admin.ModelAdmin):
#admin.display(description='Name')
def upper_case_name(self,obj):
return("%s" % (obj.name)).upper()
This is not a super clean approach, but if you would like to use the decorator you can do it this way.
In my case you should activate virtualenv , by typing "pipenv shell" command
I think it helps you too
In my case, for some reason, django was downgraded. I ran "pipenv update django" and it worked.
You can still achieve the same goal without using the display decorator.
list_display = ('upper_case_name',)
def upper_case_name(self, obj):
return "%s" % (obj.name.upper())
upper_case_name.short_description = "Name"
Django==3.1
I was fighting with this for a while, I didn't understand why the #admin.action() decorator didn't appear, I started to read the Django code and I found that when the actions for the Django Admin start to load, it calls a method called _get_base_actions, and this same method gets the action and description in this way:
# django.contrib.admin.ModelAdmin._get_base_actions
...
description = getattr(func, 'short_description', name.replace('_', ' '))
...
I had already tried several ways to load the action and to correctly take the description of the action, if it was not defined, what Django did was to take the name of the same function and replace the underscores with spaces, resulting in a somewhat frightening result.
The first thing I thought of as a quick and valid solution was to create a class and modify the __new__ method, which is called before the __init__ method.
This is an example of what I needed, to be able to generate a PDF from Django actions:
class GeneratePDF:
short_description = "WRITE THE DESCRIPTION OF ACTION HERE"
def __new__(cls, modeladmin, request, queryset):
result = cls.generate_pdf_resume(modeladmin, request, queryset)
return result
#classmethod
def generate_pdf_resume(cls, modeladmin, request, queryset):
...
Finally, I added it to the list of ModelAdmin actions.
from project.own_actions import GeneratePDF
#admin.register(Patient)
class PatientAdmin(admin.ModelAdmin):
...
actions = [GeneratePDF]
Then it appeared with the description that I had placed in the class as a class attribute.
I could also reuse this class to create a URL and successfully generate the PDF.
# project/urls.py
from project.own_actions import GeneratePDF
urlpatterns = [
path('admin/', admin.site.urls),
...
path('export/', GeneratePDF, name="export-pdf")
]
I am in the middle of learning scrappy right now and am building a simple scraper of a real estate site. With this code I am trying to scrape all of the URLs for the real estate listing of a specific city. I have run into the following error with my code - "Cannot mix str and non-str arguments".
I believe I have isolated my problem to following part of my code
props = response.xpath('//div[#class = "address ellipsis"]/a/#href').extract()
If I use the extract_first() function instead of the extract function in the props xpath assignment, the code kind of works. It grabs the first link for the property on each page. However, this ultimately is not what I want. I believe I have the xpath call correct as the code runs if I use the extract_first() method.
Can someone explain what I am doing wrong here? I have listed my full code below
import scrapy
from scrapy.http import Request
class AdvancedSpider(scrapy.Spider):
name = 'advanced'
allowed_domains = ['www.realtor.com']
start_urls = ['http://www.realtor.com/realestateandhomes-search/Houston_TX/']
def parse(self, response):
props = response.xpath('//div[#class = "address ellipsis"]/a/#href').extract()
for prop in props:
absolute_url = response.urljoin(props)
yield Request(absolute_url, callback=self.parse_props)
next_page_url = response.xpath('//a[#class = "next"]/#href').extract_first()
absolute_next_page_url = response.urljoin(next_page_url)
yield scrapy.Request(absolute_next_page_url)
def parse_props(self, response):
pass
Please let me know if I can clarify anything.
You are passing props list of strings to response.urljoin() but meant prop instead:
for prop in props:
absolute_url = response.urljoin(prop)
Alecxe's is right, it was a simple oversight in the spelling of iterator in your loop. You can use the following notation:
for prop in response.xpath('//div[#class = "address ellipsis"]/a/#href').extract():
yield scrapy.Request(response.urljoin(prop), callback=self.parse_props)
It's cleaner and you're not instantiating the "absolute_url" per loop. On a larger scale, would help you save some memory.
Hi I'm going through a Werkzeug tutorial and I'm a little confused about the statement: app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
'/static': os.path.join(os.path.dirname(__file__), 'static')
})
Contained inside:
class Shortly(object):
def __init__(self, config):
self.redis = redis.Redis(config['redis_host'], config['redis_port'])
def dispatch_request(self, request):
return Response('Hello World!')
def wsgi_app(self, environ, start_response):
request = Request(environ)
response = self.dispatch_request(request)
return response(environ, start_response)
def __call__(self, environ, start_response):
return self.wsgi_app(environ, start_response)
def create_app(redis_host='localhost', redis_port=6379, with_static=True):
app = Shortly({
'redis_host': redis_host,
'redis_port': redis_port
})
if with_static:
app.wsgi_app = SharedDataMiddleware(app.wsgi_app, {
'/static': os.path.join(os.path.dirname(__file__), 'static')
})
return app
What's going on there? Why is app.wsgi_app being assigned to whatever SharedDataMiddleware is returning? I mean, isn't app.wsgi_app just a method name?
Any insight will be appreciated :) Thanks!
TL;DR In this example an extra functionality is added to the Shortly app by wrapping its entry point with a SharedDataMiddleware object.
Long explanation
app.wsgi_app is not a method name. It's rather a reference to the method. And since Python is pretty dynamic language, one can replace any object's methods after this object was created.
Let's consider a simple example:
class App:
def run(self, param):
print(param)
app = App()
app.run('foo') # prints 'foo'
original_run = app.run # save a reference to the original run method
def run_ex(param):
print('run_ex') # add our extra functionality
original_run(param) # call the original one
app.run = run_ex
app.run('foo') # prints 'run_ex' and then 'foo'
So, in such way one can easy replace app's method run with a regular function.
Now, let's go back to Werkzeug. As you know from the WSGI specification, an application must be a callable with a specific signature. And Shortly's wsgi_app method is the desired callable. However, somebody wants to add an extra functionality to the Shortly app via SharedDataMiddleware middleware. If you look closer to it, you'll see, that it's a regular class with a __call__ method. Hence, all objects of SharedDataMiddleware class can be called.
middleware = SharedDataMiddleware(...) # create an object
middleware(...) # call the object. It can be slightly confusing at a first glance
So, for now you can see that any objects of SharedDataMiddleware is a WSGI applications by itself. And since you already know how to replace app's main method wsgi_app, the only one thing you have to do - is to store a reference to the original method Shortly.wsgi_app to be able to call it later. It's done by passing it to the SharedDataMiddleware constructor.
I've started using pyramid recently and I have some best-practice/general-concept questions about it's hybrid application approach. Let me try to mock a small but complex scenario for what I'm trying to do...
scenario
Say I'm building a website about movies, a place where users can go to add movies, like them and do other stuff with them. Here's a desired functionality:
/ renders templates/root.html
/movies renders templates/default.html, shows a list of movies
/movies/123456 shows details about a movie
/movies/123456/users shows list of users that edited this movie
/users renders templates/default.html, shows a list of users
/users/654321 shows details about a user
/users/654321/movies shows a list of favorite movies for this user
/reviews/movies renders templates/reviews.html, shows url_fetched movie reviews
/admin place where you can log in and change stuff
/admin/movies renders templates/admin.html, shows a list of editable movies
/admin/movies/123456 renders templates/form.html, edit this movie
extras:
ability to handle nested resources, for example movies/123/similar/234/similar/345, where similar is a property of movie class that lists ids of related movies. Or maybe more clear example would be: companies/123/partners/234/clients/345...
/movies/123456.json details about a movie in JSON format
/movies/123456.xml details about a movie in XML format
RESTFull methods (GET, PUT, DELETE..) with authorization headers for resource handling
approach
This is what I've done so far (my views are class based, for simplicity, I'll list just decorators...):
# resources.py
class Root(object):
__name__ = __parent__ = None
def __getitem__(self, name):
return None
def factory(request):
# pseudo code...
# checks for database model that's also a resource
if ModelResource:
return ModelResource()
return Root()
# main.py
def notfound(request):
return HTTPNotFound()
def wsgi_app():
config = Configurator()
config.add_translation_dirs('locale',)
config.add_renderer('.html', Jinja2Renderer)
# Static
config.add_static_view('static', 'static')
# Root
config.add_route('root', '/')
# Admin
config.add_route('admin', '/admin/*traverse', factory='factory')
config.add_route('default', '/{path}/*traverse', factory='factory')
config.add_notfound_view(notfound, append_slash=True)
config.scan('views')
return config.make_wsgi_app()
# views/root.py
#view_config(route_name='root', renderer="root.html")
def __call__():
# views/default.py
#view_defaults(route_name='default')
class DefaultView(BaseView):
#view_config(context=ModelResource, renderer="default.html")
def with_context():
#view_config()
def __call__():
# views/admin.py
#view_defaults(route_name='admin')
class AdminView(BaseView):
#view_config(context=ModelResource, renderer="admin.html")
def default(self):
#view_config(renderer="admin.html")
def __call__(self):
And following piece of code is from my real app. ModelResource is used as context for view lookup, and this is basically the reason for this post... Since all my models (I'm working with Google App Engine datastore) have same basic functionality they extend specific superclass. My first instinct was to add traversal functionality at this level, that's why I created ModelResource (additional explanation in code comments), but I'm begining to regret it :) So I'm looking for some insight and ideas how to handle this.
class ModelResource(ndb.Model):
def __getitem__(self, name):
module = next(module for module in application.modules if module.get('class') == self.__class__.__name__)
# this can be read as: if name == 'movies' or name == 'users' or .....
if name in module.get('nodes'):
# with this setup I can set application.modules[0]['nodes'] = [u'movies', u'films', u'фильми' ]
# and use any of the defined alternatives to find a resource
# return an empty instance of the resource which can be queried in view
return self
# my models use unique numerical IDs
elif re.match(r'\d+', name):
# return instance with supplied ID
cls = self.__class__
return cls.get_by_id(name)
# this is an attempt to solve nesting issue
# if this model has repeated property it should return the class
# of the child item(s)
# for now I'm just displaying the property's value...
elif hasattr(self, name):
# TODO: ndb.KeyProperty, ndb.StructuredProperty
return getattr(self, name)
# this is an option to find resource by slug instead of ID...
elif re.match(r'\w+', name):
cls = self.__class__
instance = cls.query(cls.slug == name).get()
if instance:
return instance
raise KeyError
questions
I have basically two big questions (widh some sub-questions):
How should I handle traversal in described scenario?
Should I extend some class, or implement an interface, or something else?
Should traversal be handled at model level (movie model, or it's superclass would have __getitem__ method)? Should resource be a model instance?
What's the best practice for __getitem__ that returns collection (list) of resources? In this scenario /movies/
My ModelResource in the code above is not location aware... I'm having trouble getting __public__ and __name__ to work, probably because this is the wrong way to do traversal :) I'm guessing once I find the right way, nested resources shouldn't be a problem.
How can I switch back from traversal to url dispatching?
For the extra stuff: How can I set a different renderer to handle JSON requests? Before I added traversal I configured config.add_route('json', '/{path:.*}.json') and it worked with appropriate view, but now this route is never matched...
Same problem as above - I added a view that handles HTTP methods #view_config(request_method='GET'), but it's never matched in this configuration.
Sorry for the long post, but it's fairly complex scenario. I should probably mention that real app has 10-15 models atm, so I'm looking for solution that would handle everything in one place - I want to avoid manually setting up Resource Tree...