Bom mais de um mês depois da primeira parte, finalmente tive tempo para voltar com a segunda parte desse artigo. Como prometido nessa parte vou mostrar mais duas aplicações que facilitam a nossa vida na construção de um CMS com o django.
django-tinymce
Para quem não conhece o TinyMCE é um poderoso editor WYSIWYG para navegadores web que permite ao usuário editar conteúdo HTML de uma maneira mais amigável. O que o django-tinymce faz é dar opções que facilitam o seu carregamento.
Instalação
Coloque o módulo tinymce no path do python. Vocꬆ pode coloca-lo no diretorio do projeto django ou executar o comando python setup.py install.
Copie o diretorio jscripts/tiny_mce da distribuição do TinyMCE num diretorio chamado js no seu diretório de media. Você pode alterar essa localização em settings.py.
Se você quiser usar algumas das views adicione tinymce na sua lista de aplicações e no URLconf:
settings.py:
INSTALLED_APPS = (
...
'tinymce',
...
)
urls.py:
urlpatterns = patterns('',
...
(r'^tinymce/', include('tinymce.urls')),
...
)
Utilizando como widget:
Se você usar o widget (recomendado) você precisa adicionar algum código python e possivelmente modificar seu template.
O widget do TinyMCE pode ser habilitado alterando o widget num formfield. Por exemplo, para usar widget para campo content numa flatpage você pode usar o seguinte código:
from django import forms
from django.contrib.flatpages.models import FlatPage
from tinymce.widgets import TinyMCE
class FlatPageForm(ModelForm):
...
content = forms.CharField(widget=TinyMCE(attrs={'cols': 80, 'rows': 30}))
...
class Meta:
model = FlatPage
O widget requer um link para o código javascript do TinyMCE. Os templates em django.contrib.admin fazem isso automaticamente, então se você só estiver usando tinymce em formulários do admin já está tudo certo. Para seus prórios templates contendo o widget você deve adicionar o seguinte código na tag head do HTML (assumindo que você nomeu seu formulario como form):
<head>
...
{{ form.media }}
</head>
O campo HTMLField
Outra opção seria utilizar o model field HTMLField, ele utiliza o TinyMCE como widget para renderizar o campo. No exemplo abaixo, a admin irá renderizar o campo my_field usando o widget TinyMCE:
from django.db import models
from tinymce import models as tinymce_models
class MyModel(models.Model):
my_field = tinymce_models.HTMLField()
Em todos os outros aspectos o HTMLField se comporta exatamente como o TextField padrão do Django.
Utilizando numa View
Se você não pode ou não irá modificar o widget num formulário você pode utilizar a view tinymce-js¬† para converter alguns ou todos campos de texto numa página para editores TinyMCE. No template da página, adicione as seguintes linhas na tag head:
<script type="text/javascript" src="{{ MEDIA_URL }}js/tiny_mce/tiny_mce.js"></script>
<script type="text/javascript" src="{% url tinymce-js "NAME" %}"></script>
O argumento NAME permite você criar múltiplas configurações do TinyMCE. Agora crie um template contendo o código javascript de inicialização. Ele deve ser colocado no path de templates como NAME/tinymce_textareas.js ou tinymce/NAME_textareas.js.
Exemplo:
tinyMCE.init({
mode: "textareas",
theme: "advanced",
plugins: "spellchecker,directionality,paste,searchreplace",
language: "{{ language }}",
directionality: "{{ directionality }}",
spellchecker_languages : "{{ spellchecker_languages }}",
spellchecker_rpc_url : "{{ spellchecker_rpc_url }}"
});
Essas são apenas as opções básicas do django-tinymce, para informações mais detalhadas acesse: http://django-tinymce.googlecode.com/svn/tags/release-1.5/docs/.build/html/index.html
django-compress
Javascript e CSS minificação/compressão pode diminuir bastante o tempo de carga de sites. É importante reduzir o número de requests que são feitos. Menos arquivos significa melhor desempenho. No entanto, quando você desenvolver CSS, e especialmente se você está construindo um grande site, pode ser bom separar as diferentes partes do CSS do site em arquivos diferentes. Também queremos manter o CSS e Javascript em arquivos diferentes ao mesmo tempo que você desenvolva, para fazer depuração mais fácil.
Também é agradável para comentar CSS e Javascript, mas você não quer que o overhead do envio de comentários e espaços em branco para os clientes.
Você também quer ter a certeza de que, muito do conteúdo estático está em cache, tanto quanto possível, no cliente. O ideal é mesmo evitar a “304 Not Modified”, que são retornados quando um cliente solicitou uma coisa que já tenha sido colocada em cache, e não precisa de ser atualizado. Isto pode ser conseguido setando o HTTP Expire header para uma data distante no futuro. Isso irá forçar o navegador para não pedir atualizações para esta URL. No entanto, quando você precisar atualizar os seus arquivos, você precisa lhes dar uma nova URL, e enviar os arquivos atualizados para os clientes.
Estas técnicas são descritas mais em profundidade no Yahoo:
- http://developer.yahoo.com/performance/rules.html#num_http
- http://developer.yahoo.com/performance/rules.html#minify
- http://developer.yahoo.com/performance/rules.html#expires
O django-compress é uma aplicação que irá proporcionar uma maneira fácil e automatizada para a saída de CSS e Javascript comprimidos / minificados. Ela segue o princípio DRY, você configura o seus arquivos CSS e Javascript nas configurações do seu projeto, e esta pronto. Não há necessidade de introduzir os nomes no seu modelo novamente (algumas templatetags cuidam cuidado disso).
Instalação
- Pegue o código do svn: svn co http://django-compress.googlecode.com/svn/trunk/ django-compress
- Use o script setup.py para instalar: python setup.py install
- OU manualmente coloque o diretório compress em algum lugar do seu¬† PYTHONPATH
- Adicione ‘compress’ na suas INSTALLED_APPS
Configuração
Em settings você especifica grupos de arquivos para serem comprimidos. A sintaxe básica para especificar grupos de CSS/JavaScript é:
COMPRESS_CSS = {
    'group_one': {
        'source_filenames': ('css/style.css', 'css/foo.css', 'css/bar.css'),
        'output_filename': 'css/one_compressed.css',
        'extra_context': {
            'media': 'screen,projection',
        },
    },
    # other CSS groups goes here
}
COMPRESS_JS = {
    'all': {
        'source_filenames': ('js/jquery-1.2.3.js', 'js/jquery-preload.js', 'js/jquery.pngFix.js',
        'js/my_script.js', 'js/my_other_script.js'),
        'output_filename': 'js/all_compressed.js',
    }
}
Opções de grupos
- source_filenames é uma tuple com os arquivos a serem comprimidos. Os arquivos são concatenados na ordem que são especificados na tupla. Essa opção é obrigatória.
- output_filename é o nome do arquivo resultante da compressão. Essa opção é obrigatória.
extra_context é um dicionário de valores para adicionar no contexto do tempate, quando gerando o HTML para as tags HTML com as templatetags. Essa opção é opcional. Para CSS, se você não especificar extra_context/media, a media padrão exibida será media=”all”.
Outras opções:
- COMPRESS: Quando COMPRESS é True, CSS e JavaScripts serão concatenado e filtrados. Quando False, os aqruivos fonte serão utilizados. Padrão é not DEBUG (arquivos comprimidos so serão utilizados em modo de produção)
- COMPRESS_CSS_FILTERS: Uma tuple de filtros para serem aplicados a arquivos CSS. Padrão (‘compress.filters.csstidy.CSSTidyFilter’, ). Note que a configuração padrão neessita do CCSTidy.
- COMPRESS_JS_FILTERS: Uma tuple de filtros que serão aplicados em arquivos JavaScript. Padrão (‘compress.filters.jsmin.JSMinFilter’,)
Como podemos perceber o django-compress utiliza o CSSTidy para comprimir os arquivos CSS. Porém nem sempre se tem acesso para instalação de pacotes no servidor, e a aplicação não oferece uma alternativa ao CSSTidy. Para resolver isso utilizei o código disponibilizado aqui para criar um filtro simples que somente remove os espaços em branco e os comentários.
Crie um pacote chamado cssmin no __init__.py coloque:
import warnings
warnings.simplefilter('ignore', RuntimeWarning)
from compress.filter_base import FilterBase
from cssmin.cssmin import minimalize
class CssMinFilter(FilterBase):
def filter_css(self,css):
return minimalize(css)
E crie o arquivo cssmin.py e coloque:
import re
# Constants for use in compression level setting.
NONE = 0
SIMPLE = 1
NORMAL = 2
FULL = 3
_REPLACERS = {
NONE: (None), # dummy
SIMPLE: ((r'\/\*.{4,}?\*\/', ''), # comment
(r'\n\s*\n', r"\n"), # empty new lines
(r'(^\s*\n)|(\s*\n$)', "")), # new lines at start or end
NORMAL: ((r'/\*.{4,}?\*/', ''), # comments
(r"\n", ""), # delete new lines
('[\t ]+', " "), # change spaces and tabs to one space
(r'\s?([;:{},+>])\s?', r"\1"), # delete space where it is not needed, change ;} to }
(r';}', "}"), # because semicolon is not needed there
(r'}', r"}\n")), # add new line after each rule
FULL: ((r'\/\*.*?\*\/', ''), # comments
(r"\n", ""), # delete new lines
(r'[\t ]+', " "), # change spaces and tabs to one space
(r'\s?([;:{},+>])\s?', r"\1"), # delete space where it is not needed, change ;} to }
(r';}', "}")), # because semicolon is not needed there
}
class CssMin:
def __init__(self, level=FULL):
self.level = level
def compress(self, css):
"""Tries to minimize the length of CSS code passed as parameter. Returns string."""
css = css.replace("\r\n", "\n") # get rid of Windows line endings, if they exist
for rule in _REPLACERS[self.level]:
css = re.compile(rule[0], re.MULTILINE|re.UNICODE|re.DOTALL).sub(rule[1], css)
return css
def minimalize(css, level=NORMAL):
"""Compress css using level method and return new css as a string."""
return CssMin(level).compress(css)
if __name__ == '__main__':
import sys
if len(sys.argv) <> 3:
print "Usage: %s " % sys.argv[0]
sys.exit(1)
f = open(sys.argv[1])
inputcss = f.read()
f.close()
open(sys.argv[2], 'w').write(minimalize(inputcss))
Agora é só configurar a COMPRESS_CSS_FILTERS para:
COMPRESS_CSS_FILTERS = ['seu.projeto.cssmin.CssMinFilter']
Para maiores informações sobre o django-compress acesse: http://code.google.com/p/django-compress/
Bom, chegamos ao fim dessa parte do artigo, em breve a última parte com mais aplicações que facilitam a sua vida na criação de um CMS com o django.
Até a próxima.