Is there a simple django tag to get the first x characters of a string in a template?
In a list of modelinstances, I would like to give a different symbol per objectinstance, depending on the status of the objectinstance. Status could be 'waiting', 'success' or 'failed XXXX', with XXXX being the errorcode.
I would like to check if the first 5 characters of objectinstance.status == 'error', then the symbol will be red. However, how can I do this? In Python I could use objectinstance.status[:5].
Using https://docs.djangoproject.com/en/dev/ref/templates/builtins/ I managed to do this with following 'monstruous' concatenation, but is there something simple as .left() or .right()?
{% if run.status|make_list|slice:":5"|join:"" == 'error' %}
You could try:
{% if run.status|truncatechars:5 == 'error...' %}
(See truncatechars in the Django docs)
Although I might say, as an overall point, you shouldn't be putting this kind of logic in your Django templates (views in other frameworks). You want to put this into the Django view (controller in other framerworks). Meaning, you would something like this in your view:
has_error = run.status.startswith('error')
Ensure has_error is passed to the template and:
{% if has_error %}
It may be more work, but the logic to detect error conditions could be shared between multiple views and templates, and you separate control logic from view logic.
If you use Django 1.4+ you can use the truncatechars tag but it will only solve partially your answer and will add ellipsis at the end.
The only viable way, a part from concatenating many filters as you already did, is to write a custom filter. Here is a first draft you can customize:
from django import template
from django.template.defaultfilters import stringfilter
register = template.Library()
#register.filter
#stringfilter
def slicestring(value, arg):
"""usage: "mylongstring"|slicestring:"2:4" """
els = map(int, arg.split(':'))
return value[els[0]:els[1]]
as a bonus this filter allows you to mimic almost completely the slice notation by providing a "slicing string" as the argument. The only exception seems the syntax [:9] that has to be replaced with [0:9], thus with this argument: yourvariable|slicestring:"0:9"
A side note: Since your question is "getting the first part of a string" I believe a custom filter may be the correct answer, however if the only reason to get a sliced string is to check for a part of it inside an if statement, then I have to agree with Anton: you should place your checks inside the view, not inside the template, when possible.
Related
I am working on a Django Project, and I want the User to be able to add the code in the .py file. Well, I have .py file that contains some code, and in the mid of code I have some lines of code that specify some rules for Fuzzy Logic Algorithm, such as below:
...
rule1 = scikit-fuzzy.control.Rule(input1["bad"] & input2["bad"] & input3["bad"] & input4["bad"] & input5["average"], output["poor"])
...
So, I have total 243 lines of codes (in other words rules) like the above centered between some code (that is above it and below it there some other code). Now, I want Admin to be able to edit and update these lines of codes in a way that, using Forms I will take the inputs from the Admin (such as: 'good', 'bad', 'average', 'bad', 'good', 'poor', and I want the system to create a new line of code taking these strings as inputs.
If admin enters: 'good', 'bad', 'average', 'bad', 'good', 'poor', I want the .py to have a new line after the 243r line which should be like this:
rule243 = #
rule244 = scikit-fuzzy.control.Rule(input1["good"] & input2["bad"] & input3["average"] & input4["bad"] & input5["good"], output["poor"]
Can anyone help me in this?
Actually this should be doable, I've a solution in mind, Let's implement it
Take caution
This requires HIGH verification and because this is python code, You don't want to give the admin all the rights to execute ANY python code from the admin page. If the admin details gets hijacked, You're ##!$#ED.
Let's analyze the problem into smaller problems.
Big point
We want to execute code from admin page
Smaller points
We need to put multiple rules, and they are uncountable, A perfect job for a database model
We will think of the code as Rule object. we will think of the dictionary key as a RuleKey object. we will think of input or output as RuleType
In your case, input1['good'] is the same as RuleTypeX[RuleKey] where x is an Integer starting from 1.
We will think of the RuleKey as many-to-many relation with the Rule, The Rule can has many RuleKey objects and those RuleKey objects can exist in different Rule objects.
THING TO CONSIDER
Verification is very important, YOU DON'T WANT SOMEONE PASSING eval() IN YOUR CODE AND EXECUTE WHATEVER HE WANTS.
I've created this REGEXP to match your code
scikit-fuzzy\.control\.Rule\(\s?((input[0-9]+\[("|')(poor|good|average|bad|whatever)("|')\])\s?&?\s?)+,?\s?(output[0-9]*\[("|')(poor|good|average|bad|whatever)("|')\])+\s?\)
Took a lot of time lol, Tested on Regexr, This matches your code well, paste your code there and test to see, feel free to improve it, this is not the main focus here.
class RuleKey(models.Model):
class TYPES(models.IntegerChoices):
INPUT = 0
OUTPUT = 1
content = models.CharField(max_length=10)
type = models.IntegerField(choices=TYPES.choices) # choices are of type Integer, the field must also be Integer
def __str__(self):
return self.content
content will contain any of ['poor', 'good', 'whatever'] and type will be 0 for Input and 1 for Output and I MEANT TO TYPE IT CAPITALIZED because we need to solve the caps problem too.
We have a function to check if the final code is valid before evaluating it.
def valid_python_code(code):
if re.match(valid_code_pattern, code):
return True
return False
Don't use the stupid RegexValidator that django provides, It raises an Exception if it didn't match but IT RETURNS NONE IF IT MATCHES, makes no sense for me, or use it, whatever.
When we run code, We're 'executing' it and this is the formal word for running code.
class Rule(models.Model):
keys = models.ManyToManyField('RuleKey', related_name='rules')
wasExecutedBefore = models.BooleanField(default=False) # ran before or no
def execute(self):
if self.wasExecutedBefore:
return None
input_keys = self.keys.filter(type=0)
output_keys = self.keys.filter(type=1)
"""
Can't use f-strings as we're evaluating genexps here, note the key.type, In a production environment
This should be RuleKey.TYPES.INPUT or RuleKey.TYPES.OUTPUT, just swap the places of the classes, I'm lazy to do that
"""
code = "scikit-fuzzy.control.Rule({inputs}, {outputs})".format(
inputs=''.join(
f"{key.get_type_display().lower()}{i + 1}['{key.content}']" for i, key in enumerate(input_keys) if
key.type == 0),
outputs=''.join(
f"{key.get_type_display().lower()}{j + 1}['{key.content}']" for j, key in enumerate(output_keys) if
key.type == 1))
if valid_python_code(code):
return eval(code)
else:
raise ValueError('Invalid code or missing libs or whatever.')
Lemme comment here the problems I tackled when implementing this.
RuleKey.TYPES is an IntegerChoices class, Django takes the attributes and capitalizes the first letter and returns it, Your code needs input and not Input , fortunately we have str.lower()
The second problem is that a regular for-in loop doesn't have a counter when looping objects other than range objects, We will use enumerate instead.
The third problem is that f-strings introduced in Python-3.6 (Not sure of 3.6) don't support GENEXPS inside, You have to use .format()
The fourth problem is that when using a GENEXP directly inside format instead of using ''.join(GENEXP), You'll print the lazy version of it i.e <generator object at 0x214312>
Don't try to use keys = keys.objects.all() and do this in one query, The problem you'll face will be related to the foor loop counter
Don't use RuleKey.type, this returns the integer, You need to call django's get_foo_display and in this case it's get_type_display()
Let's illustrate
I'll name my variables on the following format, class_type_content
keys = [key_1_poor, key_0_good, key_1_average]
let's loop and filter
for key in keys: # no count
pass
let's enumerate
for i, item in enumerate(keys):
print(i) # prints index
print(item) # prints object
now for the .all() part, If you tried to iterate .all(), You'll succeed, however, If your input started with input1, Your output will start with output2 and this is because both are in the same Queryset object.
Now, Add this to your admin page, perhaps as a button.
# admin.py
class RuleAdmin(admin.ModelAdmin):
def response_change(self, request, rule_obj):
if "execute" in request.POST:
try:
obj.execute() # execute (DONT IGNORE THE NOTES BELOW)
obj.wasExecutedBefore = True
obj.save()
except (ValueError, TypeError): # eval failed or execute
pass
return redirect(".")
return super().response_change(request, obj)
admin.site.register(Rule, RuleAdmin) # register with admin
NOTE You need to import re and all the required libs like scikit and the ones needed for your code in your models.py.
Now in your app, I named my app core , create templates/admin/core/rule, this is on the following format. <app_name/templates/admin/app_name/model_name> all lowercase.
add a file called change_form.html
add this
{% extends 'admin/change_form.html' %}
{% block submit_buttons_bottom %}
{{ block.super }}
<div class="submit-row">
<input type="submit" value="Execute the rule" name="execute">
</div>
{% endblock %}
This creates a form that posts execute then we capture it in the model admin and if it exists, we execute the code.
I've written this dev.to article based on this topic
I’ve written a search function for my django app which does a number of different filtering depending on the search string entered in the search box. I save the result of these different query filtering in a variable called ‘results’ (seems appropriate), but I am having trouble getting the template to render the variable properly depending on the type of object the queryset is based on. The results variable can either take the form of a queryset of ‘filtered’ object1 or 0 results (if nothing of object1 matched that search) OR it can take the form of a queryset of 'filtered' object2 or 0 results (if nothing of object2 matched that search). Later this might become many more different objects/models understandably so I would like to know how to check what type of object the queryset is composed of.
Any help would be really appreciated.
Given a Django queryset, you can retrieve its model using the well named model attribute, that gives a Model object.
queryset = SomeModel.objects
print queryset.model # prints 'path.to.your.app.models.SomeModel'
You probably do not want to check against the full path, so you can use __name__
print queryset.model.__name__ # prints 'SomeModel'
But since you cannot access underscore attributes in templates, you'll have to add this information in your view.
Update:
To check what is the model name in the template, you can add it on the queryset object:
queryset.model_name = queryset.model.__name__
Then in your template:
{% if queryset.model_name = 'SomeModel' %}
... do something
{% elif queryset.model_name = 'SomeOtherModel' %}
....
{% endif %}
1) Checking for a zero
2) checking for the field ".name" of the first element of selection.
also get class name for empty queryset in django - class - name - for - empty - queryset - in - django
If did not turn out, please code
I've tried several different ways a while ago, each of them gave a different exception, so I gave up and decided to manually write filters when I need them. But I'm missing the native escapejs and other useful but simple filters.
There are several related questions and answers, but as far as I see none of them gives a seamless way to implement this. I guess the main problem is that django filters routines are tied too much to the django environment.
Please answer only if you managed to use built-in django filters in the Appengine SDK environment, from my experience it's harder compared to a normal environment, as Appengine environment is limited
Template tags in the Django template engine are simple functions that accept values and parameters. They can all be accessed directly in the source code.
This is output from IPython:
In [173]: from django.template.defaultfilters import date
In [174]: date??
Type: function
String Form:<function date at 0xa2935f0>
File: /usr/local/python/thor/lib/python2.7/site-packages/django/template/defaultfilters.py
Definition: date(value, arg=None)
Source:
#register.filter(expects_localtime=True, is_safe=False)
def date(value, arg=None):
"""Formats a date according to the given format."""
if not value:
return u''
if arg is None:
arg = settings.DATE_FORMAT
try:
return formats.date_format(value, arg)
except AttributeError:
try:
return format(value, arg)
except AttributeError:
return ''
Most of the Django-specific magic resides in the decorator (register.filter) and in the way that the language resolves calls when you type {% load <template library> %} in your template. Look for the definitions in <module>.templatetags modules. Built-ins are located in django.template.defaulttags and django.template.defaultfilters.
If Jinja2 has a way to define new template filters (which it probably does), then you could simply wrap handmade template filters to actual Django functions.
So basically, just create Jinja2 filters that point to the actual Django function definitions.
Edit:
If you do not have access to the actual Django functions, just copy-paste the source code and remove or adapt Django-specific stuff.
The escapejs filter is actually a call to this function in django.utils.html:
_base_js_escapes = (
('\\', r'\u005C'),
('\'', r'\u0027'),
('"', r'\u0022'),
('>', r'\u003E'),
('<', r'\u003C'),
('&', r'\u0026'),
('=', r'\u003D'),
('-', r'\u002D'),
(';', r'\u003B'),
(u'\u2028', r'\u2028'),
(u'\u2029', r'\u2029')
)
# Escape every ASCII character with a value less than 32.
_js_escapes = (_base_js_escapes +
tuple([('%c' % z, '\\u%04X' % z) for z in range(32)]))
def escapejs(value):
"""Hex encodes characters for use in JavaScript strings."""
for bad, good in _js_escapes:
value = mark_safe(force_unicode(value).replace(bad, good))
return value
I alluded to this in my comment, but I'll be more specific here since I have more space. Django is an end-to-end web application framework, which happens to include its own template language, that for lack of a better term is just called the "Django template language". All the template tags and filters in the docs are specific to that language.
If you choose to use Jinja2, you choose to use that template language's structures to the exclusion of Django's. (Obviously the model and view stuff is a separate layer, but in principle, those could be swapped too--it's all loosely coupled.) So the Django docs for templating are no good to you in that case. If you want to format a float in Jinja2, it looks like you need to use the format filter, according to the Jinja docs.
Without more info, I really can't say what's causing your ImportError, but floatformat is not going to work in a Jinja2 template, so maybe that has something to do with it.
I have n number of def blocks in my inheriting template which shows one of them in the inherited template depending on a variable value which is passed from the view.
Currently, I do the computing in the View file, then there decide which def to be visible, then pass this in a dictionary as a key-value along with other to-be-shown data to the inheriting template and there, using if-elif-endif clause evaluate this key's value to see which def to show and then manually call that def with **${self.val_of_key_nn()}**
I want to know if there is a way to get rid of this if-elif-endif bock and simply pass the self.def_to_call() command to the template directly from the view?
example code:
#defs is a key in the passed-dictionary.
#I want to reduce this block to a single-line code
% if defs == '1':
${self.block_1()}
% elif defs == '2':
${self.block_2()}
% else:
${self.block_default()}
% endif
Thank you.
Phil, your question is most timely... as of June 2012 they are working on making this ability more explicit for a future Pyramid version.
There is a way to do it currently, but it's undocumented, and if you use it you should consider it liable to change in the future. Instead of returning only a dict from your view callable, return a tuple:
('defname', {...}) where 'defname' is the (quoted) name of the specific def that you wish to render, and {...} is the dict as usual.
If you're interested in the proposed future method for this, which puts the defname in the template path (asset spec) instead:
https://github.com/Pylons/pyramid/commit/ea009a6d4a1ffa8585faa85581848f6e74a57dfc
FYI for other interested readers: there's an excellent post on use cases for this technique on zzzeek's blog here.
For example:
<%
defdict = {'1': block_1, '2': block_2}
%>
${defdict.get(defs, block_default)()}
I have two types of users. After a user logs in, I take the user to their user profile at /profile
Based on the type of user, their profile may contain different navigation items and forms. Is there an easier way to construct the navigation based on the user type instead of putting {% if %} tags everywhere in the template.
Not sure why #dm03514 deleted his answer, but I'll post something like it, since it would've been my thoughts as well.
If the templates are different enough, then you're right, branching all over the place is a bad idea. It'll just make your template a confusing mess. So just create a separate template for each user type. Then, in your view, you can choose one template or another to show based on the user type. For example:
Old-style function-based views:
def profile_view(request):
if request.user.get_profile().type == 'foo':
template = 'path/to/foo_profile.html'
elif request.user.get_profile().type == 'bar':
template = 'path/to/bar_profile.html'
else:
template = 'path/to/generic_profile.html' # if you want a default
return render_to_response(template, {'data': 'data'}, context_instance=RequestContext(request))
New-style class-based views:
class MyView(View):
def get_template_names(self):
if self.request.user.get_profile().type == 'foo':
return ['path/to/foo_profile.html']
elif self.request.user.get_profile().type == 'bar':
return ['path/to/bar_profile.html']
else:
return ['path/to/generic_profile.html']
I'm not sure how your user types are set up, but if it's based on a string value, you can even create something much more automated, like:
template = 'path/to/%s_profile.html' % request.user.get_profile().type
Then, just create a template for each type based on that naming scheme.
And, of course, each template can extend a base profile.html template, allowing you factor out some common functionality.
Create a profile model and link the user to this profile model. (via a foreign key)
The profile model will then have different attributes for different behaviours.
These different behaviours would then be exposed in the web application either by branching the template (as you say using if in the template) or returning different data to the template or being sent to javascript functions in the font end to modify behaviour
Another alternative is to direct users to different pages based of there profile. The challenge with this is different urls will be needed to different users. This may lead to lots of code duplication.
Have you thought about using permissions for that?
I do same with custom permissions. Easy part is that auth provides anything you need, and it's always there in request.
Very similar code to what Chris Patt proposed would be used:
def profile_view(request):
if request.user.has_perm('permission_codename_foo'):
template = 'path/to/foo_profile.html'
elif request.user.has_perm('permission_codename_bar'):
template = 'path/to/bar_profile.html'
else:
template = 'path/to/generic_profile.html' # if you want a default
return render_to_response(template, {'data': 'data'}, context_instance=RequestContext(request))
what's useful, is that you can protect your views using same permissions with decorators:
#permission_required('permission_codename_foo')
def foo():
#your view here
or if you want to check for permission alternatives:
#user_passes_test(lambda u: u.has_perm('permission_codename_foo') or u.has_perm('permission_codename_bar'))
def foo_or_bar():
#your view here
django creates whole bunch of default permissions as well named: app_name.add_modelname, app_name.change_modelname, and app_name.delete_modelname if you need to limit user's possibilities
If you need to change parts of templates, try {% include %} to load those parts from different files.