Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
D
django-wiki
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
OpenEdx
django-wiki
Commits
322b5a6a
Commit
322b5a6a
authored
Jul 26, 2012
by
benjaoming
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Finalizing URLPath as an MPTT model and generic relations on Articles
parent
83fe3d46
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
186 additions
and
58 deletions
+186
-58
testproject/db/prepopulated.db
+0
-0
wiki/admin.py
+22
-0
wiki/migrations/0001_initial.py
+40
-18
wiki/models/__init__.py
+1
-1
wiki/models/article.py
+66
-16
wiki/models/urlpath.py
+57
-23
No files found.
testproject/db/prepopulated.db
View file @
322b5a6a
No preview for this file type
wiki/admin.py
0 → 100644
View file @
322b5a6a
from
django.contrib
import
admin
from
django.contrib.contenttypes.generic
import
GenericTabularInline
from
mptt.admin
import
MPTTModelAdmin
import
models
class
ArticleObjectAdmin
(
GenericTabularInline
):
model
=
models
.
ArticleForObject
extra
=
1
max_num
=
1
class
ArticleAdmin
(
admin
.
ModelAdmin
):
pass
class
URLPathAdmin
(
MPTTModelAdmin
):
inlines
=
[
ArticleObjectAdmin
]
list_filter
=
(
'site'
,)
list_display
=
(
'slug'
,
'article'
)
admin
.
site
.
register
(
models
.
URLPath
,
URLPathAdmin
)
admin
.
site
.
register
(
models
.
Article
,
ArticleAdmin
)
\ No newline at end of file
wiki/migrations/0001_initial.py
View file @
322b5a6a
...
@@ -13,17 +13,27 @@ class Migration(SchemaMigration):
...
@@ -13,17 +13,27 @@ class Migration(SchemaMigration):
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'title'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
512
)),
(
'title'
,
self
.
gf
(
'django.db.models.fields.CharField'
)(
max_length
=
512
)),
(
'current_revision'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
blank
=
True
,
related_name
=
'current_set'
,
null
=
True
,
to
=
orm
[
'wiki.ArticleRevision'
])),
(
'current_revision'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
blank
=
True
,
related_name
=
'current_set'
,
null
=
True
,
to
=
orm
[
'wiki.ArticleRevision'
])),
(
'owner'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'auth.User'
],
null
=
True
,
blank
=
True
)),
(
'group'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'auth.Group'
],
null
=
True
,
blank
=
True
)),
(
'group_read'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
True
)),
(
'group_write'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
True
)),
(
'other_read'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
True
)),
(
'other_write'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
True
)),
))
))
db
.
send_create_signal
(
'wiki'
,
[
'Article'
])
db
.
send_create_signal
(
'wiki'
,
[
'Article'
])
# Adding model '
ObjectForArticle
'
# Adding model '
ArticleForObject
'
db
.
create_table
(
'wiki_
objectforarticle
'
,
(
db
.
create_table
(
'wiki_
articleforobject
'
,
(
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'article'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'wiki.Article'
])),
(
'article'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'wiki.Article'
])),
(
'content_type'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
related_name
=
'content_type_set_for_objectforarticle'
,
to
=
orm
[
'contenttypes.ContentType'
])),
(
'content_type'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
related_name
=
'content_type_set_for_articleforobject'
,
to
=
orm
[
'contenttypes.ContentType'
])),
(
'object_pk'
,
self
.
gf
(
'django.db.models.fields.TextField'
)()),
(
'object_id'
,
self
.
gf
(
'django.db.models.fields.PositiveIntegerField'
)()),
(
'has_parent_method'
,
self
.
gf
(
'django.db.models.fields.BooleanField'
)(
default
=
False
)),
))
))
db
.
send_create_signal
(
'wiki'
,
[
'ObjectForArticle'
])
db
.
send_create_signal
(
'wiki'
,
[
'ArticleForObject'
])
# Adding unique constraint on 'ArticleForObject', fields ['content_type', 'object_id']
db
.
create_unique
(
'wiki_articleforobject'
,
[
'content_type_id'
,
'object_id'
])
# Adding model 'ArticleRevision'
# Adding model 'ArticleRevision'
db
.
create_table
(
'wiki_articlerevision'
,
(
db
.
create_table
(
'wiki_articlerevision'
,
(
...
@@ -35,14 +45,15 @@ class Migration(SchemaMigration):
...
@@ -35,14 +45,15 @@ class Migration(SchemaMigration):
(
'redirect'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
blank
=
True
,
related_name
=
'redirect_set'
,
null
=
True
,
to
=
orm
[
'wiki.Article'
])),
(
'redirect'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
blank
=
True
,
related_name
=
'redirect_set'
,
null
=
True
,
to
=
orm
[
'wiki.Article'
])),
(
'ip_address'
,
self
.
gf
(
'django.db.models.fields.IPAddressField'
)(
max_length
=
15
,
null
=
True
,
blank
=
True
)),
(
'ip_address'
,
self
.
gf
(
'django.db.models.fields.IPAddressField'
)(
max_length
=
15
,
null
=
True
,
blank
=
True
)),
(
'user'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'auth.User'
],
null
=
True
,
blank
=
True
)),
(
'user'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'auth.User'
],
null
=
True
,
blank
=
True
)),
(
'created'
,
self
.
gf
(
'django.db.models.fields.DateTimeField'
)(
auto_now_add
=
True
,
blank
=
True
)),
(
'modified'
,
self
.
gf
(
'django.db.models.fields.DateTimeField'
)(
auto_now
=
True
,
blank
=
True
)),
))
))
db
.
send_create_signal
(
'wiki'
,
[
'ArticleRevision'
])
db
.
send_create_signal
(
'wiki'
,
[
'ArticleRevision'
])
# Adding model 'URLPath'
# Adding model 'URLPath'
db
.
create_table
(
'wiki_urlpath'
,
(
db
.
create_table
(
'wiki_urlpath'
,
(
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'article'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'wiki.Article'
])),
(
'slug'
,
self
.
gf
(
'django.db.models.fields.SlugField'
)(
max_length
=
50
,
null
=
True
,
blank
=
True
)),
(
'slug'
,
self
.
gf
(
'django.db.models.fields.SlugField'
)(
max_length
=
50
)),
(
'site'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'sites.Site'
])),
(
'site'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
to
=
orm
[
'sites.Site'
])),
(
'parent'
,
self
.
gf
(
'mptt.fields.TreeForeignKey'
)(
blank
=
True
,
related_name
=
'children'
,
null
=
True
,
to
=
orm
[
'wiki.URLPath'
])),
(
'parent'
,
self
.
gf
(
'mptt.fields.TreeForeignKey'
)(
blank
=
True
,
related_name
=
'children'
,
null
=
True
,
to
=
orm
[
'wiki.URLPath'
])),
(
'lft'
,
self
.
gf
(
'django.db.models.fields.PositiveIntegerField'
)(
db_index
=
True
)),
(
'lft'
,
self
.
gf
(
'django.db.models.fields.PositiveIntegerField'
)(
db_index
=
True
)),
...
@@ -59,11 +70,14 @@ class Migration(SchemaMigration):
...
@@ -59,11 +70,14 @@ class Migration(SchemaMigration):
# Removing unique constraint on 'URLPath', fields ['site', 'parent', 'slug']
# Removing unique constraint on 'URLPath', fields ['site', 'parent', 'slug']
db
.
delete_unique
(
'wiki_urlpath'
,
[
'site_id'
,
'parent_id'
,
'slug'
])
db
.
delete_unique
(
'wiki_urlpath'
,
[
'site_id'
,
'parent_id'
,
'slug'
])
# Removing unique constraint on 'ArticleForObject', fields ['content_type', 'object_id']
db
.
delete_unique
(
'wiki_articleforobject'
,
[
'content_type_id'
,
'object_id'
])
# Deleting model 'Article'
# Deleting model 'Article'
db
.
delete_table
(
'wiki_article'
)
db
.
delete_table
(
'wiki_article'
)
# Deleting model '
ObjectForArticle
'
# Deleting model '
ArticleForObject
'
db
.
delete_table
(
'wiki_
objectforarticle
'
)
db
.
delete_table
(
'wiki_
articleforobject
'
)
# Deleting model 'ArticleRevision'
# Deleting model 'ArticleRevision'
db
.
delete_table
(
'wiki_articlerevision'
)
db
.
delete_table
(
'wiki_articlerevision'
)
...
@@ -117,37 +131,45 @@ class Migration(SchemaMigration):
...
@@ -117,37 +131,45 @@ class Migration(SchemaMigration):
'wiki.article'
:
{
'wiki.article'
:
{
'Meta'
:
{
'object_name'
:
'Article'
},
'Meta'
:
{
'object_name'
:
'Article'
},
'current_revision'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"'current_set'"
,
'null'
:
'True'
,
'to'
:
"orm['wiki.ArticleRevision']"
}),
'current_revision'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"'current_set'"
,
'null'
:
'True'
,
'to'
:
"orm['wiki.ArticleRevision']"
}),
'group'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.Group']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'group_read'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'group_write'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'other_read'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'other_write'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'True'
}),
'owner'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'title'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'512'
})
'title'
:
(
'django.db.models.fields.CharField'
,
[],
{
'max_length'
:
'512'
})
},
},
'wiki.articleforobject'
:
{
'Meta'
:
{
'unique_together'
:
"(('content_type', 'object_id'),)"
,
'object_name'
:
'ArticleForObject'
},
'article'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['wiki.Article']"
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'related_name'
:
"'content_type_set_for_articleforobject'"
,
'to'
:
"orm['contenttypes.ContentType']"
}),
'has_parent_method'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'object_id'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{})
},
'wiki.articlerevision'
:
{
'wiki.articlerevision'
:
{
'Meta'
:
{
'object_name'
:
'ArticleRevision'
},
'Meta'
:
{
'object_name'
:
'ArticleRevision'
},
'article'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['wiki.Article']"
}),
'article'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['wiki.Article']"
}),
'content'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'content'
:
(
'django.db.models.fields.TextField'
,
[],
{
'blank'
:
'True'
}),
'created'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now_add'
:
'True'
,
'blank'
:
'True'
}),
'deleted'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'deleted'
:
(
'django.db.models.fields.BooleanField'
,
[],
{
'default'
:
'False'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'ip_address'
:
(
'django.db.models.fields.IPAddressField'
,
[],
{
'max_length'
:
'15'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'ip_address'
:
(
'django.db.models.fields.IPAddressField'
,
[],
{
'max_length'
:
'15'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'modified'
:
(
'django.db.models.fields.DateTimeField'
,
[],
{
'auto_now'
:
'True'
,
'blank'
:
'True'
}),
'redirect'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"'redirect_set'"
,
'null'
:
'True'
,
'to'
:
"orm['wiki.Article']"
}),
'redirect'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"'redirect_set'"
,
'null'
:
'True'
,
'to'
:
"orm['wiki.Article']"
}),
'revision_number'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'revision_number'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
})
'user'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['auth.User']"
,
'null'
:
'True'
,
'blank'
:
'True'
})
},
},
'wiki.objectforarticle'
:
{
'Meta'
:
{
'object_name'
:
'ObjectForArticle'
},
'article'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['wiki.Article']"
}),
'content_type'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'related_name'
:
"'content_type_set_for_objectforarticle'"
,
'to'
:
"orm['contenttypes.ContentType']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'object_pk'
:
(
'django.db.models.fields.TextField'
,
[],
{})
},
'wiki.urlpath'
:
{
'wiki.urlpath'
:
{
'Meta'
:
{
'unique_together'
:
"(('site', 'parent', 'slug'),)"
,
'object_name'
:
'URLPath'
},
'Meta'
:
{
'unique_together'
:
"(('site', 'parent', 'slug'),)"
,
'object_name'
:
'URLPath'
},
'article'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['wiki.Article']"
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'True'
}),
'level'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'db_index'
:
'True'
}),
'level'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'db_index'
:
'True'
}),
'lft'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'db_index'
:
'True'
}),
'lft'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'db_index'
:
'True'
}),
'parent'
:
(
'mptt.fields.TreeForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"'children'"
,
'null'
:
'True'
,
'to'
:
"orm['wiki.URLPath']"
}),
'parent'
:
(
'mptt.fields.TreeForeignKey'
,
[],
{
'blank'
:
'True'
,
'related_name'
:
"'children'"
,
'null'
:
'True'
,
'to'
:
"orm['wiki.URLPath']"
}),
'rght'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'db_index'
:
'True'
}),
'rght'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'db_index'
:
'True'
}),
'site'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['sites.Site']"
}),
'site'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['sites.Site']"
}),
'slug'
:
(
'django.db.models.fields.SlugField'
,
[],
{
'max_length'
:
'50'
}),
'slug'
:
(
'django.db.models.fields.SlugField'
,
[],
{
'max_length'
:
'50'
,
'null'
:
'True'
,
'blank'
:
'True'
}),
'tree_id'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'db_index'
:
'True'
})
'tree_id'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'db_index'
:
'True'
})
}
}
}
}
...
...
wiki/models/__init__.py
View file @
322b5a6a
...
@@ -4,7 +4,7 @@ from django.conf import settings as django_settings
...
@@ -4,7 +4,7 @@ from django.conf import settings as django_settings
from
django.core.exceptions
import
ImproperlyConfigured
from
django.core.exceptions
import
ImproperlyConfigured
import
warnings
import
warnings
from
article
import
Article
,
ArticleRevision
,
ObjectForArticle
from
article
import
Article
,
ArticleRevision
,
ArticleForObject
from
urlpath
import
URLPath
from
urlpath
import
URLPath
######################
######################
...
...
wiki/models/article.py
View file @
322b5a6a
...
@@ -15,15 +15,6 @@ class Article(models.Model):
...
@@ -15,15 +15,6 @@ class Article(models.Model):
verbose_name
=
_
(
u'current revision'
),
verbose_name
=
_
(
u'current revision'
),
blank
=
True
,
null
=
True
,
related_name
=
'current_set'
)
blank
=
True
,
null
=
True
,
related_name
=
'current_set'
)
# Permissions. If nothing is set, the article will inherit from
# some other parent, whatever the semantics dictate. For instance, using
# URLPaths means that the article inherits from its URLPath parent.
# Inheriting permissions requires a "get_parent_articles" method to exist on
# one of the objects related to the article.
# TIP: The related object with a get_parent_articles method should be an
# MPTTModel inheritor for efficiency. See the URLPath model.
owner
=
models
.
ForeignKey
(
User
,
verbose_name
=
_
(
'owner'
),
owner
=
models
.
ForeignKey
(
User
,
verbose_name
=
_
(
'owner'
),
blank
=
True
,
null
=
True
)
blank
=
True
,
null
=
True
)
...
@@ -36,10 +27,53 @@ class Article(models.Model):
...
@@ -36,10 +27,53 @@ class Article(models.Model):
other_write
=
models
.
BooleanField
(
default
=
True
)
other_write
=
models
.
BooleanField
(
default
=
True
)
def
can_read
(
self
,
user
=
None
,
group
=
None
):
def
can_read
(
self
,
user
=
None
,
group
=
None
):
return
True
if
self
.
other_read
:
return
True
if
user
==
self
.
owner
:
return
True
if
self
.
group_read
:
if
group
==
self
.
group
:
return
True
if
self
.
group
and
user
and
user
.
groups
.
filter
(
group
=
group
):
return
True
return
False
def
can_write
(
self
,
user
=
None
,
group
=
None
):
def
can_write
(
self
,
user
=
None
,
group
=
None
):
return
True
if
self
.
other_write
:
return
True
if
user
==
self
.
owner
:
return
True
if
self
.
group_write
:
if
group
==
self
.
group
:
return
True
if
self
.
group
and
user
and
user
.
groups
.
filter
(
group
=
group
):
return
True
return
False
def
decendant_objects
(
self
):
for
obj
in
self
.
objectforarticle_set
.
filter
(
has_parent_field
=
True
):
for
decendant
in
obj
.
get_decendants
():
yield
decendant
# All recursive permission methods will use decendant_objects to access
# generic relations and check if they are using MPTT and have INHERIT_PERMISSIONS=True
def
set_permissions_recursive
(
self
):
for
decendant
in
self
.
decendant_objects
():
if
decendant
.
INHERIT_PERMISSIONS
:
decendant
.
group_read
=
self
.
group_read
decendant
.
group_write
=
self
.
group_write
decendant
.
other_read
=
self
.
other_read
decendant
.
other_write
=
self
.
other_write
def
set_group_recursive
(
self
):
for
decendant
in
self
.
decendant_objects
():
if
decendant
.
INHERIT_PERMISSIONS
:
decendant
.
group
=
self
.
group
def
set_owner_recursive
(
self
):
for
decendant
in
self
.
decendant_objects
():
if
decendant
.
INHERIT_PERMISSIONS
:
decendant
.
owner
=
self
.
owner
def
add_revision
(
self
,
new_revision
,
save
=
True
):
def
add_revision
(
self
,
new_revision
,
save
=
True
):
"""
"""
...
@@ -49,6 +83,7 @@ class Article(models.Model):
...
@@ -49,6 +83,7 @@ class Article(models.Model):
assert
self
.
id
or
save
,
(
'Article.add_revision: Sorry, you cannot add a'
assert
self
.
id
or
save
,
(
'Article.add_revision: Sorry, you cannot add a'
'revision to an article that has not been saved '
'revision to an article that has not been saved '
'without using save=True'
)
'without using save=True'
)
if
not
self
.
id
:
self
.
save
()
revisions
=
self
.
articlerevision_set
.
all
()
revisions
=
self
.
articlerevision_set
.
all
()
try
:
try
:
new_revision
.
revision_number
=
revisions
.
latest
()
.
revision_number
+
1
new_revision
.
revision_number
=
revisions
.
latest
()
.
revision_number
+
1
...
@@ -61,25 +96,40 @@ class Article(models.Model):
...
@@ -61,25 +96,40 @@ class Article(models.Model):
def
add_object_relation
(
self
,
obj
):
def
add_object_relation
(
self
,
obj
):
content_type
=
ContentType
.
objects
.
get_for_model
(
obj
)
content_type
=
ContentType
.
objects
.
get_for_model
(
obj
)
rel
=
ObjectForArticle
.
objects
.
get_or_create
(
article
=
self
,
has_parent_field
=
hasattr
(
obj
,
'parent'
)
rel
=
ArticleForObject
.
objects
.
get_or_create
(
article
=
self
,
content_type
=
content_type
,
content_type
=
content_type
,
object_pk
=
obj
.
pk
,)
object_pk
=
obj
.
pk
,
has_parent_method
=
has_parent_field
)
return
rel
return
rel
@classmethod
def
get_for_object
(
cls
,
obj
):
return
ArticleForObject
.
objects
.
get
(
object_id
=
obj
.
id
,
content_type
=
ContentType
.
objects
.
get_for_model
(
obj
))
.
article
def
__unicode__
(
self
):
return
self
.
title
class
Meta
:
class
Meta
:
app_label
=
settings
.
APP_LABEL
app_label
=
settings
.
APP_LABEL
class
ObjectForArticle
(
models
.
Model
):
class
ArticleForObject
(
models
.
Model
):
article
=
models
.
ForeignKey
(
'Article'
)
article
=
models
.
ForeignKey
(
'Article'
)
# Same as django.contrib.comments
# Same as django.contrib.comments
content_type
=
models
.
ForeignKey
(
ContentType
,
content_type
=
models
.
ForeignKey
(
ContentType
,
verbose_name
=
_
(
'content type'
),
verbose_name
=
_
(
'content type'
),
related_name
=
"content_type_set_for_
%(class)
s"
)
related_name
=
"content_type_set_for_
%(class)
s"
)
object_pk
=
models
.
TextField
(
_
(
'object ID'
))
object_id
=
models
.
PositiveIntegerField
(
_
(
'object ID'
))
content_object
=
generic
.
GenericForeignKey
(
ct_field
=
"content_type"
,
fk_field
=
"object_pk"
)
content_object
=
generic
.
GenericForeignKey
(
ct_field
=
"content_type"
,
fk_field
=
"object_id"
)
has_parent_method
=
models
.
BooleanField
(
default
=
False
,
editable
=
False
)
class
Meta
:
class
Meta
:
app_label
=
settings
.
APP_LABEL
app_label
=
settings
.
APP_LABEL
verbose_name
=
_
(
u'Article for object'
)
verbose_name_plural
=
_
(
u'Articles for object'
)
# Do not allow several objects
unique_together
=
(
'content_type'
,
'object_id'
)
class
ArticleRevision
(
models
.
Model
):
class
ArticleRevision
(
models
.
Model
):
...
...
wiki/models/urlpath.py
View file @
322b5a6a
# -*- coding: utf-8 -*-
# -*- coding: utf-8 -*-
from
django.db
import
models
from
django.db
import
models
from
django.utils.translation
import
ugettext_lazy
as
_
from
django.utils.translation
import
ugettext_lazy
as
_
,
ugettext
from
django.contrib.sites.models
import
Site
from
django.contrib.sites.models
import
Site
from
mptt.models
import
MPTTModel
from
mptt.models
import
MPTTModel
from
mptt.fields
import
TreeForeignKey
from
mptt.fields
import
TreeForeignKey
...
@@ -8,15 +8,22 @@ from mptt.fields import TreeForeignKey
...
@@ -8,15 +8,22 @@ from mptt.fields import TreeForeignKey
from
wiki.core.exceptions
import
NoRootURL
,
MultipleRootURLs
from
wiki.core.exceptions
import
NoRootURL
,
MultipleRootURLs
from
wiki.conf
import
settings
from
wiki.conf
import
settings
from
article
import
Article
from
wiki.models.article
import
ArticleRevision
,
ArticleForObject
from
django.contrib.contenttypes
import
generic
from
django.core.exceptions
import
ValidationError
class
URLPath
(
MPTTModel
):
class
URLPath
(
MPTTModel
):
"""
"""
Strategy: Very few fields go here, as most has to be managed through an
Strategy: Very few fields go here, as most has to be managed through an
article's revision. As a side-effect, the URL resolution remains slim and swift.
article's revision. As a side-effect, the URL resolution remains slim and swift.
"""
"""
article
=
models
.
ForeignKey
(
'wiki.Article'
,
# Tells django-wiki that permissions from a URLPath object's article
verbose_name
=
_
(
u'article'
),
# should be inherited to children's articles
help_text
=
_
(
u'Article to be displayed for this path'
))
INHERIT_PERMISSIONS
=
True
slug
=
models
.
SlugField
(
verbose_name
=
_
(
u'slug'
))
articles
=
generic
.
GenericRelation
(
ArticleForObject
)
slug
=
models
.
SlugField
(
verbose_name
=
_
(
u'slug'
),
null
=
True
,
blank
=
True
)
site
=
models
.
ForeignKey
(
Site
)
site
=
models
.
ForeignKey
(
Site
)
parent
=
TreeForeignKey
(
'self'
,
null
=
True
,
blank
=
True
,
related_name
=
'children'
)
parent
=
TreeForeignKey
(
'self'
,
null
=
True
,
blank
=
True
,
related_name
=
'children'
)
...
@@ -24,10 +31,11 @@ class URLPath(MPTTModel):
...
@@ -24,10 +31,11 @@ class URLPath(MPTTModel):
"/"
.
join
([
obj
.
slug
for
obj
in
self
.
get_ancestors
(
include_self
=
True
)])
"/"
.
join
([
obj
.
slug
for
obj
in
self
.
get_ancestors
(
include_self
=
True
)])
class
MPTTMeta
:
class
MPTTMeta
:
order_insertion_by
=
[
'slug'
]
pass
def
__unicode__
(
self
):
def
__unicode__
(
self
):
return
self
.
path
path
=
self
.
get_path
()
return
path
if
path
else
ugettext
(
u"(root)"
)
def
save
(
self
,
*
args
,
**
kwargs
):
def
save
(
self
,
*
args
,
**
kwargs
):
super
(
URLPath
,
self
)
.
save
(
*
args
,
**
kwargs
)
super
(
URLPath
,
self
)
.
save
(
*
args
,
**
kwargs
)
...
@@ -37,7 +45,17 @@ class URLPath(MPTTModel):
...
@@ -37,7 +45,17 @@ class URLPath(MPTTModel):
verbose_name_plural
=
_
(
u'URL paths'
)
verbose_name_plural
=
_
(
u'URL paths'
)
unique_together
=
(
'site'
,
'parent'
,
'slug'
)
unique_together
=
(
'site'
,
'parent'
,
'slug'
)
app_label
=
settings
.
APP_LABEL
app_label
=
settings
.
APP_LABEL
def
clean
(
self
,
*
args
,
**
kwargs
):
if
self
.
slug
and
not
self
.
parent
:
raise
ValidationError
(
_
(
u'Sorry but you cannot have a root article with a slug.'
))
if
not
self
.
slug
and
self
.
parent
:
raise
ValidationError
(
_
(
u'A non-root note must always have a slug.'
))
if
not
self
.
parent
:
if
URLPath
.
objects
.
root_nodes
()
.
filter
(
site
=
self
.
site
):
raise
ValidationError
(
_
(
u'There is already a root node on
%
s'
)
%
self
.
site
)
super
(
URLPath
,
self
)
.
clean
(
*
args
,
**
kwargs
)
@classmethod
@classmethod
def
get_by_path
(
cls
,
path
):
def
get_by_path
(
cls
,
path
):
"""
"""
...
@@ -45,28 +63,44 @@ class URLPath(MPTTModel):
...
@@ -45,28 +63,44 @@ class URLPath(MPTTModel):
Accepts paths both starting with and without '/'
Accepts paths both starting with and without '/'
"""
"""
site
=
Site
.
objects
.
get_current
()
site
=
Site
.
objects
.
get_current
()
paths
=
cls
.
objects
.
filter
(
site
=
site
)
root_nodes
=
cls
.
objects
.
root_nodes
()
.
filter
(
site
=
site
)
root_nodes
=
paths
.
filter
(
parent
=
None
)
path
=
path
.
lstrip
(
"/"
)
path
=
path
.
lstrip
(
"/"
)
no_paths
=
root_nodes
.
count
()
if
no_paths
==
0
:
raise
NoRootURL
if
no_paths
>
1
:
raise
MultipleRootURLs
# Root page requested
# Root page requested
if
not
path
:
if
not
path
:
no_paths
=
root_nodes
.
count
()
if
no_paths
==
0
:
raise
NoRootURL
if
no_paths
>
1
:
raise
MultipleRootURLs
return
root_nodes
[
0
]
return
root_nodes
[
0
]
slugs
=
path
.
split
(
'/'
)
slugs
=
path
.
split
(
'/'
)
level
=
1
parent
=
root_nodes
[
0
]
for
slug
in
slugs
:
for
slug
in
slugs
:
if
settings
.
URL_CASE_SENSITIVE
:
if
settings
.
URL_CASE_SENSITIVE
:
pa
ths
=
paths
.
filter
(
parent__
slug
=
slug
)
pa
rent
=
parent
.
get_children
.
get
(
slug
=
slug
)
else
:
else
:
paths
=
paths
.
filter
(
parent__slug__iexact
=
slug
)
parent
=
parent
.
get_children
.
get
(
slug__iexact
=
slug
)
level
+=
1
if
paths
.
count
()
==
0
:
return
parent
raise
cls
.
DoesNotExist
@classmethod
return
paths
[
0
]
def
create_root
(
cls
,
site
=
None
):
if
not
site
:
site
=
Site
.
objects
.
get_current
()
\ No newline at end of file
if
not
cls
.
objects
.
root_nodes
()
.
filter
(
site
=
site
):
# (get_or_create does not work for MPTT models??)
root
=
cls
.
objects
.
create
(
site
=
site
)
article
=
Article
()
article
.
add_revision
(
ArticleRevision
(),
save
=
True
)
article
.
add_object_relation
(
root
)
@property
def
article
(
self
):
try
:
return
self
.
articles
.
all
()[
0
]
except
IndexError
:
return
None
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment