Wiki Models
inyoka.wiki.models
This module implements the database models for the wiki. It’s important to know that this doesn’t automatically mean that an operation hits the database. In fact most operations will happen either on the caching system or the python layer. Operations that hit the database are all native django query methods (which are left untouched) and those that are documented to do so.
This module implements far more models that are acutually in use in the actions. This is because the Page model and the PageManager also manage other models such as Revision, Text and of course also the special Attachment model which in fact never leaves the module except for read only access.
For details about manipulating and querying objects check out the PageManager documentation as well as the Page documentation. If you just want infos about the models as such that are passed to the template context see Page, Attachment, Revision, Text and Diff.
Meta Data
Meta data keys starting with an capital X, followed by an dash are used internally. Some of them have a special meaning, others are ignored by the software until they get a meaning by code updates.
The following keys are currently in use:
X-Link
For every internal link in the page an
X-Link
is emitted. This is used by the wiki system to look up backlinks, invalidate caches, find missing pages or orphans etc. Links that leave the parser are considered “implicitly relative” which means that they are always joined with the current page name. If a parser wants to avoid that it must prefix it with an slash before emitting it.X-Attach
Works like
X-Link
but this is emitted if a page is included with a macro that displays a page inline. Examples are the Picture or the Include macro. This is also considered being an “implicit relative” reference thus if something just accepts an absolute link this must prefix it with an slash.X-Redirect
Marks this page as redirect to another page. This should be an absolute link to an existing page.
X-Behave
Gives the page a behavior. This is used by the storage system and documented as part of that module.
X-Cache-Time
This is used to give the page a different cache time than the default.
X-Owner
Every user or group (prefixed with an
'@'
) defined this way is added to the special ACL@Owner
group. This is for example used for user wiki pages that should only give moderators, administrators and the owner of the page access.
Every internal key is only modifiable by people with the PRIV_MANAGE
privilege. Some keys like X-Link and X-Attach that are defined also
by the wiki parser itself are marked as LENIENT_METADATA_KEYS which
gives users without the PRIV_MANAGE privilege to edit them.
Apart of those users without this privilege will see the metadata in their editor but if they try to send changed metadata back to the database the wiki will avoid that. The models itself do not test for changed metadata that is part of the acl system.
- copyright:
2007-2024 by the Inyoka Team, see AUTHORS for more details.
- license:
BSD, see LICENSE for more details.
- class inyoka.wiki.models.Attachment(*args, **kwargs)
Revisions can have uploaded data associated, this table holds the mapping to the uploaded file on the file system.
- exception DoesNotExist
- exception MultipleObjectsReturned
- _meta = <Options for Attachment>
- property contents
The raw contents of the file. This is usually unsafe because it can cause the memory limit to be reached if the file is too big. However this limitation currently affects the whole django system which handles uploads in the memory.
- file
The descriptor for the file attribute on the model instance. Return a FieldFile when accessed so you can write code like:
>>> from myapp.models import MyModel >>> instance = MyModel.objects.get(pk=1) >>> instance.file.size
Assign a file object on assignment so you can do:
>>> with open('/path/to/hello.world') as f: ... instance.file = File(f)
- property filename
The filename of the attachment on the filesystem.
- get_absolute_url(action=None)
- property html_representation
This method returns a HTML representation of the attachment for the show_action page. If this method does not know about an internal representation for the object the return value will be an download link to the raw attachment.
- id
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- mimetype
The mimetype of the attachment.
- objects = <django.db.models.manager.Manager object>
- open(mode='rb')
Open the file as file descriptor. Don’t forget to close this file descriptor accordingly.
- revision_set
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Parent.children
is aReverseManyToOneDescriptor
instance.Most of the implementation is delegated to a dynamically defined manager class built by
create_forward_many_to_many_manager()
defined below.
- property size
The size of the attachment in bytes.
- class inyoka.wiki.models.Diff(page, old, new)
This class represents the results of a page comparison. You can get useful instances of this class by using the
compare
function on the PageManager.- IVariables:
- page
The page for the old and new revision.
- old_rev
A revision object that points to the left, not necessarily older revision.
- new_rev
A revision object like for old_rev, but for the right and most likely newer revision.
- udiff
The udiff of the diff as string.
- template_diff
The diff in parsed form for the template. This is mainly used by the
'wiki/_diff.html'
template which is automatically rendered if one calls the render() method on the instance.
- render()
Render the diff using the
wiki/_diff.html
template. Have a look at the class’ docstring for more detail.
- class inyoka.wiki.models.MetaData(*args, **kwargs)
Every page (just pages not revisions) can have an unlimited number of metadata associated with. Metadata is useful to add invisible information to pages such as tags, acls etc.
This should be considered being a private class because it is wrapped by the Page.metadata property and the Page.update_meta method.
- exception DoesNotExist
- exception MultipleObjectsReturned
- _meta = <Options for MetaData>
- id
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- key
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- objects = <django.db.models.manager.Manager object>
- page
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Child.parent
is aForwardManyToOneDescriptor
instance.
- page_id
- value
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- class inyoka.wiki.models.Page(*args, **kwargs)
This represents one wiki page and optionally also a bound revision. Page instances exist both bound and unbound. We refer to a bound page when a revision was attached to the page and the query documents that.
Some queries might add a revision to the page object for reasons of optimization. In that case the page appears to be bound. In such a situation it’s unsafe to call save() on the page object.
Only save pages obtained by a PageManager.get_by_name() or PageManager.get_by_name_and_rev()!
- IVariables:
- name
The normalized name of the page, as used in the URLs. For displaying a page’s name, page.title should be used. This is guaranteed to be unique.
- topic
A foreign key to the topic that belongs to this wiki page.
- rev
If the page is bound this points to a Revision otherwise None.
- exception DoesNotExist
- exception MultipleObjectsReturned
- _meta = <Options for Page>
- backlinks
List of Page objects that link to this page.
- delete()
This simply raises an exception, as we never want to delete pages really. Instead we just mark pages as deleted, which is done with edit(deleted=True).
The purpose of this method is to avoid using the django default delete() and avoid some side effects with it.
- edit(text=None, user=None, change_date=None, note='', attachment=None, attachment_filename=None, deleted=None, remote_addr=None, update_meta=True, clean_cache=True)
This saves outstanding changes and creates a new revision which is then attached to the rev attribute.
- Parameters:
- text
Either a text object or a text that represents the text. If it’s a string inyoka calculates a hash of it and tries to find a text with the same value in the database. If no text is provided the text from the last revision is used.
- user
If this parameter is None the inyoka system user will be the author of the created revision. Otherwise, it can either be a User or an AnonymousUser object from the auth contrib module.
- change_date
If this is not provided the current date is used. Otherwise, it should be an UTC timestamp in form of a datetime.datetime object.
- note
The change note for the revision. If not given it will be empty.
- attachment
see attachment_filename
- attachment_filename
if an attachment filename is given the page will act as an attachment. The attachment must be a bytestring in current django versions, for performance reasons later versions probably will support a file descriptor here. If no attachment filename is given the page will either continue to be a page or attachment depending on the last revision.
- deleted
If this is True the page is created as a deleted page. This operation doesn’t make sense and creates surprising displays in the revision log if the note is not changed to something reasonable.
- remote_addr
The remote address of the user that created this page. If not given it will be None but either remote_addr or user has to be present. This decision was made so that no confusion comes up when creating page objects in the context of a request that are not affiliated with the user.
- update_meta
This is a boolean that defines whether metadata should be updated or not. It’s useful to disable this for converter scripts.
- embedders
List of Page objects that embed this page as attachment.
- property full_title
Like title but returns the revision information too.
- get_absolute_url(action='show', revision=None, new_revision=None, format=None, **query)
- id
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- property is_main_page
True if this is the main page.
- last_rev
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Child.parent
is aForwardManyToOneDescriptor
instance.
- last_rev_id
- links
Internal wiki links on this page. Because there could be links to non-existing pages the list returned contains just the link targets in normalized format, not the page objects as such.
- metadata
Get the metadata from this page as MultiMap. It’s not possible to change metadata from the model because it’s an aggregated value from multiple sources (explicit metadata, backlinks, macros etc.)
- metadata_set
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Parent.children
is aReverseManyToOneDescriptor
instance.Most of the implementation is delegated to a dynamically defined manager class built by
create_forward_many_to_many_manager()
defined below.
- name
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- objects = <inyoka.wiki.models.PageManager object>
- rev = None
this points to a revision if created with a query method that attaches revisions. Also creating a page object using the create() function binds the revision.
- revisions
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Parent.children
is aReverseManyToOneDescriptor
instance.Most of the implementation is delegated to a dynamically defined manager class built by
create_forward_many_to_many_manager()
defined below.
- save(update_meta=True, *args, **kwargs)
This not only saves the page but also a revision that is bound to the page object. If you don’t want to save the revision set it to None before calling save().
- property short_title
Like title but just the short version of it. Thus it returns the outermost part (after the last slash). This is primarly used in the do_show action.
- property title
The title of the page. This is automatically generated from the page name and cannot be changed. However future versions might support giving pages different titles by using the metadata system.
- topic
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Child.parent
is aForwardManyToOneDescriptor
instance.
- topic_id
- property trace
The trace of pages to this page.
- update_meta()
Update page metadata and crosslinks. This method always operates on the most recent revision, never on the revision attached to the page. If there is no revision in the database yet this method fails silently.
Thus, the page create method has to call this after the revision was saved manually.
- class inyoka.wiki.models.PageManager(*args, **kwargs)
Because our table definitions are rather complex due to shared text, revisions etc the PageManager binds some of those attributes directly on the page object to give a simpler interface in templates.
The PageManager singleton instance is available as Page.objects.
- _get_object_list(exclude_privileged=False, exclude_pages=False, exclude_attachments=False, existing_only=True)
Get a list of all objects that are pages or attachments. It is possible to filter out attachments, pages, privileged or deleted/existing objects.
- attachment_for_page(page_name: str) str | None
Get the internal filename of the attachment attached to the page provided. If the page does not exist or it doesn’t have an attachment defined the return value will be None.
- clean_cache(names=None)
- clear_topic(topic)
Unset the topic from all pages associated with it.
- compare(name, old_rev, new_rev=None)
Compare two revisions of a page. If the new revision is not given, the most recent one is taken. The return value of this operation is a Diff instance.
- create(name, text, user=None, change_date=None, note=None, attachment=None, attachment_filename=None, deleted=False, remote_addr=None, update_meta=True)
Create a new wiki page. Always use this method to create pages, never the Page constructor which doesn’t create the revision and text objects.
- Parameters:
- name
This must be a normalized version of the page name. The default action dispatcher (inyoka.wiki.views.show_page) automatically normalizes incoming page names so this is no issue from the web layer. However, shell scripts, converters, crons etc. have to normalize this parameter themselves.
- text
Either a text object or a text that represents the text. If it’s a string inyoka calculates a hash of it and tries to find a text with the same value in the database.
- user
If this parameter is None the inyoka system user will be the author of the created revision. Otherwise, it can either be a User or an AnoymousUser object from the auth contrib module.
- change_date
If this is not provided the current date is used. Otherwise, it should be an UTC timestamp in form of a datetime.datetime object.
- note
The change note for the revision. If not given it will be
'Created'
or something like that.- attachment
see attachment_filename
- attachment_filename
if an attachment filename is given the page will act as an attachment. The attachment must be a bytestring in current django versions, for performance reasons latter versions probably will support a file descriptor here.
- deleted
If this is True the page is created as a deleted page. This operation doesn’t make sense and creates suprising displays in the revision log if the note is not changed to something reasonable.
- remote_addr
The remote address of the user that created this page. Either remote_addr or user is required. This decision was made so that no confusion comes up when creating page objects in the context of a request that are not affiliated with the user.
- update_meta
This is a boolean that defines whether metadata should be updated or not. It’s useful to disable this for converter scripts.
- discussions(topic)
- exists(name, cached=True)
Returns True if name exists, the results are cached in a request local object to avoid cache or db requests if possible.
name gets slugified with wiki_slugify() before.
- find_by_metadata(key, value=None)
Return a list of pages that have an entry for key with value in their metadata section.
- find_by_tag(tag)
Return a list of page names tagged with tag. The list will be sorted alphabetically.
- get_attachment_list(parent=None, existing_only=True, cached=True, exclude_privileged=False)
Works like get_page_list but just lists attachments. If parent is given only pages below that page are displayed.
- get_by_name(name, cached=True, raise_on_deleted=False, exclude_privileged=False)
Return a page with the most recent revision. This should be used from the view functions if no revision is defined because it sends just one query to get all data.
The most recent version is additionally stored in the cache so that we don’t hit the database for that. Because some caching backends share cached objects you should not modify it unless you bypass the caching backend by passing cached = False.
- get_by_name_and_rev(name, rev, raise_on_deleted=False, exclude_privileged=False)
Works like get_by_name but selects a specific revision of a page, not the most recent one. If rev is None, get_by_name is called.
- get_by_slug(name)
Returns the true page name for name after slugification.
- get_head(name, offset=0)
Return the revision ID for head or with an offset. The offset can be an negative or positive number, but despite that always the absolute number is used. This is useful if you want the non head revision, say to compare head with head - 1 you can call
Page.objects.get_head("Page_Name", -1)
.
- get_missing()
Returns a dictonary where the keys are the names of a pages that do not exist and the value is a list of page objects which have a link to that missing page.
- get_orphans()
Return a list of orphaned pages. The return value will be a list of unicode strings, not the actual page object. This ignores attachments!
- get_owned(owners)
Return all the pages a user or some group (prefixed with
@
own). The return value will be a list of page names, not page objects.Reverse method of get_owners.
- get_owners(page_name)
Get a set of owners defined using the
'X-Owner'
metadata key. This set may include groups too and is probably just seful for the get_privilege_flags function from the acl module which uses it.Groups are prefixed with an
'@'
sig.-
- get_page_count(existing_only=True, cached=True)
Get the number of pages. Per default just pages with an non deleted head will be returned. This in fact just counts the results returned by get_page_list because we hit the cache most of the time anyway.
- get_page_list(existing_only=True, cached=True, exclude_privileged=False)
Get a list of unicode strings with the page names that have a head that exists. Normally the results are cached, pass it cached if you want to force the database query. Normally this is not necessary because whenever a page is deleted or created the pagelist cache is invalidated.
- get_randompages(size=10)
Get a list of random wiki articles. Redirects are excluded as well as everything defined in WIKI_PRIVILEGED_PAGES.
- get_similar(name, n=10)
Pass it a name and it will give you a list of page names with a similar name. This also checks for similar attachments.
- get_slug_list()
Returns a cached slugified list of all wiki pages, useful to speed up our parser a lot. Avoids many cache or db hits on big pages/texts.
- get_taglist(size_limit=None)
Get a list of all tags or just the most used ones (if size_limit is set). Note that this is one of the few operations that also returns attachments, not only pages. The tag list is an ordinary list of dicts with the following keys:
'name'
The name of the tag
'count'
Number of pages flagged with this tag.
'size'
:The size of a page as an integer within 1 and 10 in relation to the highest count value. One page means a size of 1. The tag with the highest count value has the size 10.
- render_all_pages()
This method will rerender all wiki pages (only the newest revision of them and only non-privilged ones). If run on a schedule, it can guarantee that an up-to-date version is in the cache.
If a page is already in the cache, the cache entry will be dropped before rerendering it.
- class inyoka.wiki.models.Revision(*args, **kwargs)
Represents a single page revision. A revision object is always bound to a page which is available with the page attribute.
Most of the time Revision objects appear as a part of a Page object for some actions however they enter a template context without a page object too.
- IVariables:
- page
The page this object is operating on. In the templates however you will never have to access this attribute because all revisions sent to the template are either part of a bound Page or provide an extra object for the page itself.
- text
a Text object. In templates you usually don’t have to cope with this attribute because it just contains the raw data and not the rendered one. For the rendered data have a look at rendered_text.
- user
The user that created this revision. If an anoymous user created the revision this will be None.
- change_date
The date of the revision as datetime.datetime object.
- note
The change note as string.
- deleted
If the revision is marked as deleted this is True.
- remote_addr
The remote address for the user. In templates this is a useful attribute if you need a replacement for the user when no user is present.
- attachment
If the page itself holds an attachment this will point to an Attachment object. Otherwise this attribute is None and must be ignored.
- exception DoesNotExist
- exception MultipleObjectsReturned
- _meta = <Options for Revision>
- attachment
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Child.parent
is aForwardManyToOneDescriptor
instance.
- attachment_id
- change_date
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- deleted
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- get_absolute_url(action=None)
- get_next_by_change_date(*, field=<django.db.models.fields.DateTimeField: change_date>, is_next=True, **kwargs)
- get_previous_by_change_date(*, field=<django.db.models.fields.DateTimeField: change_date>, is_next=False, **kwargs)
- id
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- note
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- objects = <inyoka.wiki.models.RevisionManager object>
- page
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Child.parent
is aForwardManyToOneDescriptor
instance.
- page_id
- remote_addr
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- property rendered_text
The rendered version of the text attribute.
If the page is not in the cache yet, schedule a (semi-parallel) celery task.
Reason: Some Inyoka markup renders too slow to render synchronisly inside the request and will display a timeout (HTTP 502). In those cases, the celery task will render it asynchronisly and put the result in the cache. As a side effect, the 502 will be displayed some minutes until the rendered page is in the cache. If the rendering finished inside the request already, the celery task will fetch the rendered content from the cache. (This is a small amount of ‘wasted’ work) To prevent rendering in parallel, the celery task should be executed after the gunicorn timeout, which is 30 seconds by default.
- revert(note=None, user=None, remote_addr=None)
Revert this revision and make it the current one.
- save(*args, **kwargs)
Save the revision and invalidate the cache.
- property short_description
Returns a short, stripped excerpt from the beginning of the article.
- text
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Child.parent
is aForwardManyToOneDescriptor
instance.
- text_id
- property title
The page title plus the revision date. This is equivalent to Page.full_title.
- user
Accessor to the related object on the forward side of a many-to-one or one-to-one (via ForwardOneToOneDescriptor subclass) relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Child.parent
is aForwardManyToOneDescriptor
instance.
- user_id
- class inyoka.wiki.models.RevisionManager(*args, **kwargs)
Helper manager for revisions
- get_latest_revisions(page_name=None, count=10)
- class inyoka.wiki.models.Text(*args, **kwargs)
The text for a revision. Keep in mind that text objects are shared among revisions so never ever edit a text object after it was created.
Because of that some methods require an explicit page object being passed or a RenderContext.
- IVariables:
- value
The raw unicode value of the text.
- hash
The internal unique hash for this text.
- exception DoesNotExist
- exception MultipleObjectsReturned
- _meta = <Options for Text>
- find_meta()
Return all sort of metadata that is available on this page. This includes links, commented metadata and the simplified text.
- get_value_render_context_kwargs()
Adds additional kwargs to generate the RenderContext object.
- static get_value_rendered(text, context=None)
Renders a specific text with the configuration of this field.
This is needed to render text that is not in the database (for example the preview).
The argument context has to be a RenderContext object or a dictonary containing additional keywordarguments to generate the RenderContext object.
This method is bound to the django models as staticmethod, so it can also be called from the Model and not only from the instance.
- hash
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- id
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- is_value_in_cache()
- objects = <inyoka.wiki.models.TextManager object>
- parse(template_context=None, transformers=None)
Parse the markup into a tree. This also expands template code if the template context provided is not None.
- remove_value_from_cache()
- revisions
Accessor to the related objects manager on the reverse side of a many-to-one relation.
In the example:
class Child(Model): parent = ForeignKey(Parent, related_name='children')
Parent.children
is aReverseManyToOneDescriptor
instance.Most of the implementation is delegated to a dynamically defined manager class built by
create_forward_many_to_many_manager()
defined below.
- value
A wrapper for a deferred-loading field. When the value is read from this object the first time, the query is executed.
- property value_rendered
Renders the content of the field.
- class inyoka.wiki.models.TextManager(*args, **kwargs)
Helper manager for the text table so that we can get texts by the hash of an object. You should always use the get_or_create function to get or create a text. Available as Text.objects.
- get_or_create(value)
Works like a normal get_or_create function, just that it takes the value as positional argument too and that it uses a hash to find the correct text, rather than a string based search.
- inyoka.wiki.models.is_privileged_wiki_page(name)
- inyoka.wiki.models.to_page_by_slug_key(name)