Reputation: 1558
I have extended django-markdown
with a custom model field which allows one to define classes:
from django.db import models
from django_markdown.fields import MarkdownField
class MyModel(models.Model):
text = MarkdownField()
class MySecondModel(models.Model):
description = MarkdownField()
Now, when it comes to rendering those fields in the template it is possible to do:
{% load markdown_tags %}
{{ model.text|markdown }} {{ model2.description|markdown }}
However, that seems to defeat the object of creating a custom model field in the first place (to enhance DRYness), and is preferably to be avoided at all costs.
So, is there a way to do just {{ model.text }} {{ model2.description }}
without loading the template tags and without filtering by somehow defining a render
method on the custom field?
A similar question has already been asked: Is there a way to customize how the value for a custom Model Field is displayed in a template?, but the answer entails adding a method to the Model. That would mean adding methods to MyModel
and MySecondModel
, as well as any subsequent ones. Again this defeats the entire object of DRY!
NB Both model classes are subclasses of something else, so defining a mixin is feasible, but there must surely be a nicer way!
Upvotes: 5
Views: 1447
Reputation: 23064
I'm in the same situation as you. I figured that I could solve it using a mixin to the Model class.
It seems to work as intended, but I'm not really sure if it's the right way to do it. Feels like a dirty hack that I don't fully understand.
You should of course replace the method _shout() with something more useful.
from django.utils.safestring import mark_safe
from django.db import models
class LoudModelMixin(object):
""" adds the 'html' property to a Model
Lets regular django models be louder!
Regular field:
>>> blogpost.title
'hello world'
Same field, but louder.
>>> blogpost.html.title
'<strong>HELLO WORLD!</strong>'
"""
@property
def html(self):
return self._HTML(self)
class _HTML(object):
def __init__(self, parent):
self.parent = parent
def __getattr__(self, attr, *args):
raw_text = getattr(self.parent, attr, *args)
assert isinstance(raw_text, str), 'only words can be loud.'
return mark_safe(self._shout(raw_text))
def _shout(self, raw, tag='strong'):
""" Do something useful with the text here. """
return '<{tag}>{text}!</{tag}>'.format(
tag=tag, text=raw.upper()
)
class Blogpost(models.Model, LoudModelMixin):
title = models.CharField(max_length=50)
body = models.TextField()
Upvotes: 1