Use object variable in base.html of Django - django

I come from Ruby on Rails and I am trying to learn Django. There are multiple things that puzzle me when it comes to how to solve simple things. I have a sidebar in which I would like to have a link to a random item.
My first thought was to use:
Random headline
Although it works perfectly fine to run Headline.objects.order_by('?')[0].id in the shell, this causes an error in Django:
Could not parse the remainder: '('?')[0].id' from 'Headline.objects.order_by('?')[0].id'
which I find very weird since 'Headline.objects.order_by('?')[0].id' creates a number (id) and if I put the same number in as
Random headline
it works perfectly fine.
Another option would be to create this previously in the template, like
{% rand_id = Headline.objects.order_by('?')[0].id %}
Random headline
which is I would hotfix it in Rails - but this doesn't work. The third option (which is better than the 2nd) is to put the variable in the view. However, this is not really viable since this code is in the sidebar and I cannot pass this in every view (DRY!).
So, I figure out I should use context templates, which I - after reading up on it find overly complicated for something as simple as this.
Is there really no good, simple way to solve this problem? Or am I "thinking too much rails"?

In your case a custom template tag would be just fine.
https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/#writing-custom-template-tags
from django import template
from django.utils.html import format_html
register = template.Library()
#register.simple_tag
def random_headline_link():
random_headline = Headline.objects.order_by('?')[0]
headline_url = reverse('headline_detail', args=[random_headline.id,])
return format_html('Random headline', url=headline_url)
{% random_headline_link %}
<!-- the rest is not needed anymore, as it is all coupled together in the templatetag -->
Or if you only like/need the URL, you could use the following templatetag code.
from django import template
register = template.Library()
#register.simple_tag
def random_headline_url():
random_headline = Headline.objects.order_by('?')[0]
return reverse('headline_detail', args=[random_headline.id,])
Random headline

Related

Django: a custom template tag to convert links inside of a TextField and change the hyperlink text

The scenario is that there are some dynamic texts on some templates, that will contain hyperlinks.
For this, I have a SiteDataKeyValue model, in which the dynamic texts for different parts of the template are inputted. This is the model:
class SiteDataKeyValue(models.Model):
key = models.CharField(
max_length=200, verbose_name="نام متن مورد نظر", unique=True
)
value = models.TextField(verbose_name="متن")
def __str__(self):
return self.key
A solution that I've found already, is Django urlize template tag. As mentioned in the docs, this tag converts texts like https://www.google.com to www.google.com, which is nice but not what I'd like to achieve. I want to be able to change the hyperlink text, so the output would be something like: Click Here!.
I searched for a bit, came across modules like bleach, which is a fine module, but I couldn't find the answer I was looking for (I skimmed through the docs and there was nothing about the hyperlink text).
Also I saw a comment somewhere telling that this could be achieved by writing a custom Django template tag, but although I tried to do this regarding the custom template filters docs, I didn't have a clue to how to achieve this.
I'm not asking for the code, although it would be really appreciated if you provide instructions for writing this custom template tag, or better, if you could point me to something like this that is already out there.
First of all you can extend urlize tag like the answer in this
or you can change the main code which you can find it in django.utils.html and override its url variable to change it.
But I think the best method is extending the urlize tag
like this:
{% text | urlize | change_a_text_filter:{{ dome_new_a_text }} %}
then you can scrape the text and use regex to find >sample-text</a> then you can change it to the argument that defines in your tag
from django import template
register = template.Library()
#register.simple_tag
def change_a_text_filter(format_string, arg):
# find the url that made in urlize with regex
# change it with arg
# return the result
I was on a completely wrong road to solve this problem. I was trying to urlize a link from TextField, but didn't consider the fact that I only needed to implement html code as Visit link.com! in the TextField, and then use safe template tag to render html directly as below:
{{ text.value|safe }}
So in this solution, there is no need to urlize, and of course there is no need to extend this tag neither.
NOTE: As commented by #rahimz (link to comment) I understand that there are safety concerns regarding safe tag, So I should emphasize that only me and a company-trusted admin will have access to admin panel and there is no worries that this admin will send malicious code through this TextField.

Detect URLs and #tags in Django CharField and add style to it

