Django - Template objects access verbose name - html

I have a Scrib model and a template which gets Scrib.objects.all() stored into scribs
In the template, I'd like to access to the verbose name of the model like:
<h1>{{ scribs.model.verbose_name }}</h1>
Is it possible or do I have to add the Scrib handler to the context ?

You can't access the verbose_name directly from the template. From what I see you got three options.
Option one (simplest). Assign the verbose name in your controller and then access it from the template:
# in controller
render_to_response('template.html', {'scrib_verbose_name': Scrib._meta.verbose_name})
# in a view template.html
Verbose name of a Scrib model: {{ scrib_verbose_name }}
Option two: write yourself a view helper that will return the verbose_name (or other field from _meta class) for a given class.
Update Third option (a hat tip to Uku Loskit) - define a method on a scrib model that returns the meta object (or any particular field from it).
# method in a Scrib model
def meta(self):
return self._meta
# later on in a template - scrib is a instance of Scrib model
<h1>{{ scrib.meta.verbose_name }}</h1>
Update2 If you insist on directly accessing verbose name from the scribs (which is a result of Scrib.objects.all()), then you can do stuff like:
scribs = Scrib.objects.all()
scribs.verbose_name = Scrib._meta.verbose_name
# in a template you can now access verbose name from a scribs variable
{{ scribs.verbose_name }}
Update3 Yet another way to go is using model inhertinace to be able to access the verbose name from instance of any model that inherit from our custom one.
# base model (inherits from models.Model)
class CustomModel(models.Model):
def meta(self):
return self._meta
class Meta:
abstract = True
# Scrib now inherit from CustomModel
class Scrib(CustomModel):
# do any stuff you want here ...
Scrib now inherit from CustomModel that provides us with property meta. Any model that will inherit from CustomModel class is going to have this property. It's the cleanest and most flexible solution.

I want to do that as well, I suppose another solution would be a template filter:
from django import template
register = template.Library()
#register.filter
def verbose_name(value):
return value._meta.verbose_name
#register.filter
def verbose_name_plural(value):
return value._meta.verbose_name_plural
Then in the template:
1 {{ object|verbose_name }}, 2 {{ object|verbose_name_plural }}
1 scrib, 2 scribs

Alternatively to WTK's suggestion you could define a method for the Scrib model in your models.py like this:
def get_verbose_name(self):
return self._meta.verbose_name
# in templates
{{ scrib_instance.get_verbose_name }}

Related

Unable to serialize a nested python object using json.dumps()

I am new to python so sorry about the naive questions. I have a simple code snipper where I try to serialize a python object to a dictionary using json.dumps()
import json
class Document:
uid = "1"
content = "content1"
domain = "domain"
title = "title"
class ASSMSchema:
requestSource = "unittest"
documents = []
def entry():
myObj = ASSMSchema()
myObj.requestSource = "unittest"
document1 = Document()
document1.uid = "1"
document1.content = "content1"
document1.domain = "domain"
document1.title = "title"
myObj.documents.append(document1)
print(json.dumps(myObj.__dict__))
if __name__ == "__main__":
entry()
I get the following output when I run the above code
{"requestSource": "unittest"}
This is not expected however, since it should also seralize the List of "Document" objects. Appreciate your answers. Thanks in advance!
Your class definition of ASSMSchema defines the class members documents and requestSource. These are not attributes of a single instance of this class, but shared between all instances. When you are running myObj.requestSource = "unittest", you are defining a member variable on the instance myObj. This member is actually reflected in the output of json.dumps, whereas the class members (like documents) are not.
For further reading, see https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables
Depending on the complexity and desired maintainability of your program, there are multiple approaches to archieve your desired behaviour. Firstly, you have to fix the mistake in both class definitions. To define a class with instance variables instead of class variables, do something like this:
class Foo:
# class variables go here
def __init__(self, field1, field2):
# This method is called when you write Foo(field1, field2)
# these are instance variables
self.field1 = field1
self.field2 = field2
If you want to dump this class as JSON, you can simply use the trick with __dict__: print(json.dumps(Foo(1,2).__dict__)) will output something like { "field1": 1, "field2": 2 }.
In your case, there is the documents member though, which is not JSON serializable by default. Therefore, you must handle this separately as well. You could write an encoder for your ASSMSchema (see this thread for more info on that). It could be implemented roughly like this:
from json import JSONEncoder
class ASSMSchemaEncoder(JSONEncoder):
def default(self, o):
return {
"requestSource": o.requestSource,
# Convert the list of Document objects to a list of dict
"documents": [d.__dict__ for d in o.documents]
}
Now, when serializing an instance of ASSMSchema, this implemention is used and the documents member is replaced with a list of dictionaires (which can be serialized by the default encoder). Note, that you have to specify this encoder when calling json.dumps, see the linked thread above.

