Opinion! Creating Template filters to work with class instance in templates, this works, wondering the most "django" optimal way? - django

Accessing class methods in templates, this works but was wondering if their was a better way?
someclass
class Something():
somevar = None
def __init__(self, somevar):
self.somevar = somevar
def set_somevar(self, newvar):
self.somevar = newvar
def set_weird_and_somevar(self, weird, somevar):
self.weird = weird
self.somevar = somevar
def get_tag(self, tag):
templateTag
from django import template
register = template.Library()
#register.filter
def class_get_method(value, method):
f = method.split('.')
method = f[0]
del f[0]
p = getattr(value, method)
if f:
return p(*f)
else:
return p()
in template, lets say content is a class instance
{{content|class_get_method:'set_weird_and_somevar.wenday_adams.nothervar'}}

class Something():
somevar = None
def __init__(self, somevar):
self.somevar = somevar
Yikes!
Don't do that.
The Turing machine you describe has well-defined semantics.
But python engineers don't write such code,
because it leads to maintenance headaches.
Python is all about namespaces.
There is a global namespace, which Something is in.
There is a class namespace which,
ever since the Something class was defined (at parse time)
has a somevar attribute with value None.
Later on, at run time, we create a pair of objects
with self.somevar values of 1 and 2.
But the class attribute is still None.
This is perfectly well defined.
The machine won't become confused.
But you or future maintenance engineers very likely will.
Choose a different name for the class attribute, please.
Reference it as Something.somevar, or as cls.somevar
from within a #classmethod.
Notice that class attribute somevar can be initialized
as a mutable data structure, such as a dict.
And then both classmethods and ordinary methods can mutate it.

Related

Wagtail - how to access StructBlock class attribute inside block

I'm trying to override my block template as described here:
https://github.com/wagtail/wagtail/issues/3857
I added a BooleanBlock inside the class and tried to use that value to change the template but I get an error "no attribute found".
class Features_Block(StructBlock):
title = CharBlock()
description = TextBlock(required=False)
use_other_template = BooleanBlock(default=False, required=False)
class Meta:
icon = 'list-ul'
def get_template(self, context=None):
if self.use_other_template:
return 'other_template.html'
return 'original_template.html'
I have found this thread which might be the answer but I don't understand how to implement it for my case:
https://github.com/wagtail/wagtail/issues/4387
The get_template method doesn't receive the block's value as a parameter, so there's no reliable way to vary the chosen template according to that value. You might be able to dig around in the calling template's context to retrieve the block value, as in Matt's answer, but this means the internals of Features_Block will be tied to the use of particular variable names in the calling template, which is a bad thing for reusable code.
(Accessing self.use_other_template doesn't work because self, the Features_Block object, doesn't hold on to the block value as a property of itself - it only serves as a translator between different representations. So, it knows how to render a given dictionary of data as HTML, but that dictionary of data is not something that 'belongs' to the Features_Block.)
get_template is called from the block's render method, which does receive the block value, so overriding render will allow you to vary the template based on the block value:
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
class Features_Block(StructBlock):
# ...
def render(self, value, context=None):
if value['use_other_template']:
template = 'other_template.html'
else:
template = 'original_template.html'
if context is None:
new_context = self.get_context(value)
else:
new_context = self.get_context(value, parent_context=dict(context))
return mark_safe(render_to_string(template, new_context))
Check the context that's passed to get_template.
class Features_Block(StructBlock):
title = CharBlock()
description = TextBlock(required=False)
use_other_template = BooleanBlock(default=False, required=False)
class Meta:
icon = 'list-ul'
def get_template(self, context=None):
if context and context['block'].value['use_other_template']:
return 'other_template.html'
return 'original_template.html'

Passing a variable defined in previous form to another form

