I want to have SEO-friendly URL,my current url in urls.py :
(ur'^company/news/(?P<news_title>.*)/(?P<news_id>\d+)/$','CompanyHub.views.getNews')
I use it in template:
{% for n in news %}
<a href="{% url CompanyHub.views.getNews n.title,n.pk %}" >{{n.description}}</a>
{% endfor %}
I use news_id to get news object with that PK .
I want to convert this url:
../company/news/tile of news,with comma/11
to:
../company/news/tile-of-news-with-comma/11
by doing some thing like this in template:
{% for n in news %}
<a href="{% url CompanyHub.views.getNews slugify(n.title),n.pk %}" >{{n.description}}</a>
{% endfor %}
I checked out these questions:
question1
question2
question3 and this article but they save an slugify field in database while I wanna generate it on demand.in addition I want to run a query by news_id.
I think this question is good,but I don't know how to use news_id to fetch my news object
This will generate the needed url:
{% for n in news %}
<a href="{% url CompanyHub.views.getNews n.title|slugify n.pk %}" >{{n.description}}</a>
{% endfor %}
The examples above save slugify_field in database, as they later search for it. Otherwise in database you'll have a normal title, and slugified title in code for searching.. No easy way to compare them. But the way you've explained is simpler. You will have this kind of view:
def news(request, slug, news_id):
news = News.objects.filter(pk=news_id)
UPDATE: To use unicode symbols in slugify, you'll need a conversion first. Look at this: How to make Django slugify work properly with Unicode strings?. It uses the Unidecode library
Then add a custom filter:
from unidecode import unidecode
from django.template.defaultfilters import slugify
def slug(value):
return slugify(unidecode(value))
register.filter('slug', slug)
then in your template use this:
{% load mytags %}
<a href="{% url CompanyHub.views.getNews n.title|slug n.pk %}
Here is an example:
{{ "影師嗎 1 2 3"|slug}}
renders as:
ying-shi-ma-1-2-3
Have you tried n.title|slugify and see if that works for you.
ref: https://docs.djangoproject.com/en/dev/ref/templates/builtins/?from=olddocs#slugify
Note: although this is possible, just make sure the 'slugified' element is never used for any part of routing... (ie, purely for display only)
Related
I have a rank.html which is a publicly sharing template for many other templates through {% include rank.html %} method.
This template will display the 48 hours hot news base on the click number.
Here is the view.py:
def rank(self, request):
hot_news_48h = h_mostViewed(48, News, '-pv')
return render(request, "rank.html", {
'hot_news_48h': hot_news_48h,})
h_mostViewed(48, News, '-pv') is a function,that can fetch most viewed(clicked) post within 48 hours.It works.
Here is the rank.html:
<ul>
{% for hot_view in hot_news_48h %}
<li>
<a href="{% url 'news:news_detail' hot_view.pk %}" >
<img src="{{ MEDIA_URL }}{{ hot_view.image }}" >
</a>
<a href="{% url 'news:news_detail' hot_view.pk %}">
<h6>{{ hot_view.title }}</h6>
</a>
</div>
</li>
{% endfor %}
</ul>
Here is the url.py:
path('hot_news', views.rank, name="hot_news")
The problem is,I can only get the html ,but can't receive the data.
But if I give up {% include rank.html %} method and insert the rank.html's code directly inside each template which need this function, I can get the data.
Take new_detail.html template as an example:
Here is the view.py:
def newsDetailView(request, news_pk):
news = get_object_or_404(News, id=news_pk)
all_comments = NewsComments.objects.filter(news=news)
news.comment_nums = all_comments.count()
news.save()
News.objects.filter(id=news_pk).update(pv=F('pv') + 1)
hot_news_48h = h_mostViewed(48, News, '-pv')
relative_news = News.objects.filter(tag__id__in=news.tag.all()).exclude(id=news_pk)[:6]
return render(request, "news_detail.html", {
'news': news,
'all_comments': all_comments,
'hot_news_48h': hot_news_48h,
'relative_news': relative_news
})
Here is the urls.py:
path('-<int:news_pk>', views.newsDetailView, name="news_detail"),
So above,I directly inserted rank.html's code into new_detail.html and it works I can get the data.
My question is what should I do or correct,so that I can get the data in {% include rank.html %} method. Because {% include rank.html %} is simple and flexible.I don't want to repeat the same code in several same template.
Thank you so much for your patience!
How about this:
- Create a folder "templatetags" in your application and add a file "news_tags.py" or name it what you want. Then you can define the tags you need:
from django.template import Library
from your_app.models import your_model
register = Library()
#register.inclusion_tag('your_app/your_template.html')
def hot_news(num, order):
objects = News.objects.order_by(order)[:num]
result['objects'] = objects
return result
In your templates you then do the following:
{% load news_tags %}
{% hot_news 48 '-pv' %}
Then create a template as your already did and reference it in the inclusion tag. Then it should work properly.
If you want it to work for multiple models you can have a look at this: https://docs.djangoproject.com/el/2.1/ref/applications/
The apps framework allows you to fetch models from a string input.
I finally solved the issue by Creating custom context processor.https://www.youtube.com/watch?v=QTgkGBjjVYM
I'm doing some pagination in Django. I want to show the pages' number which are ahead of the current page. I am using the following code:
{% for page in blogs_page.paginator.page_range|slice:"0:{{ blogs_page.number }}" %}
But this seems useless; the result does the same as the following:
{% for page in blogs_page.paginator.page_range %}
The slice does not work here. How do I fix this?
Never use {{ }} inside of {% %}, don't do this {% {{ }} %}.
{% for page in blogs_page.paginator.page_range|slice:"0:blogs_page.number" %}
I think it won't work. If I were you I would create a custom tag and executed all the logic there. So, it will look like this:
Template:
{% custom_tag blogs_page as result %}
{% for page in result %}
templatetags/tags.py:
from django import template
register = template.Library()
#register.simple_tag
def custom_tag(bl_page):
return bl.page.paginator.page_range[0:bl_page.number]
Details: custom tags
I am using Django and developing an i18n site serving many languages. I want to make a modal that stays in base.html, so that users can switch the language wherever they are.
I managed to do something like this.
<div class="modal-body">
{% get_available_languages as languages %}
{% for lang_code, lang_name in languages %}
{% language lang_code %}
{{lang_code|lang_name}}
{% endlanguage %}
{% endfor %}
</div>
Which turns out urls like:/ja/, /en/, /fr/, etc..
but this kind of approach links to the main page only.
When using {{request.path}} or {{request.get_full_path}} for the url like:
{{lang_code|lang_name}}
It doesn't include the i18n url patterns..
Is there any way for directing current url with request.path??
TARGET
When in /foo/ : /ja/foo/ /en/foo/ /fr/foo/
When in /bar/ : /ja/bar/ /en/bar/ /fr/bar/
Thanks in advance!
This topic is discussed in this SO question: Django templates: Get current URL in another language.
In my project, I use this simple template tag (taken from https://djangosnippets.org/snippets/2875/), which returns the URL of the current view in another language.
foo/templatetags/i18n_urls.py:
from django import template
from django.urls import translate_url
register = template.Library()
#register.simple_tag(takes_context=True)
def change_lang(context, lang: str, *args, **kwargs):
path = context['request'].path
return translate_url(path, lang)
some_template.html:
{% load i18n_urls %}
<ul>
<li>
EN
</li>
<li>
CS
</li>
<li>
DE
</li>
</ul>
Please note that translate_url function is not documented in the official Django docs. Here is the source code of this function: https://github.com/django/django/blob/master/django/urls/base.py#L161-L181.
I'm trying to figure out if there is a way to extend a partial view into a view that already extends base.html.
Here is an example of what I'm trying to do:
my-template.html
{% extends 'base.html '%}
<div class="row">
<div class="col-xs-12">
<ul class="nav nav-tabs">
<li role="presentation" class="active">Tab1</li>
<li role="presentation">Tab2</li>
</ul>
</div>
</div>
<div>
{% block tab_content %}
{% endblock %}
</div>
partial1.html
{% extends 'my-template.html' %}
{% block tab_content %}
<h1>I'm partial 1</h1>
{% endblock %}
The my-template.html view has a url that is constructed like so:
url(r'^my-template/(?P<id>[0-9]+)/$', views.my_template_view, name='my-template')
in addition a context dict is passed into the my_template_view providing the id for the url.
I would like the for the user to click on a tab and for its corresponding partial to be rendered with a url like so:
url(r'^my-template/(?P<id>[0-9]+)/tab1/$', views.tab1_view, name='tab1-view')
but right now I'm getting a NoReverseMatch at /my-template/97/tab1/ which I'm assuming means that my tab1_view doesn't have access to the same context as the my_template_view and thus can't get the id to build the reverse of my url.
In template /partial1.html, error at line 0
Reverse for 'tab1_view' with arguments '('',)' and keyword arguments '{}' not found. 1 pattern(s) tried: ['/my-template/(?P<id>[0-9]+)/tab1/$']
So, is there a way for me, at the very least, to pass along the context or the id so this works, or am i going about this in the entirely wrong way?
The typical way to solve this is by using the include template tag, not by extending with a new template.
Here is the Django doc describing this.
You can even use a variable to define a dynamic template name that will be included based on logic in your view.
Little more clarification here:
You can also have the URL route direct to the same view and have the "tab" optionally passed in as a second parameter as so:
url(r'^my-template/(?P<id>[0-9]+)/(?P<tab_name>\w+)/$', views.my_template_view, name='my-template')
url(r'^my-template/(?P<id>[0-9]+)/$', views.my_template_view, name='my-template')
And your view would look something like:
def my_template_view(request, id, tab_name=None):
if not tab_name:
tab_name = "tab1"
if tab_name == "tab1":
partial = "tab1.django.html"
elif tab_name == "tab2":
partial = "tab2.django.html"
return render("my-template.html", { 'partial': partial })
And on your template you would have:
{% include partial %}
Because the included template will have the same context, you will have access to any variables that were available in the original context as well.
EDIT 2020/09/04: As noted in a comment below, the above page no longer exists. I've updated the above link to the latest in the 1.11 branch, but for the latest version of Django (3.1 as of this edit) you can refer to the same doc here.
I've a Django template like this:
<ul>
{% for url in urls %}
<li>{{ url.url_title }}</li>
{% endfor %}
</ul>
Url is a model that stores Url name and Url title of that particular url. I thought by using this template, I might be able to open the page and get redirected to the external url specified in:
<a href="{{ url.url_name }}">
Turns out, I can't. How do I achieve this? I'm a newbie in Django and don't know what to do.
I supposed url_name is Charfield type, and it is something like example.com or starting with http or https, for all above cases, the below worked for me:
<a href="http://{{ url.url_name }}">
If you used URL type for the url_name, then your solution should work and your problem is not with tag.
Please, try with:
<a href="{{ url.url_name }}" target="_self">