Django - passing a dict to form constructor and having it available globally in the class - django

I'm making a big mess trying to access the object that I passed from the view to the form.
class PrenotaForm(forms.ModelForm):
ORARI_CHOICES = ()
def __init__(self, *args, **kwargs):
DICT_ORARI_CHOICES = kwargs.pop('ORARI_CHOICES_NEW', {})
ORARI_CHOICES_NEW = []
for key, value in DICT_ORARI_CHOICES.items():
temp = [key,value]
ORARI_CHOICES_NEW.append(temp)
super(PrenotaForm, self).__init__(*args, **kwargs)
self.ORARI_CHOICES = ORARI_CHOICES_NEW
print("EEEEEEEEEEEEEEE" + str(self.ORARI_CHOICES))
print(ORARI_CHOICES)
I don't understand why inside the init the ORARI_CHOICES is populated as shown in console output:
EEEEEEEEEEEEEEE[['è uguale', 'Indifferente'], ['845', '08:45'], ['900', '09:00'], ['915', {'label': '09:15', 'disabled': 'disabled'}], ['930', {'label': '09:30', 'disabled': 'disabled'}], ['945', '09:45'], ['1000', '10:00'], ['1015', '10:15'], ['1030', '10:30'], ['1045', '10:45'], ['1100', '11:00'], ['1115', '11:15'], ['1130', '11:30'], ['1145', '11:45']]
but outside the init the ORARI_CHOICE is still empty:
print(ORARI_CHOICES)
since the print does not output nothing.
How can I override the ORARI_CHOICES = () and make it avalable globally in the class after every GET request performed in the view?
if request.method == 'GET':
size_gruppi = 30
print("gruppi size is : " + str(size_gruppi))
ORARI_CHOICES = (
('è uguale', "Indifferente"),
('845', "08:45"),
('900', "09:00"),
('915', "09:15"),
('930', "09:30"),
('945', "09:45"),
('1000', "10:00"),
('1015', "10:15"),
('1030', "10:30"),
('1045', "10:45"),
('1100', "11:00"),
('1115', "11:15"),
('1130', "11:30"),
('1145', "11:45"),
)
orari_map = map(list,ORARI_CHOICES)
orari_dict = dict(ORARI_CHOICES)
print(orari_dict)
counter = 0
for key in orari_map:
if key[0] != 'è uguale':
tot_in_fascia = sum(filter(None, Iscritto.objects.filter(fasce_orarie=key[0]).aggregate(Sum('size_adulti'), Sum('size_giovani')).values()))
print(tot_in_fascia)
if tot_in_fascia >= size_gruppi:
print("fascia " + key[0] + " è al completo ")
orari_dict.update({key[0]: {'label': key[1], 'disabled': 'disabled'}})
form = PrenotaForm(ORARI_CHOICES_NEW = orari_dict)
return render(request, "prenota.html", {'form': form, 'posti_liberi': posti_disponibili, 'giovani_iscritti': giovani_iscritti})

You should set ORARI_CHOICES as a class/static attribute.
class PrenotaForm(forms.ModelForm):
ORARI_CHOICES = []
def __init__(self, *args, **kwargs):
DICT_ORARI_CHOICES = kwargs.pop('ORARI_CHOICES_NEW', {})
# ORARI_CHOICES_NEW = []
for key, value in DICT_ORARI_CHOICES.items():
temp = [key,value]
self.__class__.ORARI_CHOICES.append(temp)
super(PrenotaForm, self).__init__(*args, **kwargs)
print("EEEEEEEEEEEEEEE" + str(self.ORARI_CHOICES))
Now, PrenotaForm.ORARI_CHOICES is already accessible. PrenotaForm.ORARI_CHOICES will always be accessible, but it returns empty list, untill you do not create instance of PrenotaForm. After instance creation of PrenotaForm, __init__ method will be called and data will be added inside ORARI_CHOICES.

Related

Python - Overriding a parent variable with a getter/setter

So I have a parent class BaseAdd that I'm trying to subclass. The BaseAdd uses self.left and self.right, I want to use self.nodes to make it easier to access both left and right at once:
class BaseAdd():
def __init__(self, leftright):
self.left = leftright[0]
self.right = leftright[1]
class Add(BaseAdd):
def __init__(self, leftright):
self.nodes = leftright
#property
def left(self):
return self.nodes[0]
#left.setter
def left(self, value):
self.nodes[0] = value
foo = Add(('L', 'R'))
foo.left = "new"
print(foo.left, foo.nodes[0])
>>> ('new', 'L')
The problem is that the setter is never getting called, my hunch is that it's using the BaseAdd.left somehow instead. How can I make the setter properly set the list element?