So I have this flask app I'm making and I need some help with a variable access.
Most of the time, when you define a form in flask, you'll do the following :
class MyForm(Form):
my_field = StringField('I'm a field')
my_submit = SubmitField('Go!')
And when the time comes where you need the form, you'll declare an instance of that class with form = MyForm()
Up to here, it's all good, However :
If you want say, a SelectField (Dropdown) where the choices depend on the answers of a previous form, you need to be able to give the new form those choices. This is what I'm trying to achieve, but I can't get a variable to keep its contents.
Here is my Form code (Above the page code):
class DataMappingForm(Form):
dm_choices = #I need this array !
DMpatient_id = SelectField(u'Select Patient ID Column',
choices=dm_choices, validators=[Required()])
...
Here is my Page code :
#app.route('/upload', methods=['GET','POST'])
def upload():
uform = SomeOtherForm()
if uform.is_submitted() and uform.data['Usubmit']:
#Do stuff from previous form
# and declare array_of_choices
dmform = DataMappingForm() #Needs array_of_choices to work
...
What I've tried so far :
session['dm_choices'] gives me a working outside of request context error
global variables, get reset for some reason
overloading the __init__ of Form by adding the array but i can't access it in the parts above the __init__ function.
I should mention, this all needs to be on the same page.
Is there a way to pass this array_of_choices to my DataMappingForm class ?
EDIT This is what it looked like when I trid the __init__ overload:
class DataMappingForm(Form):
def __init__(self, dm_choices, *args, **kwargs):
self.dm_choices = dm_choices
Form.__init__(self, *args, **kwargs)
DMpatient_id = SelectField(u'Select Patient ID Column',
choices=dm_choices, validators=[Required()])
#I've tried putting it above or below, I get 'dm_choices is not defined'
I've Got it ! Thanks to #synonym for pointing me in the right direction with your last link.
All you need to do is declare a function in which the class is defined. You then pass the variable to the function, and it will be accessible within the class.
Finally, make the function return the form object.
Example :
def makeMyForm(myArray):
def class MyForm(Form):
my_select_field = SelectField(u'I'm a select field', choices=myArray)
my_submit = SubmitField(u'Go!')
return MyForm()
And to make the form, you use :
form = makeMyForm(theArrayYouWant)
And VoilĂ  !
Note : As I've had the problem before, I'll mention that the Array is composed of tuples :
myArray = [('value','What you see'),('value2','What you see again')]
If you want to dynamically change the choices of a SelectField the following should work:
class DataMappingForm(Form):
def __init__(self, choices)
self.DMpatient_id.choices = choices
DMpatient_id = SelectField(u'Select Patient ID Column') #note that choices is absent
If you want fully dynamic fields you can create the class dynamically in a function. From the WTForms Documentation:
def my_view():
class F(MyBaseForm):
pass
F.username = StringField('username')
for name in iterate_some_model_dynamically():
setattr(F, name, StringField(name.title()))
form = F(request.POST, ...)
# do view stuff
In that case you can customize the form as much as you want. Of course in the case you only want to customize the choices the first approach should be enough.

Python: Child Inheriting Parents Default Values If Not Specified

fairly intermediate programmer but Python beginner here. I've been working on a game for a while and I restructured all of my classes yesterday. Where I was initially using only compositional data structure, I'm now using a mix of both. My issues come when I want to spawn the player. Here's the relevant code.
class Object(object):
def __init__(self, **kwargs):
DeaultValues={'x':0, 'y':0, 'name':None, 'texture':None, 'blocks':False, 'ObjectID':None, 'Fighter':None, 'Corpse':None, 'Skill':None, 'ai':None}
for key,value in DeaultValues.items():
try:
vars(self)[key] = kwargs[key]
except ValueError:
vars(self)[key] = value
except KeyError:
vars(self)[key] = value
self.x = kwargs['x']
self.y = kwargs['y']
self.name=kwargs['name']
self.blocks=kwargs['blocks']
self.ObjectID=self.AttachID()
self.texture = kwargs['texture']
#This section binds an actors compenents to itself
self.Corpse = kwargs['Corpse']
if self.Corpse:
self.Corpse.owner = self
self.Skill=kwargs['Skill']
if self.Skill:
self.Skill.owner = self
self.Fighter = kwargs['Fighter']
if self.Fighter:
self.Fighter.owner = self
self.ai = kwargs['ai']
if self.ai:
self.ai.owner = self
class HighActor(Object):
def __init__(self, **kwargs):
super(HighActor, self).__init__(**kwargs)
class Player(HighActor):
def __init__(self, Level=1, Xp=0, PreviousLevel=0, PreviousLevelThreshold=100, LevelThreshold=500, **kwargs):
super(Player, self).__init__(**kwargs)
self.LevelThreshold = LevelThreshold
self.PreviousLevelThreshold=PreviousLevelThreshold
self.PreviousLevel=PreviousLevel
self.Level = Level
self.Xp = Xp
def SpawnPlayer():
global player
FighterComponent = Fighter(MaxHp=100, Hp=100, IsHasted=[False, False], death_function=None)
CorpseComponent = Corpse()
SkillComponent = HighActorSkill()
player=Player(name="player", x=None, y=None, texture="player.png", blocks=True, ObjectID=None, Fighter=FighterComponent, Corpse=CorpseComponent, Skill=SkillComponent, ai=None)
The above code works just fine, however its not really inheriting anything. To get the player object to not error I had to add to add all of the attributes of the base object class to the Player initialization. If I remove any of the values that are set to none in the player=Player() statement I get value errors or key errors. I tried to correct this by having a dict of default values that looped through all kwargs the init was given and if they had no value, set them to the default found. This worked until I got to any of the components. So in the case of not specifying ai=none, I got key errors. I would really love to have my code in such a format that if I do not specify a value for any of the base object class attributes the default values would be passed in, but if I do specify a value, that gets passed up to the base class. My ideal end result would be to have my player instancing look like this:
def SpawnPlayer():
global player
FighterComponent = Fighter(MaxHp=100, Hp=100, IsHasted=[False, False], death_function=None)
CorpseComponent = Corpse()
SkillComponent = HighActorSkill()
player=Player(name="player", texture="player.png", blocks=True, Fighter=FighterComponent, Corpse=CorpseComponent, Skill=SkillComponent)
I have a suspicion that my inheritance isn't working 100% because I get errors if I leave out ObjectID even though that should be assigned since in the init of the bass class its set equal to getid(self). So I'm either having issues with my inheritance (I'm really struggling with Super), or the signatures of my objects, and I'm not quite sure what my problem is, and more importantly why. I'm not opposed to changing the codes signature dramatically, as I'm still writing the engine so nothing is reliant on this yet. What should be done?
I think your class structure should be different. Each class should only have the attributes it needs, add new ones as you build up the inheritance, e.g.:
class Object(object):
def __init__(self, x=0, y=0, name=None, **kwargs):
self.x = x
self.y = y
self.name = name
class HighActor(Object):
def __init__(self, corpse=None, skill=None, **kwargs):
super(HighActor, self).__init__(**kwargs)
self.corpse = corpse
self.skill = skill
class Player(HighActor):
def __init__(self, level=1, xp=0, **kwargs):
super(Player, self).__init__(**kwargs)
self.level = level
self.xp = xp
At each level you specify the attributes - all Objects should have x, y and name, all HighActors should also have corpse and skill, etc. Now you can specify arguments to supply to any of the three levels of the hierarchy, or leave them out to get defaults:
player = Player(name="player one", skill=100, xp=12)
You may have things that don't fit into this inheritance scheme - it is OK to have more than one separate set of inheritance relationships in your model, don't force it!
This works because the **kwargs at the end of each __init__ "mops up" any keyword arguments that method isn't expecting into a dictionary kwargs, and can then pass them all to the next level. When you do so, super(...).__init__(**kwargs), this unpacks the dictionary back into keyword arguments, and any that aren't present will take the specified default value.

Django + WSGI: Force object initialization?

I have a form class that looks something like this:
class RegisterForm(Form):
username = Field(model_field='username', filters=validators.minlength(3))
You'll notice that username is a class variable. I believe this means that Field will be constructed once the first time the RegisterForm is used (after apache is restarted). It will not be re-constructed between page reloads (unless a 2nd WSGI instance (?) is spawned, but we won't get into that). I noticed this because some of the values I've set in Field.__init__ are not being reset.
However, Form.__init__ does seem to be called each page reload. I guess that's because of the way I'm using it? I'm actually constructing it like form = RegisterForm(request) at each page request.
So... supposing I don't want the [class variables in] RegisterForm to be "cached" and have the Fields re-initialized at each request... how would I do that? (without modifying the syntax of RegisterForm; you can do whatever inside the base class, Form)
You could update the class variable each instantiation:
class ContactForm(forms.Form):
username = Field(model_field='username', filters=validators.minlength(3))
def __init__(self, *args, **kwargs):
super(ContactForm, self).__init__(*args, **kwargs)
ContactForm.username = Field(model_field='username', filters=validators.minlength(3))
You could define the class within a function. That way it gets constructed each time the function is called.
def gotclass(data):
class InnerClass(object):
someattr = DoSomethingWith(data)
return InnerClass
MyNewClass = gotclass(42)
someobj = MyNewClass()

Django template context function without running automatically

Sorry or the confusing title! It's actually a lot simpler than it sounds.
I've got a function:
def get_messages(request):
# do something expensive with the request
return 'string'
I want to be able to call that function from the template, so I've strapped in with a context processor:
def context_processor(request):
return {'messages':get_messages(request)}
So now when I have {{messages}} in my template, string prints out. Great.
The problem is get_messages is quite expensive and isn't always needed. Less than half the templates need it. Is there a way of passing the function to the template and leave it up to the template if it runs or not?
I tried this already:
def context_processor(request):
return {'messages':get_messages}
But that just outputs the function description <function get_messages at 0x23e97d0> in the template instead of running it.
I think You shouldn't mix logic of application with template (the view in MVC pattern). This breaks consistency the architecture. You can call get_messages in views that need it and simply pass messages to the template context, in the others just pass None.
But answering Your question: You can make a proxy object. E.g:
class Proxy(object):
def __init__(self, request)
self.request = request
super(Proxy, self).__init__()
def get_messages(self):
# so some expensive things
return 'string'
# context processor
def context_processor(request):
return {'messages':Proxy(request)}
# in the view
{{ messages.get_messages }}
You can make this ever more generic, and create Proxy class that has one method (e.g get), and takes one parameter in constructor: a function which takes request object as first parameter. This way You gain generic method to proxy a function call in Your templates. Here it is:
class Proxy(object):
def __init__(self, request, function)
self.request = request
self.function = function
super(Proxy, self).__init__()
def get(self):
return self.function(self.request)
then You can write even cooler than I had written before:
# context processor
def context_processor(request):
return {'messages':Proxy(request, get_messages)}
# sounds nice to me
{{ messages.get }}