From bb551d54ea65621cae28c6acbfd91b22dc441dae Mon Sep 17 00:00:00 2001 From: Radek Czajka Date: Fri, 1 Jul 2011 15:28:22 +0200 Subject: [PATCH 1/1] make dvcs models abstract, refactor chunk list rendering --- apps/dvcs/admin.py | 11 -- apps/dvcs/migrations/0001_initial.py | 151 ------------------ apps/dvcs/migrations/__init__.py | 0 apps/dvcs/models.py | 64 ++++++-- apps/wiki/admin.py | 2 + apps/{dvcs => wiki}/fixtures/stages.json | 18 +-- apps/wiki/forms.py | 7 +- apps/wiki/helpers.py | 46 ++++-- ...ber__add_unique_ch.py => 0003_add_dvcs.py} | 142 ++++++++++------ apps/wiki/models.py | 7 +- apps/wiki/templates/wiki/book_append_to.html | 1 + apps/wiki/templates/wiki/book_detail.html | 3 +- apps/wiki/templates/wiki/book_edit.html | 1 + apps/wiki/templates/wiki/chunk_add.html | 1 + apps/wiki/templates/wiki/chunk_edit.html | 1 + apps/wiki/templates/wiki/document_list.html | 12 +- apps/wiki/templates/wiki/pubmark_dialog.html | 1 + apps/wiki/templates/wiki/revert_dialog.html | 1 + apps/wiki/templates/wiki/save_dialog.html | 1 + apps/wiki/templates/wiki/tag_dialog.html | 1 + apps/wiki/templatetags/wiki.py | 11 +- apps/wiki/views.py | 34 ++-- redakcja/settings/common.py | 7 +- 23 files changed, 238 insertions(+), 285 deletions(-) delete mode 100644 apps/dvcs/admin.py delete mode 100644 apps/dvcs/migrations/0001_initial.py delete mode 100644 apps/dvcs/migrations/__init__.py rename apps/{dvcs => wiki}/fixtures/stages.json (83%) rename apps/wiki/migrations/{0003_auto__add_book__add_chunk__add_unique_chunk_book_number__add_unique_ch.py => 0003_add_dvcs.py} (72%) diff --git a/apps/dvcs/admin.py b/apps/dvcs/admin.py deleted file mode 100644 index f6a1ab39..00000000 --- a/apps/dvcs/admin.py +++ /dev/null @@ -1,11 +0,0 @@ -from django.contrib import admin - -from dvcs import models - - -class TagAdmin(admin.ModelAdmin): - list_display = ['name', 'slug', 'ordering'] - -admin.site.register(models.Tag, TagAdmin) -admin.site.register(models.Document) -admin.site.register(models.Change) diff --git a/apps/dvcs/migrations/0001_initial.py b/apps/dvcs/migrations/0001_initial.py deleted file mode 100644 index bf8d3e24..00000000 --- a/apps/dvcs/migrations/0001_initial.py +++ /dev/null @@ -1,151 +0,0 @@ -# encoding: utf-8 -import datetime -from south.db import db -from south.v2 import SchemaMigration -from django.db import models - -class Migration(SchemaMigration): - - def forwards(self, orm): - - # Adding model 'Tag' - db.create_table('dvcs_tag', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('name', self.gf('django.db.models.fields.CharField')(max_length=64)), - ('slug', self.gf('django.db.models.fields.SlugField')(db_index=True, max_length=64, unique=True, null=True, blank=True)), - ('ordering', self.gf('django.db.models.fields.IntegerField')()), - )) - db.send_create_signal('dvcs', ['Tag']) - - # Adding model 'Change' - db.create_table('dvcs_change', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), - ('author_name', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)), - ('author_email', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)), - ('patch', self.gf('django.db.models.fields.TextField')(blank=True)), - ('tree', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['dvcs.Document'])), - ('revision', self.gf('django.db.models.fields.IntegerField')(db_index=True)), - ('parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='children', null=True, blank=True, to=orm['dvcs.Change'])), - ('merge_parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='merge_children', null=True, blank=True, to=orm['dvcs.Change'])), - ('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)), - ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, db_index=True)), - ('publishable', self.gf('django.db.models.fields.BooleanField')(default=False)), - )) - db.send_create_signal('dvcs', ['Change']) - - # Adding unique constraint on 'Change', fields ['tree', 'revision'] - db.create_unique('dvcs_change', ['tree_id', 'revision']) - - # Adding M2M table for field tags on 'Change' - db.create_table('dvcs_change_tags', ( - ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), - ('change', models.ForeignKey(orm['dvcs.change'], null=False)), - ('tag', models.ForeignKey(orm['dvcs.tag'], null=False)) - )) - db.create_unique('dvcs_change_tags', ['change_id', 'tag_id']) - - # Adding model 'Document' - db.create_table('dvcs_document', ( - ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), - ('creator', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='created_documents', null=True, to=orm['auth.User'])), - ('head', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['dvcs.Change'], null=True, blank=True)), - ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), - ('stage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['dvcs.Tag'], null=True, blank=True)), - )) - db.send_create_signal('dvcs', ['Document']) - - if not db.dry_run: - from django.core.management import call_command - call_command("loaddata", "stages.json") - - - def backwards(self, orm): - - # Removing unique constraint on 'Change', fields ['tree', 'revision'] - db.delete_unique('dvcs_change', ['tree_id', 'revision']) - - # Deleting model 'Tag' - db.delete_table('dvcs_tag') - - # Deleting model 'Change' - db.delete_table('dvcs_change') - - # Removing M2M table for field tags on 'Change' - db.delete_table('dvcs_change_tags') - - # Deleting model 'Document' - db.delete_table('dvcs_document') - - - models = { - 'auth.group': { - 'Meta': {'object_name': 'Group'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}), - 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) - }, - 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, - 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'}) - }, - 'auth.user': { - 'Meta': {'object_name': 'User'}, - 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}), - 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}), - 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}), - 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}), - 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}), - 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}), - 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'}) - }, - 'contenttypes.contenttype': { - 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"}, - 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) - }, - 'dvcs.change': { - 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'Change'}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), - 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), - 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), - 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['dvcs.Change']"}), - 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['dvcs.Change']"}), - 'patch': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'publishable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['dvcs.Tag']", 'symmetrical': 'False'}), - 'tree': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['dvcs.Document']"}) - }, - 'dvcs.document': { - 'Meta': {'object_name': 'Document'}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_documents'", 'null': 'True', 'to': "orm['auth.User']"}), - 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['dvcs.Change']", 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['dvcs.Tag']", 'null': 'True', 'blank': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) - }, - 'dvcs.tag': { - 'Meta': {'ordering': "['ordering']", 'object_name': 'Tag'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'ordering': ('django.db.models.fields.IntegerField', [], {}), - 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}) - } - } - - complete_apps = ['dvcs'] diff --git a/apps/dvcs/migrations/__init__.py b/apps/dvcs/migrations/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/apps/dvcs/models.py b/apps/dvcs/models.py index 86f66bc9..54492402 100644 --- a/apps/dvcs/models.py +++ b/apps/dvcs/models.py @@ -1,6 +1,7 @@ from datetime import datetime from django.db import models +from django.db.models.base import ModelBase from django.contrib.auth.models import User from django.utils.translation import ugettext_lazy as _ from mercurial import mdiff, simplemerge @@ -20,6 +21,7 @@ class Tag(models.Model): _object_cache = {} class Meta: + abstract = True ordering = ['ordering'] def __unicode__(self): @@ -63,7 +65,6 @@ class Change(models.Model): author_name = models.CharField(max_length=128, null=True, blank=True) author_email = models.CharField(max_length=128, null=True, blank=True) patch = models.TextField(blank=True) - tree = models.ForeignKey('Document') revision = models.IntegerField(db_index=True) parent = models.ForeignKey('self', @@ -79,9 +80,8 @@ class Change(models.Model): default=datetime.now) publishable = models.BooleanField(default=False) - tags = models.ManyToManyField(Tag) - class Meta: + abstract = True ordering = ('created_at',) unique_together = ['tree', 'revision'] @@ -122,8 +122,7 @@ class Change(models.Model): if self.parent is None and self.merge_parent is not None: return self.apply_to(self.merge_parent.materialize()) - changes = Change.objects.exclude(parent=None).filter( - tree=self.tree, + changes = self.tree.change_set.exclude(parent=None).filter( revision__lte=self.revision).order_by('revision') text = u'' for change in changes: @@ -183,19 +182,60 @@ class Change(models.Model): self.tree.commit(text=self.materialize(), **kwargs) +def create_tag_model(model): + name = model.__name__ + 'Tag' + attrs = { + '__module__': model.__module__, + } + return type(name, (Tag,), attrs) + + +def create_change_model(model): + name = model.__name__ + 'Change' + + attrs = { + '__module__': model.__module__, + 'tree': models.ForeignKey(model, related_name='change_set'), + 'tags': models.ManyToManyField(model.tag_model, related_name='change_set'), + } + return type(name, (Change,), attrs) + + + +class DocumentMeta(ModelBase): + "Metaclass for Document models." + def __new__(cls, name, bases, attrs): + model = super(DocumentMeta, cls).__new__(cls, name, bases, attrs) + if not model._meta.abstract: + # create a real Tag object and `stage' fk + model.tag_model = create_tag_model(model) + models.ForeignKey(model.tag_model, + null=True, blank=True).contribute_to_class(model, 'stage') + + # create real Change model and `head' fk + model.change_model = create_change_model(model) + models.ForeignKey(model.change_model, + null=True, blank=True, default=None, + help_text=_("This document's current head."), + editable=False).contribute_to_class(model, 'head') + + return model + + + class Document(models.Model): """ File in repository. """ + __metaclass__ = DocumentMeta + creator = models.ForeignKey(User, null=True, blank=True, editable=False, related_name="created_documents") - head = models.ForeignKey(Change, - null=True, blank=True, default=None, - help_text=_("This document's current head."), - editable=False) user = models.ForeignKey(User, null=True, blank=True) - stage = models.ForeignKey(Tag, null=True, blank=True) + + class Meta: + abstract = True def __unicode__(self): return u"{0}, HEAD: {1}".format(self.id, self.head_id) @@ -222,7 +262,7 @@ class Document(models.Model): else: parent = kwargs['parent'] if not isinstance(parent, Change): - parent = Change.objects.get(pk=kwargs['parent']) + parent = self.change_set.objects.get(pk=kwargs['parent']) if 'patch' not in kwargs: if 'text' not in kwargs: @@ -289,7 +329,7 @@ class Document(models.Model): if not isinstance(instance, Document): return if created: - instance.head = Change.objects.create( + instance.head = instance.change_model.objects.create( revision=-1, author=instance.creator, patch=Change.make_patch('', ''), diff --git a/apps/wiki/admin.py b/apps/wiki/admin.py index 9725d0bf..b742f70d 100644 --- a/apps/wiki/admin.py +++ b/apps/wiki/admin.py @@ -9,3 +9,5 @@ class BookAdmin(admin.ModelAdmin): admin.site.register(models.Book, BookAdmin) admin.site.register(models.Chunk) admin.site.register(models.Theme) + +admin.site.register(models.Chunk.tag_model) diff --git a/apps/dvcs/fixtures/stages.json b/apps/wiki/fixtures/stages.json similarity index 83% rename from apps/dvcs/fixtures/stages.json rename to apps/wiki/fixtures/stages.json index fc05d579..992ebc71 100644 --- a/apps/dvcs/fixtures/stages.json +++ b/apps/wiki/fixtures/stages.json @@ -1,7 +1,7 @@ [ { "pk": 1, - "model": "dvcs.tag", + "model": "wiki.chunktag", "fields": { "ordering": 1, "name": "Autokorekta", @@ -10,7 +10,7 @@ }, { "pk": 2, - "model": "dvcs.tag", + "model": "wiki.chunktag", "fields": { "ordering": 2, "name": "Tagowanie", @@ -19,7 +19,7 @@ }, { "pk": 3, - "model": "dvcs.tag", + "model": "wiki.chunktag", "fields": { "ordering": 3, "name": "Korekta", @@ -28,7 +28,7 @@ }, { "pk": 4, - "model": "dvcs.tag", + "model": "wiki.chunktag", "fields": { "ordering": 4, "name": "Sprawdzenie przypis\u00f3w \u017ar\u00f3d\u0142a", @@ -37,7 +37,7 @@ }, { "pk": 5, - "model": "dvcs.tag", + "model": "wiki.chunktag", "fields": { "ordering": 5, "name": "Uwsp\u00f3\u0142cze\u015bnienie", @@ -46,7 +46,7 @@ }, { "pk": 6, - "model": "dvcs.tag", + "model": "wiki.chunktag", "fields": { "ordering": 6, "name": "Przypisy", @@ -55,7 +55,7 @@ }, { "pk": 7, - "model": "dvcs.tag", + "model": "wiki.chunktag", "fields": { "ordering": 7, "name": "Motywy", @@ -64,7 +64,7 @@ }, { "pk": 8, - "model": "dvcs.tag", + "model": "wiki.chunktag", "fields": { "ordering": 8, "name": "Ostateczna redakcja literacka", @@ -73,7 +73,7 @@ }, { "pk": 9, - "model": "dvcs.tag", + "model": "wiki.chunktag", "fields": { "ordering": 9, "name": "Ostateczna redakcja techniczna", diff --git a/apps/wiki/forms.py b/apps/wiki/forms.py index e153f7e8..6b10909b 100644 --- a/apps/wiki/forms.py +++ b/apps/wiki/forms.py @@ -8,7 +8,6 @@ from django.db.models import Count from django import forms from django.utils.translation import ugettext_lazy as _ -from dvcs.models import Tag from wiki.constants import MASTERS from wiki.models import Book, Chunk @@ -18,7 +17,7 @@ class DocumentTagForm(forms.Form): """ id = forms.CharField(widget=forms.HiddenInput) - tag = forms.ModelChoiceField(queryset=Tag.objects.all()) + tag = forms.ModelChoiceField(queryset=Chunk.tag_model.objects.all()) revision = forms.IntegerField(widget=forms.HiddenInput) @@ -114,7 +113,7 @@ class DocumentTextSaveForm(forms.Form): ) stage_completed = forms.ModelChoiceField( - queryset=Tag.objects.all(), + queryset=Chunk.tag_model.objects.all(), required=False, label=_(u"Completed"), help_text=_(u"If you completed a life cycle stage, select it."), @@ -157,7 +156,7 @@ class ChunkForm(forms.ModelForm): Form used for editing a chunk. """ user = forms.ModelChoiceField(queryset= - User.objects.annotate(count=Count('document')). + User.objects.annotate(count=Count('chunk')). order_by('-count', 'last_name', 'first_name')) diff --git a/apps/wiki/helpers.py b/apps/wiki/helpers.py index fe4b3b86..253f1291 100644 --- a/apps/wiki/helpers.py +++ b/apps/wiki/helpers.py @@ -1,4 +1,5 @@ from django import http +from django.db.models import Count from django.utils import simplejson as json from django.utils.functional import Promise from datetime import datetime @@ -144,27 +145,50 @@ def active_tab(tab): return wrapper -class BookChunks(object): - """ - Yields the chunks of a book. - """ +class ChunksList(object): + def __init__(self, chunk_qs): + self.chunk_qs = chunk_qs.annotate( + book_length=Count('book__chunk')).select_related( + 'book', 'stage__name', + 'user') - def __init__(self, book): - self.book = book + self.book_ids = [x['book_id'] for x in chunk_qs.values('book_id')] + + def __getitem__(self, key): + if isinstance(key, slice): + return self.get_slice(key) + elif isinstance(key, int): + return self.get_slice(slice(key, key+1))[0] + else: + raise TypeError('Unsupported list index. Must be a slice or an int.') + + def __len__(self): + return len(self.book_ids) + + def get_slice(self, slice_): + book_ids = self.book_ids[slice_] + chunk_qs = self.chunk_qs.filter(book__in=book_ids) - @property - def chunks(self): - return self.book.chunk_set.all() + chunks_list = [] + book = None + for chunk in chunk_qs: + if chunk.book != book: + book = chunk.book + chunks_list.append(ChoiceChunks(book, [chunk], chunk.book_length)) + else: + chunks_list[-1].chunks.append(chunk) + return chunks_list -class ChoiceChunks(BookChunks): +class ChoiceChunks(object): """ Associates the given chunks iterable for a book. """ chunks = None - def __init__(self, book, chunks): + def __init__(self, book, chunks, book_length): self.book = book self.chunks = chunks + self.book_length = book_length diff --git a/apps/wiki/migrations/0003_auto__add_book__add_chunk__add_unique_chunk_book_number__add_unique_ch.py b/apps/wiki/migrations/0003_add_dvcs.py similarity index 72% rename from apps/wiki/migrations/0003_auto__add_book__add_chunk__add_unique_chunk_book_number__add_unique_ch.py rename to apps/wiki/migrations/0003_add_dvcs.py index deb649f9..a301abf9 100644 --- a/apps/wiki/migrations/0003_auto__add_book__add_chunk__add_unique_chunk_book_number__add_unique_ch.py +++ b/apps/wiki/migrations/0003_add_dvcs.py @@ -86,7 +86,7 @@ def migrate_file_from_hg(orm, fname, entry): book=book, number=1, slug='1') - head = orm['dvcs.Change'].objects.create( + head = orm['wiki.ChunkChange'].objects.create( tree=chunk, revision=-1, patch=make_patch('', ''), @@ -95,7 +95,7 @@ def migrate_file_from_hg(orm, fname, entry): ) chunk.head = head try: - chunk.stage = orm['dvcs.Tag'].objects.order_by('ordering')[0] + chunk.stage = orm['wiki.ChunkTag'].objects.order_by('ordering')[0] except IndexError: chunk.stage = None old_data = '' @@ -112,12 +112,12 @@ def migrate_file_from_hg(orm, fname, entry): # get tags from description description = fctx.description().decode("utf-8", 'replace') tags = STAGE_TAGS_RE.findall(description) - tags = [orm['dvcs.Tag'].objects.get(slug=slug.strip()) for slug in tags] + tags = [orm['wiki.ChunkTag'].objects.get(slug=slug.strip()) for slug in tags] if tags: max_ordering = max(tags, key=lambda x: x.ordering).ordering try: - chunk.stage = orm['dvcs.Tag'].objects.filter(ordering__gt=max_ordering).order_by('ordering')[0] + chunk.stage = orm['wiki.ChunkTag'].objects.filter(ordering__gt=max_ordering).order_by('ordering')[0] except IndexError: chunk.stage = None @@ -135,7 +135,7 @@ def migrate_file_from_hg(orm, fname, entry): else: author_name = author_desc - head = orm['dvcs.Change'].objects.create( + head = orm['wiki.ChunkChange'].objects.create( tree=chunk, revision=rev + 1, patch=make_patch(old_data, data), @@ -173,10 +173,6 @@ def migrate_from_hg(orm): class Migration(SchemaMigration): - depends_on = [ - ('dvcs', '0001_initial'), - ] - def forwards(self, orm): # Adding model 'Book' @@ -194,11 +190,15 @@ class Migration(SchemaMigration): # Adding model 'Chunk' db.create_table('wiki_chunk', ( - ('document_ptr', self.gf('django.db.models.fields.related.OneToOneField')(to=orm['dvcs.Document'], unique=True, primary_key=True)), + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('creator', self.gf('django.db.models.fields.related.ForeignKey')(blank=True, related_name='created_documents', null=True, to=orm['auth.User'])), + ('user', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), ('book', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['wiki.Book'])), ('number', self.gf('django.db.models.fields.IntegerField')()), ('slug', self.gf('django.db.models.fields.SlugField')(max_length=50, db_index=True)), - ('comment', self.gf('django.db.models.fields.CharField')(max_length=255)), + ('comment', self.gf('django.db.models.fields.CharField')(max_length=255, blank=True)), + ('stage', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['wiki.ChunkTag'], null=True, blank=True)), + ('head', self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['wiki.ChunkChange'], null=True, blank=True)), )) db.send_create_signal('wiki', ['Chunk']) @@ -208,11 +208,54 @@ class Migration(SchemaMigration): # Adding unique constraint on 'Chunk', fields ['book', 'slug'] db.create_unique('wiki_chunk', ['book_id', 'slug']) + # Adding model 'ChunkTag' + db.create_table('wiki_chunktag', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('name', self.gf('django.db.models.fields.CharField')(max_length=64)), + ('slug', self.gf('django.db.models.fields.SlugField')(db_index=True, max_length=64, unique=True, null=True, blank=True)), + ('ordering', self.gf('django.db.models.fields.IntegerField')()), + )) + db.send_create_signal('wiki', ['ChunkTag']) + + # Adding model 'ChunkChange' + db.create_table('wiki_chunkchange', ( + ('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)), + ('author', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['auth.User'], null=True, blank=True)), + ('author_name', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)), + ('author_email', self.gf('django.db.models.fields.CharField')(max_length=128, null=True, blank=True)), + ('patch', self.gf('django.db.models.fields.TextField')(blank=True)), + ('revision', self.gf('django.db.models.fields.IntegerField')(db_index=True)), + ('parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='children', null=True, blank=True, to=orm['wiki.ChunkChange'])), + ('merge_parent', self.gf('django.db.models.fields.related.ForeignKey')(default=None, related_name='merge_children', null=True, blank=True, to=orm['wiki.ChunkChange'])), + ('description', self.gf('django.db.models.fields.TextField')(default='', blank=True)), + ('created_at', self.gf('django.db.models.fields.DateTimeField')(default=datetime.datetime.now, db_index=True)), + ('publishable', self.gf('django.db.models.fields.BooleanField')(default=False)), + ('tree', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['wiki.Chunk'])), + )) + db.send_create_signal('wiki', ['ChunkChange']) + + # Adding unique constraint on 'ChunkChange', fields ['tree', 'revision'] + db.create_unique('wiki_chunkchange', ['tree_id', 'revision']) + + # Adding M2M table for field tags on 'ChunkChange' + db.create_table('wiki_chunkchange_tags', ( + ('id', models.AutoField(verbose_name='ID', primary_key=True, auto_created=True)), + ('chunkchange', models.ForeignKey(orm['wiki.chunkchange'], null=False)), + ('chunktag', models.ForeignKey(orm['wiki.chunktag'], null=False)) + )) + db.create_unique('wiki_chunkchange_tags', ['chunkchange_id', 'chunktag_id']) + if not db.dry_run: + from django.core.management import call_command + call_command("loaddata", "stages.json") + migrate_from_hg(orm) def backwards(self, orm): + # Removing unique constraint on 'ChunkChange', fields ['tree', 'revision'] + db.delete_unique('wiki_chunkchange', ['tree_id', 'revision']) + # Removing unique constraint on 'Chunk', fields ['book', 'slug'] db.delete_unique('wiki_chunk', ['book_id', 'slug']) @@ -225,6 +268,15 @@ class Migration(SchemaMigration): # Deleting model 'Chunk' db.delete_table('wiki_chunk') + # Deleting model 'ChunkTag' + db.delete_table('wiki_chunktag') + + # Deleting model 'ChunkChange' + db.delete_table('wiki_chunkchange') + + # Removing M2M table for field tags on 'ChunkChange' + db.delete_table('wiki_chunkchange_tags') + models = { 'auth.group': { @@ -234,7 +286,7 @@ class Migration(SchemaMigration): 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}) }, 'auth.permission': { - 'Meta': {'ordering': "('content_type__app_label', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, + 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'}, 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}), 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), @@ -263,37 +315,6 @@ class Migration(SchemaMigration): 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}), 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'}) }, - 'dvcs.change': { - 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'Change'}, - 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), - 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), - 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), - 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), - 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['dvcs.Change']"}), - 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['dvcs.Change']"}), - 'patch': ('django.db.models.fields.TextField', [], {'blank': 'True'}), - 'publishable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), - 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), - 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['dvcs.Tag']", 'symmetrical': 'False'}), - 'tree': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['dvcs.Document']"}) - }, - 'dvcs.document': { - 'Meta': {'object_name': 'Document'}, - 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), - 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['dvcs.Change']", 'null': 'True', 'blank': 'True'}), - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['dvcs.Tag']", 'null': 'True'}), - 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True'}) - }, - 'dvcs.tag': { - 'Meta': {'ordering': "['ordering']", 'object_name': 'Tag'}, - 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), - 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), - 'ordering': ('django.db.models.fields.IntegerField', [], {}), - 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}) - }, 'wiki.book': { 'Meta': {'ordering': "['parent_number', 'title']", 'object_name': 'Book'}, '_list_html': ('django.db.models.fields.TextField', [], {'null': 'True'}), @@ -306,12 +327,39 @@ class Migration(SchemaMigration): 'title': ('django.db.models.fields.CharField', [], {'max_length': '255'}) }, 'wiki.chunk': { - 'Meta': {'ordering': "['number']", 'unique_together': "[['book', 'number'], ['book', 'slug']]", 'object_name': 'Chunk', '_ormbases': ['dvcs.Document']}, + 'Meta': {'ordering': "['number']", 'unique_together': "[['book', 'number'], ['book', 'slug']]", 'object_name': 'Chunk'}, 'book': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.Book']"}), - 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255'}), - 'document_ptr': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['dvcs.Document']", 'unique': 'True', 'primary_key': 'True'}), + 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}), + 'creator': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'created_documents'", 'null': 'True', 'to': "orm['auth.User']"}), + 'head': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'to': "orm['wiki.ChunkChange']", 'null': 'True', 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), 'number': ('django.db.models.fields.IntegerField', [], {}), - 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}) + 'slug': ('django.db.models.fields.SlugField', [], {'max_length': '50', 'db_index': 'True'}), + 'stage': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.ChunkTag']", 'null': 'True', 'blank': 'True'}), + 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}) + }, + 'wiki.chunkchange': { + 'Meta': {'ordering': "('created_at',)", 'unique_together': "(['tree', 'revision'],)", 'object_name': 'ChunkChange'}, + 'author': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'blank': 'True'}), + 'author_email': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'author_name': ('django.db.models.fields.CharField', [], {'max_length': '128', 'null': 'True', 'blank': 'True'}), + 'created_at': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now', 'db_index': 'True'}), + 'description': ('django.db.models.fields.TextField', [], {'default': "''", 'blank': 'True'}), + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'merge_parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'merge_children'", 'null': 'True', 'blank': 'True', 'to': "orm['wiki.ChunkChange']"}), + 'parent': ('django.db.models.fields.related.ForeignKey', [], {'default': 'None', 'related_name': "'children'", 'null': 'True', 'blank': 'True', 'to': "orm['wiki.ChunkChange']"}), + 'patch': ('django.db.models.fields.TextField', [], {'blank': 'True'}), + 'publishable': ('django.db.models.fields.BooleanField', [], {'default': 'False'}), + 'revision': ('django.db.models.fields.IntegerField', [], {'db_index': 'True'}), + 'tags': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['wiki.ChunkTag']", 'symmetrical': 'False'}), + 'tree': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['wiki.Chunk']"}) + }, + 'wiki.chunktag': { + 'Meta': {'ordering': "['ordering']", 'object_name': 'ChunkTag'}, + 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}), + 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}), + 'ordering': ('django.db.models.fields.IntegerField', [], {}), + 'slug': ('django.db.models.fields.SlugField', [], {'db_index': 'True', 'max_length': '64', 'unique': 'True', 'null': 'True', 'blank': 'True'}) }, 'wiki.theme': { 'Meta': {'ordering': "('name',)", 'object_name': 'Theme'}, diff --git a/apps/wiki/models.py b/apps/wiki/models.py index 28fdab8b..d35b3c40 100644 --- a/apps/wiki/models.py +++ b/apps/wiki/models.py @@ -176,13 +176,12 @@ class Chunk(dvcs_models.Document): else: return cls.objects.get(book__slug=slug, slug=chunk) - def pretty_name(self): + def pretty_name(self, book_length=None): title = self.book.title if self.comment: title += ", %s" % self.comment - count = len(self.book) - if count > 1: - title += " (%d/%d)" % (self.number, len(self.book)) + if book_length > 1: + title += " (%d/%d)" % (self.number, book_length) return title def split(self, slug, comment='', creator=None): diff --git a/apps/wiki/templates/wiki/book_append_to.html b/apps/wiki/templates/wiki/book_append_to.html index 0350aa63..da6594da 100755 --- a/apps/wiki/templates/wiki/book_append_to.html +++ b/apps/wiki/templates/wiki/book_append_to.html @@ -3,6 +3,7 @@ {% block leftcolumn %}
+ {% csrf_token %} {{ form.as_p }}