Replacement for django `render_options`

So I am implementing this answer: Country/State/City dropdown menus inside the Django admin inline, but the def render piece of code needs to be redone.... I have managed to redo it, but I am struggling to find a replacement (or the correct code) for the self.render_options method (which was deprecated on 1.11) of the Widget class.
I am on Django 2.1.
What should I change?
Here is my code:
class StateChoiceWidget(widgets.Select):
def render(self, name, value, attrs=None, renderer=None):
self.choices = [(u"", u"---------")]
if value is None:
value = ''
model_obj = self.form_instance.instance
if model_obj and model_obj.country:
for m in model_obj.country.state_set.all():
self.choices.append((m.id, smart_text(m)))
else:
obj = State.objects.get(id=value)
for m in State.objects.filter(country=obj.country):
self.choices.append((m.id, smart_text(m)))
final_attrs = self.build_attrs(attrs)
output = ['<select%s>' % flatatt(final_attrs)]
for option in self.choices:
output.append('<option value="%s">%s</option>' % (option[0], option[1]))
output.append('</select>')
return mark_safe(''.join(output))
Original poster updated the sample code, so now it doesn't show the code in the question: see previous revision https://stackoverflow.com/revisions/52174508/1
So I figured out the answer. Will post it here in case someone runs into the same issue.
class StateChoiceWidget(widgets.Select):
def render(self, name, value, attrs=None, renderer=None):
self.choices = [(u"", u"---------")]
if value is None or value == '':
value = ''
model_obj = self.form_instance.instance
if model_obj and model_obj.country:
for m in model_obj.country.state_set.all():
self.choices.append((m.id, smart_text(m)))
else:
obj = State.objects.get(id=value)
for m in State.objects.filter(country=obj.country):
self.choices.append((m.id, smart_text(m)))
final_attrs = self.build_attrs(attrs)
s = widgets.Select(choices=self.choices)
select_html = s.render(name=name,value=value,attrs=attrs)
return mark_safe(''.join(select_html))

Django single object update in for loop

Hi I'm wondering if it possible or how to update single model object name inside for loop by his id using object.filter(pk=id).update(name='name') function
I try to do this but its not working in for loop. It's working only outside loop
EDIT
my edit view with for loop:
first i prepare data based on my database.Data can be modified by other methods so i keep they in global list schedule_table.
When I'm saving project object i want to update other data representing by schedule_table, using for loop.
def ProjectEditView(request, pk):
project = get_object_or_404(Project, pk=17)
schedule_table_load_form_db(project)#preparing list with data
Task_Schedule_TableView(request)
project_form = ProjectForm(request.POST or None, instance=project)
project_form_valid = project_form.is_valid()
if project_form_valid:
with transaction.atomic():
# save form in DB
project = project_form.save(commit=False)
project.save()
# modify other object based on changed list schedule_table
if schedule_table.__len__() > 0:
#my for loop
for p in schedule_table:
team = Team.objects.get(name=p.team)
phase = Phase.objects.filter(pk=p.pk).update(name=p.name,
project=project,
team=team,
order=p.order,
duration=p.duration,
prev=p.prev,
start=p.start,
end=p.end)
# some other staff..... outside the loop
return redirect('Project:ProjectListView')
context = {'project_form': project_form}
return render(request, 'Project/test.html', context)
function to prepare list with data:
def schedule_table_load_form_db(project):
global schedule_table
schedule_table = []
phases = Phase.objects.filter(project=project)
for phase in phases:
tasks_list = Task.objects.filter(phase=phase)
tasks = []
for task in tasks_list:
task_dict = Task_dictionary.objects.get(pk=task.task_dictionary.pk)
tmp = ''
for e in task.employers.employer.all():
user = User.objects.get(pk=e.user_id)
tmp += user.first_name + ' ' + user.last_name + ','
tasks.append(TableTask(pk=task.pk,
order=task.order,
name=task.name,
duration=task.duration,
employer=tmp,
start=task.start,
end=task.end,
min_employers_nr=task_dict.min_employers_nr,
max_employers_nr=task_dict.max_employers_nr,
prev=task.prev_task,
))
schedule_table.append(TablePhase(pk=phase.pk,
name=phase.name,
duration=0.0,
start=phase.start,
end=phase.end,
team=phase.team.name,
task=tasks,
order=schedule_table.__len__(),
prev=phase.prev
))

Tkinter assign buttons to entries in dynamically created widgets

