2

In Python Crash Course chapter 18 we make a Learning Log website.

I can't make this return just the first 50 characters of a >50 character long entry when I go into the Learning Log website that we make (through localhost:8000). It doesn't show the ellipsis either, it just shows the whole entry.

from django.db import models
from django.contrib.auth.models import User

class Topic(models.Model):
    """A topic the user is learning about"""
    text = models.CharField(max_length=200)
    date_added = models.DateTimeField(auto_now_add=True)
    owner = models.ForeignKey(User, on_delete=models.CASCADE)

    def __str__(self):
        """Return a string representation of the model."""
        return str(self.text)

class Entry(models.Model):
    """Something specific learned about a topic"""
    topic = models.ForeignKey(Topic, on_delete=models.PROTECT)
    text = models.TextField()
    date_added = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name_plural = 'entries'

    def __str__(self):
        """Return a string representation of the model."""
        if len(self.text) > 50:
            return f"{str(self.text)[:50]}..."
        else:
            return f"{str(self.text)}"

It is the same whether I include the if len(self.text) > 50 statement or not. My code differs somewhat from the book in that:

  1. I use on_delete=models.PROTECT, as I understand that CASCADE can cause weird issues like accidentally getting something deleted that you didn't intend to delete
  2. I use str(self.text) instead of just self.text in the __str__ definitions; if I don't it raises a pylint error "Value 'self.text' is unsubscriptable". I can still make entries without the str() conversion - it still won't show only the first 50 characters however.

Is it something about how models.TextField() function that causes this? Am I supposed to have to do the str() conversions to make the self.text variable "subscriptable"?

fuffens1
  • 23
  • 3
  • returning from the `__str__` method will not help you. it's only for the viewing purpose for e.g if you try to see that instance on python shell it will truncate the output of `self.text` to 50 characters. – Vishal Singh Jun 27 '20 at 19:58
  • So what is sent to the webpage has nothing to do with the __str__ method, it is rather what precedes it like the topic, text, date_added variables, is that correct? – fuffens1 Jun 28 '20 at 20:04

4 Answers4

2

In Django 3.0 models.TextField returns a string(str) if you call it as self.text or Entry.text. So you don't need to call str() function.

If you want to get first 50 characters:

def __str__(self):
    return self.text[:50]

In Python if you use [:50] for a subscriptable object, it will return first 50 parts (or all if it have less than 50 parts) of the object.

I wish my answer helps you.

mhn2
  • 119
  • 9
  • I suppose that is different from how Django used to work? I couldn't find that specific change in the changelog for Django 3.0, but in this post from 2 years ago it seems like Django then wouldn't treat that as a string. https://stackoverflow.com/questions/48810094/django-model-foreignkey-and-return-self-text-errors#comment93040755_48816824 I tried your suggestion prior to posting this, it still showed the whole text. I suppose the issue lies in that this is not what gets sent to the webpage, but rather what would be shown in a Python shell, as other users have suggested? – fuffens1 Jun 28 '20 at 20:02
0

According to what I see you can just say

def __str__(self):
    return self.text[:50]

but also

You can use truncate word filter when calling it in the HTML form

You did not show the views.py but say you have a view that returns to a page all the Entries in the Entry Class you and you happen to say {% for Entry in Entries %} you would just add

{{ Entry:text|truncatewords:50 }}

{% endfor %}

you can learn more at The Docs

casualhuman
  • 163
  • 14
0

Also you can do this:

def __str__(self):
    if self.text[50:]:
        return f"{self.text[:50]}..."
    else:
        return f"{self.text[:50]}"
Semen
  • 1
  • 1
0
def __str__(self):
        """Return a string representation of the model."""
        if len(self.text) > 50:
            return f"{str(self.text)[:50]}..."
        else:
            return f"{str(self.text)}"

This function gives you the first 50 characters, please remove and run your program. Textfield support unlimited text in this field.

Young
  • 536
  • 2
  • 19