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()
Related
I'm starting to use class based views for an application I'm creating but I'm nots sure how it works.
What I need is to have three different templates, and each template will show different information depending on a model field. My question is if there's a way to have only one class view that can render three different html templates with 3 different contexts, or if I need to create 3 different classes.
Using function based views, I would just do this:
# def humanResourcesView(request):
# context = {
# 'data' : Document.objects.all().filter(documentType='humanResources'),
# }
# return render(request, 'main/hr.html', context)
# #view to display training documents after click
# def trainingView(request):
# context = {
# 'data' : Document.objects.all().filter(documentType='training'),
# }
# return render(request, 'main/training.html', context)
# #view to display resource documents after click
# def reportsView(request):
# context = {
# 'data' : Document.objects.all().filter(documentType='reports')
# }
# return render(request, 'main/reports.html', context)
But I'm not sure how it works with class based views. Currently I have this, which renders and filters data correctly for one template, but I don't know how to do multiple templates. Do I need to create 3 different classes?
class DocumentView(View):
def get(self, request, *args, **kwargs):
reports = Document.objects.all().filter(documentType="reports")
context = {
'reports' : Document.objects.all().filter(documentType='reports')
}
return render(request, 'documents/reportsDocs.html', context)
Is there a way to only have one class, and pass a certain context depen
You would need to inherit from TemplateView
and override the get_template_names method to return your conditional based template.
And you would override get_context_date to fetch the data accordingly.
from django.views.generic import TemplateView
class DocumentView(TemplateView):
def get_template_names(self):
pass
def get_context_data(self, **kwargs):
pass
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.
I'd like to know how to store data from my app so I can review the data when I re-run the app.
e.g. I type some info in a TextInput and then when I click the submit button, the info is pasted in a label, so I close the app and when I reopen it the info should be appearing in the label. I know that there are sqlite3 and mysql but I don't know how to apply it into my python/kivy code.
Please anyone suggest me how that can be done.
If possible show with an example, it would be perfect.
Thanks in advance,
My py code:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from random import shuffle
from kivy.core.window import Window
Window.clearcolor = [1, 1, 1, 1]
Window.size = (550, 650)
Builder.load_file('builder.kv')
class MainScreen(ScreenManager):
pass
class Menu(Screen):
pass
class Levels(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def on_pre_enter(self):
Window.bind(on_keyboard=self.voltar)
def voltar(self, window, key, *args):
if key == 27:
App.get_running_app().root.current = 'menu'
return True
def on_pre_leave(self):
Window.unbind(on_keyboard=self.voltar)
class LvLogos(Screen):
def on_pre_enter(self):
Window.bind(on_keyboard=self.voltar)
def voltar(self, window, key, *args):
if key == 27:
App.get_running_app().root.current = 'menu'
return True
def on_pre_leave(self):
Window.unbind(on_keyboard=self.voltar)
class Logo(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def shuffle(self):
letter = self.letters
self.s = shuffle(letter)
return letter
def on_pre_enter(self):
Window.bind(on_keyboard=self.voltar)
def voltar(self, window, key, *args):
if key == 27:
App.get_running_app().root.current = 'menu'
return True
def on_pre_leave(self):
Window.unbind(on_keyboard=self.voltar)
class LvShields(Screen):
pass
class Shield(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def shuffle(self):
letter = self.letters
self.s = shuffle(letter)
return letter
class QuizZApp(App):
def build(self):
self.icon = 'C:\\Users\\gusta\\PycharmProjects\\QuizzApp\\Images\\QuizzLogo.png'
return MainScreen()
if __name__ == '__main__':
QuizZApp().run()
Of course you can use sqlite3, but the simplest way to store basic data for kivy app like your exaple would be to use json file with kivy's own JsonStore class.
It has the benefit of allocating your file in the right place depending on the platform it is deployed on, you won't need to care where exactly.
Here is a simple example using get(), put() and exists() methods to store typed text from TextInput and load it on a Label. (You won't need to create the file itself, just initialize the object and write (put()) in it).
from kivy.uix.boxlayout import BoxLayout
from kivy.storage.jsonstore import JsonStore
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.properties import ObjectProperty
kv='''
RootWidget:
orientation: 'vertical'
BoxLayout:
TextInput:
id: txtinpt
Label:
id: lbl
text: root.stored_data.get('mydata')['text'] if root.stored_data.exists('mydata') else ''
Button:
size_hint_y: .3
text: 'Submit'
on_press:
root.stored_data.put('mydata', text=txtinpt.text)
lbl.text = txtinpt.text
'''
class RootWidget(BoxLayout):
stored_data = ObjectProperty(None)
def __init__(self, *args, **kwargs):
super(BoxLayout, self).__init__(*args, **kwargs)
self.stored_data = JsonStore('data.json')
runTouchApp(Builder.load_string(kv))
If you are new to Json, it is a file containing list of pairs, which's value by its own may be a new list of pair. pretty much like python's dict.
For kivy's JsonStore class, it assume you are working with a minimum of two levels, hence {"mydata": {"text": "What you have written last run"}}. It doesn't make much sense in this simple example to have a nested dict, but in general it will be exactly what you want for real applications, like if you wanted to take contacts data for multiple contacts, or you want to store various configurations for multiple widget for the app itself (in this case you may want to read (get()) the data prior of loading the widgets, probably in the App-class's build() method).
reference: https://kivy.org/docs/api-kivy.storage.html
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.
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 }}