NetAngels / django-webodt

django module to create MS Word, PDF and other types of documents from ODF and HTML templates
http://packages.python.org/django-webodt/
93 stars 52 forks source link

Can't display new lines in variable #10

Open jsykora opened 12 years ago

jsykora commented 12 years ago

First off, this may not be an issue, but more of a support question.

I have a model with a TextField and I am trying to use it in a .odt template converting to .pdf via Open Office.

The value of the field is u'Line one\r\nLine two'

I've tried just the plain variable as well as the following template tags: linebreaks, linebreaksbr, safe. But none of them seem to work to allow the carriage return or newline characters.

Am I missing the proper way to allow new lines?

imankulov commented 12 years ago

According to ODF specification, line breaks in ODF document must be represented with <text:line-break /> XML tag, so if you write a template filter converting u'Line one\r\nLine two' to u'Line one<text:line-break />Line two', it should work.

For more info, see "6.1.5 text:line-break" of the Specification (pdf), or simply perform a simple experiment as I did. I created a new document with a number of linebreaks and then took a look at the contents, as described here.

Please consider closing the ticket if it solves your problem. Otherwise, please let me know if something goes wrong.

jsykora commented 12 years ago

I figured it wasn't a bug but more of a feature that wasn't implemented.

It may be nice to have that filter included in the package. I assume wanting to put text with line breaks in documents would be fairly popular- blog posts, news articles, etc.

Here is a Gist of the code for a templatetag for xml line breaks. I borrowed/stole the code from Django's linebreaksbr filter and just switched it to the proper xml tag.

from django import template
from django.template.defaultfilters import stringfilter
from django.utils.safestring import mark_safe
from django.utils.text import normalize_newlines

register = template.Library()

@register.filter()
@stringfilter
def linebreaksodt(value, autoescape=None):
    """
    Converts all newlines in a piece of plain text to XML line breaks
    (``<text:line-break />``).
    """
    autoescape = autoescape and not isinstance(value, SafeData)
    value = normalize_newlines(value)
    if autoescape:
        value = escape(value)
    return mark_safe(value.replace('\n', '<text:line-break />'))
imankulov commented 12 years ago

Thank you. Indeed, it would be useful to include this filter in the webodt package. I re-open the issue as a reminder for myself.

jsykora commented 12 years ago

I don't know if this is any easier, or more practical, but maybe instead of the filter to convert \n to <text:line-break />, it'd be better to use the Django provided linebreaksbr tag and then convert all <br /> in a document to the xml line break.

Does that make sense? I guess the way I see it is that XML doesn't care about any <br />, so maybe if it's anywhere in a document, and already declared safe, it should be converted to the proper break without the programmer having to explicitly call a filter or load the custom template tags somewhere in the document.

imankulov commented 12 years ago

Regarding your last proposal. Frankly, It seems to me as too unobvious and incomplete. If we convert <br /> tags to <text:line-break />, why we wouldn't convert <em>, <strong>, <p>, <img>, etc the same way? At the end this functionality is a half-way to HTML to ODF converter which is not the goal of the project.

So I'd rather stay with template filter implementation.

jsykora commented 12 years ago

That makes perfect sense. I seemed to have entangled the actual scope of the project with how I use it or how I envision it being used.

In other news, the filter I posted above has been working well- I guess it helps that it is practically actual Django code. I just wish I didn't have to use the {% load %} tag in every template.

Thanks for your work on this project, it's awesome.

jsykora commented 12 years ago

I was having a problem with a couple pdfs I was trying to generate. After a lot of line by line debugging, I realized that the Objects which were causing problems were those which had '&' in the attributes that I was running through this line break filter.

The solution was to use escape option with the 'linebreaksodt' filter I defined above. I switched the autoescape kwarg to True which then made me realize I hadn't fully imported the necessary functions, so i had to add a few things to the imports.

The updated Gist is here: Gist 1676645

vmassuchetto commented 10 years ago

<text:line-break /> was printed after rendering instead of showing up as a line break. Any ideas?

monkee-ch commented 8 years ago

Am i right with my conclusion that this project is practically dead?

Many Thanks to @jsykora that line-break Gist works perfectly!

This helped me implementing it: https://docs.djangoproject.com/en/1.8/howto/custom-template-tags/

jsykora commented 8 years ago

@monkee-ch for what it's worth, I'm still using this in some internal apps, but migrating away from it. Mainly because the Open Office daemon is a pain. I run into a lot of crashes and issues with temp files pilling up. I have cron jobs to restart OO every hour.

monkee-ch commented 8 years ago

So far i use Abiword, and that works fine so far...

Only Problem i have now is that it somehow chokes on Special Characters like äöü - Any idea how to fix that?

Or do you recommend using something completely different than webodt?

jsykora commented 8 years ago

I don't really have to deal with special characters, but that may have been a limitation of abiword and googledocs processors. I needed to use Open Office for some more advanced tables anyway. (4 year ago, they might be better now).

I started using z3c.rml which is an open source implementation of Reportlab's RML. Fairly high learning curve to get it to do what you want but it's been nice for me.

monkee-ch commented 8 years ago

I fixed my special Char Problem, just force the script to UTF8

# encoding=utf8
import sys
reload(sys)
sys.setdefaultencoding('utf8')`

Thanks for your Support and Tipps!