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):
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'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'
])),
(
'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'
])
# Adding model '
ObjectForArticle
'
db
.
create_table
(
'wiki_
objectforarticle
'
,
(
# Adding model '
ArticleForObject
'
db
.
create_table
(
'wiki_
articleforobject
'
,
(
(
'id'
,
self
.
gf
(
'django.db.models.fields.AutoField'
)(
primary_key
=
True
)),
(
'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'
])),
(
'object_pk'
,
self
.
gf
(
'django.db.models.fields.TextField'
)()),
(
'content_type'
,
self
.
gf
(
'django.db.models.fields.related.ForeignKey'
)(
related_name
=
'content_type_set_for_articleforobject'
,
to
=
orm
[
'contenttypes.ContentType'
])),
(
'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'
db
.
create_table
(
'wiki_articlerevision'
,
(
...
...
@@ -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'
])),
(
'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
)),
(
'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'
])
# Adding model 'URLPath'
db
.
create_table
(
'wiki_urlpath'
,
(
(
'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
)),
(
'slug'
,
self
.
gf
(
'django.db.models.fields.SlugField'
)(
max_length
=
50
,
null
=
True
,
blank
=
True
)),
(
'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'
])),
(
'lft'
,
self
.
gf
(
'django.db.models.fields.PositiveIntegerField'
)(
db_index
=
True
)),
...
...
@@ -59,11 +70,14 @@ class Migration(SchemaMigration):
# Removing unique constraint on 'URLPath', fields ['site', 'parent', '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'
db
.
delete_table
(
'wiki_article'
)
# Deleting model '
ObjectForArticle
'
db
.
delete_table
(
'wiki_
objectforarticle
'
)
# Deleting model '
ArticleForObject
'
db
.
delete_table
(
'wiki_
articleforobject
'
)
# Deleting model 'ArticleRevision'
db
.
delete_table
(
'wiki_articlerevision'
)
...
...
@@ -117,37 +131,45 @@ class Migration(SchemaMigration):
'wiki.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']"
}),
'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'
}),
'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'
})
},
'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'
:
{
'Meta'
:
{
'object_name'
:
'ArticleRevision'
},
'article'
:
(
'django.db.models.fields.related.ForeignKey'
,
[],
{
'to'
:
"orm['wiki.Article']"
}),
'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'
}),
'id'
:
(
'django.db.models.fields.AutoField'
,
[],
{
'primary_key'
:
'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']"
}),
'revision_number'
:
(
'django.db.models.fields.IntegerField'
,
[],
{}),
'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'
:
{
'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'
}),
'level'
:
(
'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']"
}),
'rght'
:
(
'django.db.models.fields.PositiveIntegerField'
,
[],
{
'db_index'
:
'True'
}),
'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'
})
}
}
...
...
wiki/models/__init__.py
View file @
322b5a6a
...
...
@@ -4,7 +4,7 @@ from django.conf import settings as django_settings
from
django.core.exceptions
import
ImproperlyConfigured
import
warnings
from
article
import
Article
,
ArticleRevision
,
ObjectForArticle
from
article
import
Article
,
ArticleRevision
,
ArticleForObject
from
urlpath
import
URLPath
######################
...
...
wiki/models/article.py
View file @
322b5a6a
...
...
@@ -15,15 +15,6 @@ class Article(models.Model):
verbose_name
=
_
(
u'current revision'
),
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'
),
blank
=
True
,
null
=
True
)
...
...
@@ -36,10 +27,53 @@ class Article(models.Model):
other_write
=
models
.
BooleanField
(
default
=
True
)
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
):
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
):
"""
...
...
@@ -49,6 +83,7 @@ class Article(models.Model):
assert
self
.
id
or
save
,
(
'Article.add_revision: Sorry, you cannot add a'
'revision to an article that has not been saved '
'without using save=True'
)
if
not
self
.
id
:
self
.
save
()
revisions
=
self
.
articlerevision_set
.
all
()
try
:
new_revision
.
revision_number
=
revisions
.
latest
()
.
revision_number
+
1
...
...
@@ -61,25 +96,40 @@ class Article(models.Model):
def
add_object_relation
(
self
,
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
,
object_pk
=
obj
.
pk
,)
object_pk
=
obj
.
pk
,
has_parent_method
=
has_parent_field
)
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
:
app_label
=
settings
.
APP_LABEL
class
ObjectForArticle
(
models
.
Model
):
class
ArticleForObject
(
models
.
Model
):
article
=
models
.
ForeignKey
(
'Article'
)
# Same as django.contrib.comments
content_type
=
models
.
ForeignKey
(
ContentType
,
verbose_name
=
_
(
'content type'
),
related_name
=
"content_type_set_for_
%(class)
s"
)
object_pk
=
models
.
TextField
(
_
(
'object ID'
))
content_object
=
generic
.
GenericForeignKey
(
ct_field
=
"content_type"
,
fk_field
=
"object_pk"
)
object_id
=
models
.
PositiveIntegerField
(
_
(
'object ID'
))
content_object
=
generic
.
GenericForeignKey
(
ct_field
=
"content_type"
,
fk_field
=
"object_id"
)
has_parent_method
=
models
.
BooleanField
(
default
=
False
,
editable
=
False
)
class
Meta
:
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
):
...
...
wiki/models/urlpath.py
View file @
322b5a6a
# -*- coding: utf-8 -*-
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
mptt.models
import
MPTTModel
from
mptt.fields
import
TreeForeignKey
...
...
@@ -8,15 +8,22 @@ from mptt.fields import TreeForeignKey
from
wiki.core.exceptions
import
NoRootURL
,
MultipleRootURLs
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
):
"""
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
=
models
.
ForeignKey
(
'wiki.Article'
,
verbose_name
=
_
(
u'article'
),
help_text
=
_
(
u'Article to be displayed for this path'
))
slug
=
models
.
SlugField
(
verbose_name
=
_
(
u'slug'
))
# Tells django-wiki that permissions from a URLPath object's article
# should be inherited to children's articles
INHERIT_PERMISSIONS
=
True
articles
=
generic
.
GenericRelation
(
ArticleForObject
)
slug
=
models
.
SlugField
(
verbose_name
=
_
(
u'slug'
),
null
=
True
,
blank
=
True
)
site
=
models
.
ForeignKey
(
Site
)
parent
=
TreeForeignKey
(
'self'
,
null
=
True
,
blank
=
True
,
related_name
=
'children'
)
...
...
@@ -24,10 +31,11 @@ class URLPath(MPTTModel):
"/"
.
join
([
obj
.
slug
for
obj
in
self
.
get_ancestors
(
include_self
=
True
)])
class
MPTTMeta
:
order_insertion_by
=
[
'slug'
]
pass
def
__unicode__
(
self
):
return
self
.
path
path
=
self
.
get_path
()
return
path
if
path
else
ugettext
(
u"(root)"
)
def
save
(
self
,
*
args
,
**
kwargs
):
super
(
URLPath
,
self
)
.
save
(
*
args
,
**
kwargs
)
...
...
@@ -37,7 +45,17 @@ class URLPath(MPTTModel):
verbose_name_plural
=
_
(
u'URL paths'
)
unique_together
=
(
'site'
,
'parent'
,
'slug'
)
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
def
get_by_path
(
cls
,
path
):
"""
...
...
@@ -45,28 +63,44 @@ class URLPath(MPTTModel):
Accepts paths both starting with and without '/'
"""
site
=
Site
.
objects
.
get_current
()
paths
=
cls
.
objects
.
filter
(
site
=
site
)
root_nodes
=
paths
.
filter
(
parent
=
None
)
root_nodes
=
cls
.
objects
.
root_nodes
()
.
filter
(
site
=
site
)
path
=
path
.
lstrip
(
"/"
)
no_paths
=
root_nodes
.
count
()
if
no_paths
==
0
:
raise
NoRootURL
if
no_paths
>
1
:
raise
MultipleRootURLs
# Root page requested
if
not
path
:
no_paths
=
root_nodes
.
count
()
if
no_paths
==
0
:
raise
NoRootURL
if
no_paths
>
1
:
raise
MultipleRootURLs
return
root_nodes
[
0
]
slugs
=
path
.
split
(
'/'
)
level
=
1
parent
=
root_nodes
[
0
]
for
slug
in
slugs
:
if
settings
.
URL_CASE_SENSITIVE
:
pa
ths
=
paths
.
filter
(
parent__
slug
=
slug
)
pa
rent
=
parent
.
get_children
.
get
(
slug
=
slug
)
else
:
paths
=
paths
.
filter
(
parent__slug__iexact
=
slug
)
parent
=
parent
.
get_children
.
get
(
slug__iexact
=
slug
)
level
+=
1
if
paths
.
count
()
==
0
:
raise
cls
.
DoesNotExist
return
paths
[
0
]
\ No newline at end of file
return
parent
@classmethod
def
create_root
(
cls
,
site
=
None
):
if
not
site
:
site
=
Site
.
objects
.
get_current
()
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