Django admindoc not rendering reStructuredText - python

Im using django admindocs for documentation and the basic functionality works nicely (I can access the doc pages, models are listed an documented, help_text is included, etc.).
Unfortunately, reStructuredText markup in docstrings is completely ignored, e.g.
Hyperlinks are not converted to hyperlinks
Bullet Lists are no bullet lists
Django markups such as :model:appname.ModelName are not resolved
I'm using the Development Trunk Version of Django (1.7)
Here is an example of a docstring I'm using:
class Adresse(models.Model):
u"""Postanschrift
Wird für
- Organisationen
- Personen
genutzt.
Siehe auch https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/#generic-relations
"""
object_id = models.PositiveIntegerField()
content_type = models.ForeignKey(ContentType)
of = generic.GenericForeignKey('content_type', 'object_id' )
...
When I paste the above docstring content into a rest editor (I used http://rst.ninjs.org/), everything works as expected.
The conversion works for docstrings documenting methods, e.g.
def my_method(self):
"""Docstring Heading
1. Listitem 1
2. Listitem 2
refers to :model:`personen.Person`
"""
pass
ist correctly converted.
I'm sure, I missed something very obvious, didn't I?

Then the admindocs module's behavior is the same as in Django 1.4.
To auto-generate navigatable docs from your python files, Python Sphinx https://www.sphinx-doc.org may be a better way, by putting the generates files in another pseudostatic folder.
To do that copy the sphinx docs to a template folder and add a custom urls(..) and view that provides access to the files with restrictions set to staff only (for instance via the canonical decorators login_required and user_pases_test.
Other solutions:
Unfortunately the documentation regarding the rst-usage is somewhat lacking, such as the settings.py parameter RESTRUCTUREDTEXT_FILTER_SETTINGS.
Reassure yourself that in order to activate these filters, django.contrib.markup' is added to your INSTALLED_APPS setting in your settings.py and {% load markup %} in the template.
You should have docutils installed. You will not receive errors if it is not installed.
When using linux with bash, enter:
if [[ -z `pip freeze | grep docutils` ]]; then sudo easy_install docutils;fi;
Directly rendering the reStructuredText:
from django import template
class Adresse(models.Model):
doc = u"""Postanschrift
Wird für
- Organisationen
- Personen
"""
t = template.Template('{% load markup %}{{ contentstr|restructuredtext }}')
c = template.Context({'contentstr': doc})
__doc__ = t.render(c)
You could do this automated by looping through all [relevant] models and their __docs__ attribute to subsequently render the string as reStructuredText as follows:
from django.conf import settings
from django.db.models import get_app, get_models
from django import template
for appname in settings.INSTALLED_APPS:
app = get_app(appname )
for model in get_models(app):
if hasattr(model, '__doc__') and model.__doc__ != "":
t = template.Template('{% load markup %}{{ contentstr|restructuredtext }}')
c = template.Context({'contentstr': model.__doc__})
model.__doc__ = t.render(c)

Related

Django 3 models.Q - app_lable gets displayed inside html

since I upgraded to Django 3.x I have a strage behaviour.
Imaging the following field at your models.py
content_type = models.ForeignKey(ContentType, limit_choices_to=filter_choice, on_delete=models.CASCADE, null=True, blank=True)
which refers to:
filter_choice = models.Q(app_label='App', model='model_x') | models.Q(app_label='App', model='model_y')
If I now display the content_type field on my html templates it look like this: "App| Model Y" which looks quite stupid, same goes for Django admin. Is this a Bug? I'm asking because on Django 2.2.7 (Latest version of 2.x) I dont had this behaviour and only model_x and model_y have been displayed as expected.
Would be awesome if only model_x and model_y getting displayd without there app lables. Is there any solution for this, maybe a new option that comes with django 3.x?
Thanks in advance :)
If I now display the content_type field on my html templates it look like this: "App| Model Y" which looks quite stupid.
This is how the __str__ of a ContentType is implemented. Indeed, if we take a look at the source code [GitHub], we see:
class ContentType(models.Model):
# …
def __str__(self):
return self.app_labeled_name
# …
#property
def app_labeled_name(self):
model = self.model_class()
if not model:
return self.model
return '%s | %s' % (model._meta.app_label, model._meta.verbose_name)
If you want to render the model name however, you can for example use:
{{ object.content_type.model_class._meta.verbose_name }}
It makes sense to include the app label, since the same model name can be used in different apps, hence it is possible that your project has two Model Ys, in two different apps.
Furthermore it is not very common to render a ContentType in the template. Normally this is part of the technical details of your project, that you likely do not want to expose. If you need to show the type of the object in a GenericForeignKey, you can simply follow the GenericForeignKey, and render the ._meta.verbose_name of that object.

What's the best way to disable Jinja2 template caching in bottle.py?

I'm using Jinja2 templates with Bottle.py and Google App Engine's dev_appserver for development. I want the templates to automatically reload on every request (or ideally only when they change), so that I don't have to keep restarting the server.
According to bottle's docs, you're supposed to be able to disable template caching by calling bottle.debug(True).
Jinja still seems to be caching its templates, though. I believe this to be because of the way the bottle jinja2 adapter is written (it just uses a default Jinja2 loader and doesn't expose many configuration options).
Following the Jinja2 Docs, I wrote this custom Loader that I would expect to trigger a template reload every time, but it doesn't seem to work either:
import settings
from bottle import jinja2_template
from bottle import Jinja2Template, template as base_template
class AutoreloadJinja2Template(Jinja2Template):
def loader(self, name):
def uptodate():
# Always reload the template if we're in DEVMODE (a boolean flag)
return not settings.DEVMODE
fname = self.search(name, self.lookup)
if fname:
with open(fname, "rb") as f:
source = f.read().decode(self.encoding)
return (source, fname, uptodate)
template = functools.partial(base_template,
template_adapter=AutoreloadJinja2Template,
template_lookup = settings.TEMPLATE_PATHS,
template_settings={
'auto_reload': settings.DEVMODE
}
)
Templates are still getting cached until I restart dev_appserver. This must be a fairly common problem. Does anyone have a solution that works?
UPDATE:
I ended up doing something like:
class CustomJinja2Template(Jinja2Template):
if settings.DEVMODE:
def prepare(self, *args, **kwargs):
kwargs.update({'cache_size':0})
return Jinja2Template.prepare(self, *args, **kwargs)
template = functools.partial(original_template, template_adapter=CustomJinja2Template)
This causes the templates to always reload, but only if a python module has been touched. i.e. if you just edit a template file, the changes won't take affect until you edit one of the python files that imports it. It seems as if the templates are still being cached somewhere.
I resolved this issue by ditching bottle's template solutions completely and using pure jinja2. It seems that Jijnja's FileSystemLoader is the only one, which can watch for file changes.
I defined new template function as follows (it looks for files in views/, just like bottle used to):
from jinja2 import Environment, FileSystemLoader
if local_settings.DEBUG:
jinja2_env = Environment(loader=FileSystemLoader('views/'), cache_size=0)
else:
jinja2_env = Environment(loader=FileSystemLoader('views/'))
def template(name, ctx):
t = jinja2_env.get_template(name)
return t.render(**ctx)
Then I use it like this:
#route('/hello')
def hello():
return template('index.tpl', {'text': "hello"})
The difference from bottle's API is that you have to include .tpl in file name and you have to pass context variables as dictionary.
Bottle caches templates internally (independent from Jinja2 caching). You can disable the cache via bottle.debug(True) or bottle.run(..., debug=True) or clear the cache with bottle.TEMPLATES.clear().
The Environment object in jinja2 has a configuration value for the cache size and, according to the documentation,
If the cache size is set to 0 templates are recompiled all the time
Have you tried something like this?
from jinja2 import Environment
env = Environment(cache_size=0)
Using bottle view decorator, you can just do #view('your_view', cache_size=0).
Bottle has a reloader=True parameter in server adapter, but I guess it works only with SimpleTemplate. I will try to extend this behaviour to other template engines.
If you want to do it in all your views, maybe you can do something like this:
import functools
view = functools.partials(view, cache_size=0)
This way, you can do it only when you are in debug mode adding an if statement to this code if bottle.DEBUG.

Adding a custom Jinja2 filter in GAE 1.6.0

I'd like to add filter to format my time and the best would be filters like django's timesince that automatically outputs the language of the i18n selected language, but first to make a quick solution I'd like to format my date. The suggested solution from the manual is:
def datetimeformat(value, format='%H:%M / %d-%m-%Y'):
return value.strftime(format)
jinja_environment.filters['datetimeformat'] = datetimeformat
But adding this code to my file doesn't make the filter available in the template:
{{ ad.modified|datetimeformat }}
TemplateAssertionError: no filter named 'datetimeformat'
If I add the code to the Jinja2 library's filters.py then it works. But I shouldn't need to add to Jinja2 files manually, it should work just adding the Jinja2 to my app.yaml and put my filter in my code instead of in the Jinja2 code. Where should I put the filter code?
Thank you
Update
My code looks like this and it seems the filter is not picked up:
from django.utils import translation
from django.utils.translation import gettext, ngettext, ugettext, ungettext, get_language, activate
from jinja2 import Environment, FileSystemLoader
class DjangoTranslator(object):
def __init__(self):
self.gettext = gettext
self.ngettext = ngettext
self.ugettext = ugettext
self.ungettext = ungettext
class DjangoEnvironment(jinja2.Environment):
def get_translator(self, context):
return DjangoTranslator()
jinja_environment = DjangoEnvironment(
loader=jinja2.FileSystemLoader(os.path.dirname(__file__)), extensions=['jinja2.ext.i18n'])
jinja_environment.install_gettext_translations(translation)
def datetimeformat(value, format='%H:%M / %d-%m-%Y'):
return value.strftime(format)
jinja_environment.filters['datetimeformat'] = datetimeformat
Following your example and Jinja2 docs I've added custom filter and it works.
Make sure that you use proper jinja2.Environment instance for getting template and rendering:
env = jinja2.Environment(
loader=jinja2.FileSystemLoader(template_path))
env.filters['default_if_none'] = default_if_none # a function
tmpl = env.get_template(filename)
tmpl.render(**context)
Because I was using a cached jinja2 environment as recommended here,
Kee's answer didn't work for me, but this one did.
Specifically, adding the filter when calling webapp2.WSGIApplication
myconfig = {}
myconfig['webapp2_extras.jinja2'] = {'template_path': ['templates','blog_posts'],
'filters': {'blog_filter': blog_filter}}
app = webapp2.WSGIApplication(_routes,
debug=True,
config = myconfig)

Django: persistent database-backed settings

I want to have some database stored settings for my Django app - just some key-value pairs. Does Django have a conventional way of doing this / something built in for it, or should I implement it myself?
class Setting(models.Model):
key = models.TextField()
value = models.TextField()
Of course, I'd want to be able to store any data type for keys and values. Perhaps I could use pickle to coerce them all into strings.
I've just been playing with the django-satchmo e-store application. Satchmo uses satchmo-livesettings or just livesettings to achieve this goal. In addition to that it is possible to change the settings using the admin interface.
The only problem is that I didn't find a tutorial on how to use livesettings. But if you browse the satchmo code, you'll see how it works.
Here is my example
from livesettings import config_register, StringValue, PositiveIntegerValue
SHOP_GROUP = ConfigurationGroup('SHOP', ('ShirtSale Shop Settings'), ordering=0)
CHARGE_PORTO = config_register(
BooleanValue(SHOP_GROUP,
'CHARGE_PORTO',
description = ('Porto Erheben?'),
help_text = ("Wird bei Bestellungen zusaetzlich ein Porto erhoben?"),
default = True))
I've included those lines in the config.py file. To execute this file it was necessary to:
import config
in the admin.py file (I'm wondering whether this is necessary)
In order to access the settings I've included the following to the urls.py file:
(r'^settings/', include('livesettings.urls')),

Cheetah with Cherrypy: how to load base templates, and do so automatically on change during development

I am working on a cherrypy+cheetah app and would like to improve the development experience.
I have everything working when I manually compile templates beforehand. (Update: This is how things work for production: precompile, don't ship *.tmpl and load templates as regular python modules.) However, during development I'd rather just load the templates every time they are referenced so that I don't need to kill and restart my application. I have a couple of issues I am facing:
If I have templates inheriting from base templates, I get import errors (can't find base templates). I think I had this actually working during my experiments, but unfortunately didn't save it and now I can't make it work.
Suppose I get 1. working, how do make it so that edits even in base templates get picked up without restart.
Below is my sample application that should demonstrate the problems. The directory structure is as follows:
t.py
templates/
base.tmpl
index.tmpl
t.py:
import sys
import cherrypy
from Cheetah.Template import Template
class T:
def __init__(self, foo):
self.foo = foo
#cherrypy.expose
def index(self):
return Template(file='templates/index.tmpl',
searchList=[{'foo': self.foo}]).respond()
cherrypy.quickstart(T(sys.argv[1]))
base.tmpl:
#def body
This is the body from the base
#end def
This is the base doc
index.tmpl:
#from templates.base import base
#extends base
#def body
$base.body(self)
This is the extended body
#end def
This is from index
Run it like this:
python t.py Something
Try this:
Replace base.tmpl with:
#from Cheetah.Template import Template
#def body
#set $base = Template(file="templates/base.tmpl")
$base.body()
<br/>
This is the extended body
#end def
$body()
<br/>
This is from index
Looks like this question was kind of answered in another SO question. By using the cheetah_import function, I can write my methods like this:
#cherrypy.expose
def index(self):
templates = cheetah_import('templates.index')
t = getattr(getattr(templates, 'index'), 'index')(searchList=[{'foo': self.foo}])
return t.respond()
I will also need to add an __init__.py into the templates directory. This approach also requires that Cherrypy's engine.autoreload_on setting is set to True.
To make production more efficient, I can make cheetah_import = __import__ and not replace the default __builtin__.import.

Categories