Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Журнальная вёрстка в Django

Журнальная вёрстка в Django

Алексей Дубков

Доклад посвящён проблеме всех WYSIWYG’ов, а именно, их примитивности в форматировании наполнения сайтов. Алексей предложил вариант построения админки проекта, которая по задумке автора позволяет получить на сайте вёрстку контента как в журнале, то есть красивую и сложную.

Moscow Python Meetup

March 01, 2012
Tweet

More Decks by Moscow Python Meetup

Other Decks in Programming

Transcript

  1. CMS против • Раньше верстали руками • Сейчас копируют и

    вставляют • Скучный “Текст” • HTML-редактор не спасает • Скудное оформление
  2. Что хочется • Перемешивать текст и графику • Делать выноски,

    плашки • Делать колонки • Расставлять акценты • Галерею, вот прямо сюда
  3. В чём идея? • Любой элемент — блок • Блоки:

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

    отсортированы • Привязаны к Статье, Новости и т.д.
  5. # 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)
  6. # 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',) }), )
  7. Вывести блоки • Выбираем блоки для статьи • Склеиваем (CAN_COLLAPSE)

    • Отдельный рендер для блока • Склеиваем конечный HTML
  8. # 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()
  9. # 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
  10. # 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
  11. Шаблоны • В простых шаблонах сразу выводятся переменные {{ title

    }}, {{ text }}... • В склееных шаблонах нужен цикл • {{ for item in blocks }}
  12. # 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']
  13. # 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)
  14. # 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))
  15. # 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)
  16. $(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); })