Passing a context variable through a class in Django

how can i pass a context variable in a class. i know that i would use the render if i was showing my template from a function. and then i could just pass my context variable as part of the render. But how do i pass a context variable to html if i am using a class to show the template.
i have tried putting a function into my class but it has not worked.
views.py
class hithere(ListView):
model = Datadata
template_name = 'index.html'
def whatsup(request):
context = {}
context['my_string'] = "this is my sring"
return render(request, context)
Index.html
<h1> {{ my_string }} </h1>
You can override the .get_context_data(…) method [Django-doc]:
class hithere(ListView):
model = Datadata
template_name = 'index.html'
def get_context_data(self, *args, **kwargs):
context = super().get_context_data(*args, **kwargs)
context['my_string'] = 'this is my string'
return context
But perhaps more convenient is to define a method:
class hithere(ListView):
model = Datadata
template_name = 'index.html'
def my_string(self):
return 'this is my string'
and render this with:
{{ view.my_string }}
Note: normally a Django models, just like all classes in Python are given a name in PerlCase, not snake_case, so it should be: HitHereView instead of hithere.

Can I use urls parameter again in Django? [duplicate]

In my url conf, I have several URL's which have the same named parameter, user_id.
Is it possible to access this parameter either in a middleware - so I can generically pass it on to the context_data - or in the template itself?
Sample URL conf to illustrate the question:
url(r'^b/(?P<user_id>[0-9]+)/edit?$', user.edit.EditUser.as_view(), name='user_edit'),
url(r'^b/(?P<user_id>[0-9]+)/delete?$', user.delete.DeleteUser.as_view(), name='user_delete')
For class based views, the view is already available in the context, so you dont need to do anything on the view side. In the template, just do the following:
{{ view.kwargs.user_id }}
See this answer
If you need this data in the template, just override your view's get_context_data method:
class MyView(View):
def get_context_data(self, **kwargs):
context = super(MyView, self).get_context_data(**kwargs)
context['user_id'] = self.kwargs.get('user_id')
return context
For function based views:
template
{% url 'view' PARAM=request.resolver_match.kwargs.PARAM %}
views.py
def myview(request, PARAM):
...
Django 2.2

Jinja2 escaping object passed to templare.render

I created a class representing an input widget and I'd like to use if directly in the template. However, whenever I pass it to the template it gets escaped.
class Widget:
def render(self):
Markup('<input type="text">')
def __str__(self):
return self.render()
def __repr__(self):
return self.render()
widget = Widget()
widget # <input type="text">
tpl = Template('{{ field }}', autoescape=True)
tpl.render(field=widget) # '<input type="text">'
tpl.render(field=str(widget)) # '<input type="text">'
Is it possible to use the widget directly without wrapping it in str or calling render from within the template? Is there any magic method which I need to override?
After digging through jinja2 and markupsafe source code I found that my widget needs to implement __html__ magic method which returns the "safe" string.
def __html__(self):
return self.render()

NameError: global name not defined when calling method inside class

I'm trying to call a different function inside the same class from my main function and I can seem to figure where the error is.
I keep getting this error relating to functions not being defined and I'm not sure how to resolve it:
NameError: global name 'results' is not defined
class Darts:
def main() :
print results()
def results() :
round_result_totals = "Stuff"
return round_result_totals
#RUNNING CODE
main()
Make sure that you define properly self in your functions and initialize an object first before you do anything else. You can't just call a function from a class without creating an instance of that class and calling a function from that instance (NOT THE CLASS). Usually you want to have an __init__ in your python classes.
class Darts:
def __init__(self):
pass
def main(self):
print(self.results())
def results(self):
round_result_totals = "Stuff"
return round_result_totals
Dart1 = Darts()
Dart1.main()
If you want to use variables, self is critical too for encapsulation.
class Darts:
def __init__(self):
self.a = 500
def main(self):
self.a += 1
print(self.a)
Dart1 = Darts()
Dart1.main()
You need to pass self (the instance of your object) into your object's methods.
class Darts:
def main(self) :
print self.results()
def results(self) :
round_result_totals = "Stuff"
return round_result_totals
You're missing all of the required references to self inside your class. It should look like this:
class Darts:
def main(self) :
print self.results()
def results(self) :
round_result_totals = "Stuff"
return round_result_totals
Here is the Python documentation on classes. And the fifth paragraph of this section makes reference to the convention of self.
Briefly: the first argument to a method of a Python class is automatically passed in a reference to the instance of that class from which the method is being called (provided it is being called as an instance method). This is done automatically by Python's interpreter. This parameter still needs to be explicitly stated in the method definition, however, and the convention is to call it self.