How can I access an Entry content with pressing the corresponding Button in dynamically created widgets?
Below is the best I come up with so far. Thank you for any help.
from Tkinter import *
class App(object):
def __init__(self, master):
self.master = master
self.mf = Frame(self.master)
self.l = ["white", "red", "blue", "brown"]
self.font = ("Arial", 30)
self.c, self.r = 1, 0
self.cc, self.rr = 0, 0
self.bel = []
for c in self.l:
action = self.print_entry
self.e = Entry(self.mf, bg=c, width=10, font=self.font)
self.e.grid(row=self.r, column=self.c)
self.b = Button(self.mf, bg=c, text=c, font=self.font)
self.b.grid(row=self.rr, column=self.cc)
self.b.config(command=action)
self.bel.append((self.b, self.e))
self.rr += 1
self.r += 1
self.mf.pack()
def print_entry(self): # this function prints the content of the entry
pass
def main():
root = Tk()
display = App(root)
root.mainloop()
if __name__=="__main__":
main()
You can pass a reference to the entry widget into the command, using lambda or functools.partial. For example:
self.b.config(command= lambda entry=self.e: action(entry))
...
def print_entry(self, entry):
print("the entry is '%s'" % entry.get())
By the way, using self.b and self.e is pointless, since those variables will only ever hold references to the last button and last entry. You should either use a local variable, and/or append the values to a list.

django: Class-based Form has no errors but is not valid. What is happening?

I have a form which is returning False from .is_valid(), but .errors and .non_field_errors() appear to be empty. Is there any other way to check out what might be causing this?
In case it's a problem with my logging code, here it is:
logger.debug('form.non_field_errors(): ' + str(form.non_field_errors()))
logger.debug('form.errors: ' + str(form.errors))
My form code:
class IncorporateForm(forms.Form):
type_choices = (("LTD", "Private company limited by shares"),
("LTG", "Private company limited by guarantee"),
("PLC", "Public limited company"),
("USC", "Unlimited company with share capital"),
("UWS", "Unlimited company without share capital"))
country_choices = (("EW", "England and Wales"),
("CY", "Wales"),
("SC", "Scotland"),
("NI", "Northern Ireland"))
articles_choices = (("MOD", "Model articles"),
("AMD", "Model articles with amendments"),
("BES", "Entirely bespoke articles"))
name = forms.CharField(initial = "[name] limited")
registered_office = forms.CharField(widget=forms.Textarea,
label='Registered office address')
registration_country = forms.ChoiceField(choices=country_choices,
widget=forms.RadioSelect(renderer=SaneRadioField))
company_type = forms.ChoiceField(choices=type_choices,
widget=forms.RadioSelect(renderer=SaneRadioField), initial="LTD")
articles_type = forms.ChoiceField(choices=articles_choices,
initial='MOD',
widget=forms.RadioSelect(renderer=SaneRadioField))
restricted_articles = forms.BooleanField()
arts_upload = forms.FileField(label='Articles to upload')
My view code (to the point where I detect that the form is not valid):
def incorporate_view(request):
form = IncorporateForm()
DirectorsFormset = forms.formsets.formset_factory(OfficerForm, extra=30)
CapitalFormset = forms.formsets.formset_factory(CapitalForm, extra=30)
HoldingFormset = forms.formsets.formset_factory(HoldingForm, extra=30)
AmendsFormset = forms.formsets.formset_factory(ArticlesAmendsForm, extra=50)
if request.method == 'POST':
#bind and validate
form.data = request.POST
guarantee_form = GuaranteeForm(data=request.POST)
directors_formset = DirectorsFormset(prefix='directors', data=request.POST)
capital_formset = CapitalFormset(prefix='capital', data=request.POST)
holding_formset = HoldingFormset(prefix='holding', data=request.POST)
amends_formset = AmendsFormset(prefix='amends', data=request.POST)
save_objects = [] # objects to be saved at the end if there is no error
user_objects = {} # keyed by email
individual_objects = {} # keyed by email?
if(not (form.is_valid() and guarantee_form.is_valid()
and directors_formset.is_valid()
and capital_formset.is_valid() and
holding_formset.is_valid() and
amends_formset.is_valid())):
dbg_str = """
form.is_valid(): %s
guarantee_form.is_valid(): %s
directors_formset.is_valid(): %s
capital_formset.is_valid(): %s
holding_formset.is_valid(): %s
amends_formset.is_valid(): %s
""" % (form.is_valid(), guarantee_form.is_valid(),
directors_formset.is_valid(),
capital_formset.is_valid(),
holding_formset.is_valid(),
amends_formset.is_valid())
logger.debug(dbg_str)
logger.debug('form.non_field_errors(): ' + str(form.non_field_errors()))
logger.debug('form.errors: ' + str(form.errors))
Assigning to form.data does not bind the form — you should pass the data dict when the object is constructed (or look into the code and see which flags are set, but that's probably not documented and therefore not recommended).