A R Y A N
A R Y A N

Reputation: 95

Substract a substring from a string in a model object in Django

I'm building a blog website with Django, and for posts on the blog I want to have 2 pages, first page would be the page where all the posts are displayed as a list, and the second would be a page for a specific post, with all the details. On the first page I want to show every post with title, date, and a part of the post's text. I thought that I can add to the post model another field which'll hold a substring from the hole post's text. My post model is this:

class Post(models.Model):
    author = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=500)
    content = models.TextField()
    display_content = models.TextField(blank=True)
    tags = models.CharField(max_length=100)
    date_posted = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.title

I want for every post the display_content field to hold the first 167 characters from the content field + "...", and I'm not sure that I'd have to implement something directly on the class Post, maybe a function, or if I need to make this operation on the view function that renders this page with posts.

Upvotes: 1

Views: 627

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476554

You can define the logic in the __str__ method, but it might be better to define a utility function that you can later reuse:

def shorten(text, max_len=167):
    if len(text) <= max_len:
        return text
    else:
        return '{}…'.format(text[:max_len])

Note that an ellipsis character ('…') [wiki] is a single character, and normally not three inidividual dots.

Then we can use this in the __str__ method:

from django.conf import settings

class Post(models.Model):
    author = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE
    )
    title = models.CharField(max_length=500)
    content = models.TextField()
    display_content = models.TextField(blank=True)
    tags = models.CharField(max_length=100)
    date_posted = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return shorten(self.title)

For templates, Django already has a |truncatechars template filter. So if you plan to render this in a template, there is no need to implement this logic in the model. You can render the title then with:

{{ mypost.title|truncatechars:167 }}

This makes more sense, since a Django model should not be concerned with how to render data, a model deals with storing, and modifying data.


Note: It is normally better to make use of the settings.AUTH_USER_MODEL [Django-doc] to refer to the user model, than to use the User model [Django-doc] directly. For more information you can see the referencing the User model section of the documentation.


Note: Django's DateTimeField [Django-doc] has a auto_now_add=… parameter [Django-doc] to work with timestamps. This will automatically assign the current datetime when creating the object, and mark it as non-editable (editable=False), such that it does not appear in ModelForms by default.

Upvotes: 1

Related Questions