For now on I have in my template a paragraph like this <p class="...">{{ post.content }}</p> and if this Post's content contains a link or #hashtag it is rendered as a normal text with the rest of the post. How can I customize it? For example change text-color and add tag around it?
As I said in comment, you can use custom tag filter to wrap your content, and use Regular Expression to generate links and hashtags
Create your tags file, and name it as you want:
tag_filter_name.py
If you're not familiar with custom tag filter creation, you can learn more about it in the Official Documentation
from django import template
import re
register = template.Library()
def generate_link(link):
return '<a class="link" href="{}">{}</a>'.format(link, link)
def generate_hashtag_link(tag):
# Free to configuree the URL the way adapted your project
url = "/tags/{}/".format(tag)
return '<a class="hashtag" href="{}">#{}</a>'.format(url, tag)
And then, you create the function what will be used as tag filter
#register.filter
def render_content(obj):
text = re.sub(r"#(\w+)", lambda m: generate_hashtag_link(m.group(1)),obj)
return re.sub(r"(?P<url>https?://[^\s]+)", lambda m: generate_link(m.group(1)),text)
If you want Django to mark it as safe content, you can do the following:
from django.utils.safestring import mark_safe # import function
''' function codes here '''
return mark_safe(re.sub(r"(?Phttps?://[^\s]+)",
lambda m: generate_link(m.group(1)),text))
And finally, to use it in your template, don't forget to load it
{% load tag_filter_name %}
{{ post.content|render_content }}
Best way: custom tag filters here is the docs URL
https://docs.djangoproject.com/en/2.2/ref/templates/builtins/
Good way: If you know JS create a function that handles the formatting on the front end
in HTML:
onload="myfunction("{{post.content}}")"
in JS sort for the string containing the # wrap it in a span or other element and style away. then replace the inner HTML with your new formatted piece. This will save rendering time on the server and also frees you up from having to loop thru the list of posts in the view
Ok way: not preferred but if you hate js and only want to work in python (understandable). You need to loop through the list of posts separate out the items of the post format them the way you like with inline style. then add them to a new object that you will append to the end of a new list of posts that you will then pass thru to context. This is a real pain please don't do this if you can help it at all.
the tag filters are awsome take advantage but if they won't work for your use case I would highly advise using vanilla JS

How to Pass a Python Variable to a Template in another app in Django

I have views in app_1 which returns a dictionary and I want to pass it in the html in another app called app_2. I tried using {{dic_name.value_1}} and also like {{app_name:dic_name.value_1}}, but it didn't work.
-app_1
--urls.py
--views.py
-app_2
--templates
--app_2
-- app_2.html
my view in app_1
def index(request):
user_info={}
user_info['name']= 'joe'
user_info['age'] = 23
return JsonResponse(user_info)
my Html in app2 is like
<body>
<h1>Name</h1>: {{user_info.name}}
<h1>Ange</h1>: {{user_info.age}}
</body>
Can anyone help to solve this problem. Thanks
First a couple comments:
I have views in app_1 which returns a dictionary
Nope, it returns an HTTP response (with json content and application/json as content-type).
and I want to pass it in the html in another app called app_2.
That's just not how it works. A Django view returns a HTTP response, period (wether the response's body contains HTML and wether this HTML has been built using a template are totally irrelevant here).
I tried using {{dic_name.value_1}} and also like {{app_name:dic_name.value_1}}, but it didn't work.
Programming by accident never really works. You'll get better results - and you'll get them faster - by understanding how things work and do the right thing right from the start.
NB : Sorry if this looks a bit patronizing, please don't take it as a personal offense, I'm really trying to help you with those comments.
Now for the proper answer:
For the general case, when you have a piece of data (an object, a list, a dict, whatever) that you want to make accessible to different unrelated templates, you mainly have two solution:
a context processor
a custom templatetag
A context processor will be invoked for all templates rendering (well, almost, cf the doc), so it's the right solution when you want this "piece of data" to be available everywhere "out of the box". The downside is that you'll get a performance hit for each and every template. Also, a context processor only has access to the request - it can't access the template's context.
A custom templatetag is only executed when called from a template, so it's a better option if the "piece of data" you want is costly to build and is only used in a few templates. Also it can take arguments from the template, including the full context.
From a maintainability / reusability POV, whether you go for a processor or templatetag, it's usually better to factor out the code producing the desired value(s) into a dedicated utility function and to call that functions from the processor or tag.
In your case, your app_1.views.index_view returns a JsonResponse, so factoring out this part of code is indeed the best solution:
app_1/utils.py:
def get_user_info():
return {"name": "Joe", "age": 42}
app_1/views.py:
from app_1.utils import get_user_info
def index(request):
user_info = get_user_info()
return JsonResponse(user_info)
app_1/templatags/app_1.py:
# you'll need this if using python 2.7.x
# else the import will fail
from __future__ import absolute_imports
from django import template
from app_1.utils import get_user_info
register = template.Library()
#register.simple_tag
def user_info():
return get_user_info()
app2 template.html
{% load user_info from app_1 %}
{% user_info as ui %}
<dl>
<dt>Name</dt><dd>{{ ui.name }}</dd>
<dt>Age</dt><dd>{{ ui.age }}</dd>
</dl>
This is of course a dumbed down example (and it might have a couple bugs, as all made up examples) and your real code will certainly be a bit more involved, but this should at least get you started.

Django/Haystack - best option to have a listview with search capability

