I am making a social networking site, and I want to be able to mention users or categories by using the # symbol. (Example: #User #Category #Other Category). Using a template filter, I want to first find all the # in the string, and then get the word after it. Then I would check in the models for categories:
class Category(models.Model):
name = models.CharField(max_length=250, unique=True)
category_detail = models.TextField(max_length=1250, default='No information is known on this category.')
And if it does not match a category I would check if the word after the # is a user. If It is a category, I want to link it using the <a>
tag, and if it is a user I also want to link it using the <a>
tag.
The urls:
urlpatterns = [
path('u/@<str:username>', UserPostListView.as_view(), name='user-posts'), # User Profile Link. Link This If After The # The Word Is A User
path('c/<str:cats>/', views.category_view, name='category-detail'), # View Category Link. Link This If After The # The Word Is A Category
]
Usage: Going back to the example, let's say I have a comment like this:
This is such a great post! #some_user #category #other_category
And in my template I render it like:
{{ comment.text|safe|filter_to_parse }}
I want the template filter filter_to_parse
to return:
This is such a great post! <a href="/u/@some_user">#some_user</a> <a href="/c/category">#category</a> <a href="/c/other_category">#other_category</a>
So how would I make a template filter in Django to do this?
I have found some things that would've helped me do this:
But the code from these links don't work. Thanks.
Edit 2: Ok so thanks to @flaunder, I have added mark_safe and tried to debug the filter. Here's the working code I have so far:
from django import template
from django.template.defaultfilters import stringfilter
from django.contrib.auth.models import User
from django.utils.safestring import mark_safe
register = template.Library()
@register.filter(name='mention', is_safe=True)
@stringfilter
def mention(value):
my_list = value.split()
for i in my_list:
if i[0] == '@':
try:
stng = i[1:]
user = User.objects.get(username=stng)
if user:
profile_link = user.userprofile.get_absolute_url()
i = f"<a href='{profile_link}'>{i}</a>"
res = res + i + ' '
return mark_safe(res)
except User.DoesNotExist:
return value
else:
return value
This worked and in the templates it has a link to the user profile, but the rest of the comment is missing. Example: "@da hi!" became "@da", with no hi! This is because it returns res, which is the tag and a space, so I need help returning the rest of the comment too.
The other problem with this code is that if you are mentioning multiple users like @da @user2, then only the first user becomes a url and the rest are just text.
this is fully untested code, but to get you going: def mention(original): listAts = list()
for i in my_list:
if i[0] == '@':
try:
stng = i[1:]
user = User.objects.get(username = stng)
if user:
profile_link = user.userprofile.get_absolute_url()
i = f"<a href='{profile_link}'>{i}</a>"
except User.DoesNotExist:
print("Could not get the data")