diff --git a/apps/wiki/templates/wiki/book_detail.html b/apps/wiki/templates/wiki/book_detail.html index 84d2097b..5ea0e3df 100755 --- a/apps/wiki/templates/wiki/book_detail.html +++ b/apps/wiki/templates/wiki/book_detail.html @@ -54,6 +54,7 @@ {% if need_fixing %} + {% csrf_token %} {% if choose_master %} {{ form.master }} {% endif %} @@ -89,7 +90,7 @@ -

+

{% else %} {% trans "This book cannot be published yet" %} {% endif %} diff --git a/apps/wiki/templates/wiki/book_edit.html b/apps/wiki/templates/wiki/book_edit.html index d5f527dc..8bc7ea7f 100755 --- a/apps/wiki/templates/wiki/book_edit.html +++ b/apps/wiki/templates/wiki/book_edit.html @@ -3,6 +3,7 @@ {% block leftcolumn %}
+ {% csrf_token %} {{ form.as_p }}

diff --git a/apps/wiki/templates/wiki/chunk_add.html b/apps/wiki/templates/wiki/chunk_add.html index 2b8939e0..836c34d6 100755 --- a/apps/wiki/templates/wiki/chunk_add.html +++ b/apps/wiki/templates/wiki/chunk_add.html @@ -3,6 +3,7 @@ {% block leftcolumn %} + {% csrf_token %} {{ form.as_p }}

