Slide 1

Slide 1 text

Журнальная вёрстка Делаем “красиво” с Django Алексей Дубков [email protected] MoscowDjango, 01/03/2012

Slide 2

Slide 2 text

CMS против • Раньше верстали руками • Сейчас копируют и вставляют • Скучный “Текст” • HTML-редактор не спасает • Скудное оформление

Slide 3

Slide 3 text

No content

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

Что хочется • Перемешивать текст и графику • Делать выноски, плашки • Делать колонки • Расставлять акценты • Галерею, вот прямо сюда

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

И так...

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

В чём идея? • Любой элемент — блок • Блоки: текст + графика • Сверху-вниз • Слева-направо • Блоки независимы друг от друга

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

Итак, блоки • Они могут быть разных типов • Как-то отсортированы • Привязаны к Статье, Новости и т.д.

Slide 15

Slide 15 text

# blocks/models.py from django.db import models from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes import generic class Block(models.Model): BLOCK_TYPES = ( (11, u'T-01: Обычный текст'), (21, u'P-01: Картинки 250x в 3 колонки'),) CAN_COLLAPSE = (21,) content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() content_object = generic.GenericForeignKey( 'content_type', 'object_id') block_type = models.IntegerField(choices=BLOCK_TYPES) sort = models.IntegerField(default=20) image = models.ImageField(blank=True) title = models.CharField(max_length=255, blank=True) text = models.TextField(blank=True)

Slide 16

Slide 16 text

# blocks/admin.py from django.contrib import admin from django.contrib.contenttypes.generic import GenericStackedInline from blocks.models import Block class BlockInline(GenericStackedInline): model = Block extra = 0 fieldsets = ( (None, { 'fields': (('block_type', 'sort',), 'image', 'title', 'text',) }), )

Slide 17

Slide 17 text

Вывести блоки • Выбираем блоки для статьи • Склеиваем (CAN_COLLAPSE) • Отдельный рендер для блока • Склеиваем конечный HTML

Slide 18

Slide 18 text

# blocks/utils.py from django.template import RequestContext, loader from django.contrib.contenttypes.models import ContentType from blocks.models import Block def get_blocks_html(request, obj): content_type = ContentType.objects.get( model=obj.__class__.__name__) blocks = Block.objects.filter( content_type=content_type, object_id=obj.id).order_by('sort') blocks_count = blocks.count()

Slide 19

Slide 19 text

# blocks/utils.py ... bl = [] # blocks tuple (type, data) if blocks_count: it = 0 i = 0 while i < blocks_count: type = blocks[i].block_type if type in Block.CAN_COLLAPSE: result = [] it = i for j in blocks[i:]: if j.block_type == type: result.append(j) it += 1 else: break bl.append([type, {'blocks':result}]) i = it - 1 else: bl.append([type, blocks[i].__dict__]) i += 1

Slide 20

Slide 20 text

# blocks/utils.py ... html = '' # result html if blocks_count: for (type, item) in bl: t_name = "blocks/block-%s.html" % type t = loader.get_template(t_name) render = t.render( RequestContext(request, item)) html += render return html

Slide 21

Slide 21 text

Шаблоны • В простых шаблонах сразу выводятся переменные {{ title }}, {{ text }}... • В склееных шаблонах нужен цикл • {{ for item in blocks }}

Slide 22

Slide 22 text

Пример • Делаем статьи • Подключаем админку • Блоки подключаем через inlines • Делаем вывод

Slide 23

Slide 23 text

# articles/models.py from django.db import models class Article(models.Model): title = models.CharField(max_length=64) pub_date = models.DateField() blocks_html = models.TextField(blank=True) class Meta: ordering = ['-pub_date']

Slide 24

Slide 24 text

# articles/admin.py from django.contrib import admin from articles.models import Article from blocks.admin import BlockInline class ArticleAdmin(admin.ModelAdmin): save_on_top = True inlines = [BlockInline, ] list_display = ( 'title', 'pub_date',) admin.site.register(Article, ArticleAdmin)

Slide 25

Slide 25 text

No content

Slide 26

Slide 26 text

# articles/views.py def articles_one(request, id): obj = get_object_or_404(Article, id=id) blocks_html = get_blocks_html(request, obj) return render_to_response( 'articles/articles_one.html', {'obj': obj,'blocks_html': blocks_html,}, context_instance=RequestContext(request))

Slide 27

Slide 27 text

No content

Slide 28

Slide 28 text

Ньюансы • Как хранить картинки • Утомительная сортировка • Производительность

Slide 29

Slide 29 text

# blocks/models.py def image_upload(instance, filename): return "block/%s/%s" % (instance.content_object.block_image_path(), filename.lower()) # artiles/models.py class Article(models.Model): ... def block_image_path(self): return "article/%d/%02d/%d" % ( self.pub_date.year, self.pub_date.month, self.id)

Slide 30

Slide 30 text

$(document).ready(function(){ $('#block-block-content_type-object_id-group .add-row a').click(function(){ var totalBlocks=$('#id_block-block-content_type-object_id- TOTAL_FORMS').val(); var sortFieldId="#id_block-block-content_type- object_id-"+parseInt(totalBlocks-2)+"-sort"; var newSortFieldId="#id_block-block-content_type- object_id-"+parseInt(totalBlocks-1)+"-sort"; var lastSortVal=$(sortFieldId).val(); var newSortVal=parseInt(lastSortVal)+10; $(newSortFieldId).val(newSortVal); })

Slide 31

Slide 31 text

Скорость • Производительность низкая • Можно сохранять HTML • Переопределив save_model в админке сохранять дважды

Slide 32

Slide 32 text

Минусы • Сложно в обучении • Можно “накакафонить” • Подгонять контент под формат

Slide 33

Slide 33 text

No content

Slide 34

Slide 34 text

No content

Slide 35

Slide 35 text

Спасибо