I have an app with a Restaurant model. I'd like to understand what is the best way to put together a view that displays the list of restaurant objects, but also has a search form above that a user could enter parameters to filter the results displayed. If no parameters are entered, all the restaurants should be shown. I'm already using haystack and have a search form, but currently it is on a standalone search.html template. I also have an ListView on a separate template, and I guess I'm looking for an end result that combines these.
I did some reading on line and it's unclear what the best way to do it is:
using just listview from Django with some queryset filtering
combining haystack SearchView with django class based views?
this is my best bet so far - creating a customized version of SearchView from Haystack
ideally, ultimately the search capabilities would include things like allow autocompleting the user's inputs, and dynamically filter the results as the user types.
any thoughts on what the best way is to go about this and any examples out there?
There probably is out there some package that gives you everything automatically, displaying the queryset list and allowing simple adding of a search bar and so on (like the admin site). But I take it you are still a beginner to web development, so I'd strongly suggest you drop the listviews, drop haystack, drop everything, and do it all yourself.
See, they're not bad approaches or anything, but they're like shortcuts. And shortcuts are good only if they shorten the original way, which in your case isn't all that long.
To give you an example, here's a simple approach to displaying a list of items:
views.py
def restaraunt_list(request):
restaraunts = Restaraunt.objects.all().order_by('name')[:100] # Just for example purposes. You can order them how you'd like, and you probably want to add pagination instead of limiting the view number arbitrarily
context = {'restaraunts': restaraunts}
return render_to_response('index.html', context)
index.html:
<ul>
{% for rest in restaraunts %}
<li>{{ rest }}</li>
{% endfor %}
</ul>
That's it. Now it displays it in a list. Now to add a search filter all you need to do is this:
index.html (add this anywhere you want it)
<form>
<input type='text' name='q' id='q'></input>
<input type='submit' value='search!'></input>
</form>
When a user sends the data from 'q' it is sent through GET, and then on server side you add this:
def restaraunt_list(request):
restaraunts = Restaraunt.objects.all()
# filter results!
if request.method == 'GET':
q = request.GET['q']
if q != '':
restaraunts = restaraunts.filter(name__contains=q)
# ordering is the last thing you do
restaraunts = restaraunts.order_by('name')[:100]
context = {'restaraunts': restaraunts}
return render_to_response('index.html', context)
Now, this will work, but from what you wrote I understand you want the search to be live the moment a key is pressed. For that, you'd need to use AJAX (go learn how it works, I'm not gonna delve into it here). As for autocomplete, you should check out jQuery UI.
But, like I said, before jumping ahead and using all those stuff, I suggest you first learn the basics. Go through the django tutorial (if you haven't already), and use the amazingly detailed django-docs every step of the way. When some specific things won't work and you're stuck, come here to Stackoverflow and someone will surely help you. good luck!

Putting links in list_detail.object_list to list_detail.object_detail

I've started using Django and am going right to generic views. Great architecture! Well, the documents are great, but for the absolute beginner it is a bit like unix docs, where they make the most sense when you already know what you're doing. I've looked about and cannot find this specifically, which is, how do you set up an object_list template so that you can click on an entry in the rendered screen and get the object_detail?
The following is working. The reason I'm asking is to see if I am taking a reasonable route or is there some better, more Djangoish way to do this?
I've got a model which has a unicode defined so that I can identify my database entries in a human readable form. I want to click on a link in the object_list generated page to get to the object_detail page. I understand that a good way to do this is to create a system where the url for the detail looks like http://www.example.com/xxx/5/ which would call up the detail page for row 5 in the database. So, I just came up with the following, and my question is am I on the right track?
I made a template page for the list view that contains the following:
<ul>
{% for aninpatient in object_list %}
<li><a href='/inpatient-detail/{{ aninpatient.id }}/'>{{ aninpatient }}</a></li>
{% endfor %}
</ul>
Here, object_list comes from the list_detail.object_list generic view. The for loop steps through the object list object_list. In each line I create an anchor in html that references the desired href, "/inpatient-detail/nn/", where nn is the id field of each of the rows in the database table. The displayed link is the unicode string which is therefore a clickable link. I've set up templates and this works just fine.
So, am I going in the right direction? It looks like it will be straightforward to extend this to be able to put edit and delete links in the template as well.
Is there a generic view that takes advantage of the model to create the detail page? I used ModelForm helper from django.forms to make the form object, which was great for creating the input form (with automatic validation! wow that was cool!), so is there something like that for creating the detail view page?
Steve
If you're on django < 1.3 then what you are doing is basically perfect. Those generic views are quite good for quickly creating pages. If you're on django 1.3 you'll want to use the class based generic views. Once you get a handle on those they are are crazy good.
Only note I have is that you should use {% url %} tags in your templates instead of hardcoding urls. In your urls.conf file(s) define named urls like:
url('inpatient-detail/(?P<inpatient_id>\d+)/$', 'your_view', name='inpatient_detail')
and in your template (for django < 1.3):
...
In 1.3 a new url tag is available that improves life even more.