diff --git a/apps/wiki/templates/wiki/chunk_edit.html b/apps/wiki/templates/wiki/chunk_edit.html index d5f527dc..8bc7ea7f 100755 --- a/apps/wiki/templates/wiki/chunk_edit.html +++ b/apps/wiki/templates/wiki/chunk_edit.html @@ -3,6 +3,7 @@ {% block leftcolumn %} + {% csrf_token %} {{ form.as_p }}

diff --git a/apps/wiki/templates/wiki/document_list.html b/apps/wiki/templates/wiki/document_list.html index 2a0a5efa..434324ca 100644 --- a/apps/wiki/templates/wiki/document_list.html +++ b/apps/wiki/templates/wiki/document_list.html @@ -47,17 +47,19 @@ $(function() { {% endif %} {% for item in books %} {% with item.book as book %} - - {% ifequal book.chunk_set.count 1 %} + + {% ifequal item.book_length 1 %} + {% with item.chunks.0 as chunk %} [B] - [c] + [c] {{ book.title }} - ({{ book.0.stage }}) - {% if book.0.user %}{{ book.0.user.first_name }} {{ book.0.user.last_name }}{% endif %} + ({{ chunk.stage }}) + {% if chunk.user %}{{ chunk.user.first_name }} {{ chunk.user.last_name }}{% endif %} + {% endwith %} {% else %} [B] diff --git a/apps/wiki/templates/wiki/pubmark_dialog.html b/apps/wiki/templates/wiki/pubmark_dialog.html index 93a98563..a70a0c38 100755 --- a/apps/wiki/templates/wiki/pubmark_dialog.html +++ b/apps/wiki/templates/wiki/pubmark_dialog.html @@ -1,6 +1,7 @@ {% load i18n %}
+ {% csrf_token %} {% for field in forms.pubmark.visible_fields %}

{{ field.label_tag }} {{ field }}

{{ field.help_text }}

diff --git a/apps/wiki/templates/wiki/revert_dialog.html b/apps/wiki/templates/wiki/revert_dialog.html index 7e5089f0..c2fc1553 100644 --- a/apps/wiki/templates/wiki/revert_dialog.html +++ b/apps/wiki/templates/wiki/revert_dialog.html @@ -1,6 +1,7 @@ {% load i18n %}
+ {% csrf_token %}

{{ forms.text_revert.comment.label }}

{{ forms.text_revert.comment.help_text}} diff --git a/apps/wiki/templates/wiki/save_dialog.html b/apps/wiki/templates/wiki/save_dialog.html index b2f53bab..c34eb9ec 100644 --- a/apps/wiki/templates/wiki/save_dialog.html +++ b/apps/wiki/templates/wiki/save_dialog.html @@ -1,6 +1,7 @@ {% load i18n %}

+ {% csrf_token %}

{{ forms.text_save.comment.label }}

{{ forms.text_save.comment.help_text}} diff --git a/apps/wiki/templates/wiki/tag_dialog.html b/apps/wiki/templates/wiki/tag_dialog.html index bc601cb9..aa4b2427 100644 --- a/apps/wiki/templates/wiki/tag_dialog.html +++ b/apps/wiki/templates/wiki/tag_dialog.html @@ -1,6 +1,7 @@ {% load i18n %}

+ {% csrf_token %} {% for field in forms.add_tag.visible_fields %}

{{ field.label_tag }} {{ field }}

{{ field.help_text }}

diff --git a/apps/wiki/templatetags/wiki.py b/apps/wiki/templatetags/wiki.py index 337afa65..db2eca3e 100644 --- a/apps/wiki/templatetags/wiki.py +++ b/apps/wiki/templatetags/wiki.py @@ -1,13 +1,13 @@ from __future__ import absolute_import +from django.db.models import Count from django.core.urlresolvers import reverse from django.contrib.comments.models import Comment from django.template.defaultfilters import stringfilter from django import template from django.utils.translation import ugettext as _ -from wiki.models import Book -from dvcs.models import Change +from wiki.models import Book, Chunk register = template.Library() @@ -63,11 +63,14 @@ class WallItem(object): def changes_wall(max_len): - qs = Change.objects.filter(revision__gt=-1).order_by('-created_at').select_related() + qs = Chunk.change_model.objects.filter(revision__gt=-1).order_by('-created_at') + qs = qs.defer('patch') + qs = qs.select_related('author', 'tree') + #qs = qs.annotate(book_length=Count('chunk__book__chunk')) qs = qs[:max_len] for item in qs: tag = 'stage' if item.tags.count() else 'change' - chunk = item.tree.chunk + chunk = item.tree w = WallItem(tag) w.title = chunk.pretty_name() w.summary = item.description diff --git a/apps/wiki/views.py b/apps/wiki/views.py index 7bff1a05..59ba9846 100644 --- a/apps/wiki/views.py +++ b/apps/wiki/views.py @@ -47,8 +47,12 @@ MAX_LAST_DOCS = 10 @active_tab('all') @never_cache def document_list(request): + chunks_list = helpers.ChunksList(Chunk.objects.order_by( + 'book__title', 'book', 'number')) + return direct_to_template(request, 'wiki/document_list.html', extra_context={ - 'books': [helpers.BookChunks(b) for b in Book.objects.all()], + 'books': chunks_list, + #'books': [helpers.BookChunks(b) for b in Book.objects.all().select_related()], 'last_books': sorted(request.session.get("wiki_last_books", {}).items(), key=lambda x: x[1]['time'], reverse=True), }) @@ -57,18 +61,11 @@ def document_list(request): @active_tab('unassigned') @never_cache def unassigned(request): - chunks = Chunk.objects.filter(user=None).order_by('book__title', 'book', 'number') - books = [] - book = None - for chunk in chunks: - if chunk.book != book: - book = chunk.book - books.append(helpers.ChoiceChunks(book, [chunk])) - else: - books[-1].chunks.append(chunk) + chunks_list = helpers.ChunksList(Chunk.objects.filter( + user=None).order_by('book__title', 'book__id', 'number')) return direct_to_template(request, 'wiki/document_list.html', extra_context={ - 'books': books, + 'books': chunks_list, 'last_books': sorted(request.session.get("wiki_last_books", {}).items(), key=lambda x: x[1]['time'], reverse=True), }) @@ -84,18 +81,11 @@ def user(request, username=None): else: user = get_object_or_404(User, username=username) - chunks = Chunk.objects.filter(user=user).order_by('book__title', 'number') - books = [] - book = None - for chunk in chunks: - if chunk.book != book: - book = chunk.book - books.append(helpers.ChoiceChunks(book, [chunk])) - else: - books[-1].chunks.append(chunk) + chunks_list = helpers.ChunksList(Chunk.objects.filter( + user=user).order_by('book__title', 'book', 'number')) return direct_to_template(request, 'wiki/document_list.html', extra_context={ - 'books': books, + 'books': chunks_list, 'last_books': sorted(request.session.get("wiki_last_books", {}).items(), key=lambda x: x[1]['time'], reverse=True), }) @@ -105,7 +95,7 @@ my = login_required(active_tab('my')(user)) @active_tab('users') def users(request): return direct_to_template(request, 'wiki/user_list.html', extra_context={ - 'users': User.objects.all().annotate(count=Count('document')).order_by( + 'users': User.objects.all().annotate(count=Count('chunk')).order_by( '-count', 'last_name', 'first_name'), }) diff --git a/redakcja/settings/common.py b/redakcja/settings/common.py index f55a877b..7c40abe5 100644 --- a/redakcja/settings/common.py +++ b/redakcja/settings/common.py @@ -61,13 +61,12 @@ SESSION_COOKIE_NAME = "redakcja_sessionid" # List of callables that know how to import templates from various sources. TEMPLATE_LOADERS = ( - 'django.template.loaders.filesystem.load_template_source', - 'django.template.loaders.app_directories.load_template_source', -# 'django.template.loaders.eggs.load_template_source', + 'django.template.loaders.filesystem.Loader', + 'django.template.loaders.app_directories.Loader', ) TEMPLATE_CONTEXT_PROCESSORS = ( - "django.core.context_processors.auth", + "django.contrib.auth.context_processors.auth", "django.core.context_processors.debug", "django.core.context_processors.i18n", "redakcja.context_processors.settings", # this is instead of media -- 2.20.1