Source code for mezzanine.generic.models
from __future__ import unicode_literals
from future.builtins import map, str
from django.contrib.contenttypes.fields import GenericForeignKey
from django.db import models
from django.template.defaultfilters import truncatewords_html
from django.utils.translation import ugettext, ugettext_lazy as _
from django.utils.encoding import python_2_unicode_compatible
from django.utils.html import escape
from django_comments.models import Comment
from mezzanine.generic.fields import RatingField
from mezzanine.generic.managers import CommentManager, KeywordManager
from mezzanine.core.models import Slugged, Orderable
from mezzanine.conf import settings
from mezzanine.utils.models import get_user_model_name
from mezzanine.utils.sites import current_site_id
[docs]class ThreadedComment(Comment):
"""
Extend the ``Comment`` model from ``django_comments`` to
add comment threading. ``Comment`` provides its own site foreign key,
so we can't inherit from ``SiteRelated`` in ``mezzanine.core``, and
therefore need to set the site on ``save``. ``CommentManager``
inherits from Mezzanine's ``CurrentSiteManager``, so everything else
site related is already provided.
"""
by_author = models.BooleanField(_("By the blog author"), default=False)
replied_to = models.ForeignKey("self", on_delete=models.CASCADE, null=True,
editable=False, related_name="comments")
rating = RatingField(verbose_name=_("Rating"))
objects = CommentManager()
class Meta:
verbose_name = _("Comment")
verbose_name_plural = _("Comments")
[docs] def get_absolute_url(self):
"""
Use the URL for the comment's content object, with a URL hash
appended that references the individual comment.
"""
url = self.content_object.get_absolute_url()
return "%s#comment-%s" % (url, self.id)
[docs] def save(self, *args, **kwargs):
"""
Set the current site ID, and ``is_public`` based on the setting
``COMMENTS_DEFAULT_APPROVED``.
"""
if not self.id:
self.is_public = settings.COMMENTS_DEFAULT_APPROVED
self.site_id = current_site_id()
super(ThreadedComment, self).save(*args, **kwargs)
################################
# Admin listing column methods #
################################
def intro(self):
return truncatewords_html(self.comment, 20)
intro.short_description = _("Comment")
def avatar_link(self):
from mezzanine.core.templatetags.mezzanine_tags import gravatar_url
vars = (escape(self.user_email), gravatar_url(self.email),
escape(self.user_name))
return ("<a href='mailto:%s'><img style='vertical-align:middle; "
"margin-right:3px;' src='%s' />%s</a>" % vars)
avatar_link.allow_tags = True
avatar_link.short_description = _("User")
def admin_link(self):
return "<a href='%s'>%s</a>" % (self.get_absolute_url(),
ugettext("View on site"))
admin_link.allow_tags = True
admin_link.short_description = ""
# Exists for backward compatibility when the gravatar_url template
# tag which took the email address hash instead of the email address.
@property
def email_hash(self):
return self.email
[docs]class Keyword(Slugged):
"""
Keywords/tags which are managed via a custom JavaScript based
widget in the admin.
"""
objects = KeywordManager()
class Meta:
verbose_name = _("Keyword")
verbose_name_plural = _("Keywords")
[docs]@python_2_unicode_compatible
class AssignedKeyword(Orderable):
"""
A ``Keyword`` assigned to a model instance.
"""
keyword = models.ForeignKey("Keyword", on_delete=models.CASCADE,
verbose_name=_("Keyword"), related_name="assignments")
content_type = models.ForeignKey("contenttypes.ContentType",
on_delete=models.CASCADE)
object_pk = models.IntegerField()
content_object = GenericForeignKey("content_type", "object_pk")
class Meta:
order_with_respect_to = "content_object"
def __str__(self):
return str(self.keyword)
[docs]class Rating(models.Model):
"""
A rating that can be given to a piece of content.
"""
value = models.IntegerField(_("Value"))
rating_date = models.DateTimeField(_("Rating date"),
auto_now_add=True, null=True)
content_type = models.ForeignKey("contenttypes.ContentType",
on_delete=models.CASCADE)
object_pk = models.IntegerField()
content_object = GenericForeignKey("content_type", "object_pk")
user = models.ForeignKey(get_user_model_name(), on_delete=models.CASCADE,
verbose_name=_("Rater"), null=True, related_name="%(class)ss")
class Meta:
verbose_name = _("Rating")
verbose_name_plural = _("Ratings")
[docs] def save(self, *args, **kwargs):
"""
Validate that the rating falls between the min and max values.
"""
valid = map(str, settings.RATINGS_RANGE)
if str(self.value) not in valid:
raise ValueError("Invalid rating. %s is not in %s" % (self.value,
", ".join(valid)))
super(Rating, self).save(*args, **kwargs)