How to modify the form filed data? - django

I have a model:
class PastStudy(Model):
grade_average = FloatField(null=True)
I have a modelform as below:
class PastStudyForm(ModelForm):
class Meta:
model = PastStudy
fields = ('grade_average', )
What I have in view:
...
if request.POST:
past_study_form = PastStudyForm(request.POST)
if past_study_form.is_valid():
return HttpResponse(past_study_form.cleaned_data['grade_average'])
else:
profile_filter_past_study_form = ProfileFilterPastStudyForm()
...
What I need is that I want to write a clean method for PastStudyForm so that in case I entered 90 as grade average, HttpResponse converts it two 0-20 grading scheme and returns 18.
I tried this and I was still getting 90 not 18
class PastStudyForm(ModelForm):
class Meta:
model = PastStudy
fields = ('grade_average', )
def clean(self):
cleaned_data = super().clean()
grade_average = self.cleaned_data['grade_average']
self.cleaned_data['grade_average'] = grade_average/5
return cleaned_data
and This:
class PastStudyForm(ModelForm):
class Meta:
model = PastStudy
fields = ('grade_average', )
def clean_grade_average(self):
grade_average = self.cleaned_data['grade_average']
data = grade_average/5
return data
However, I still get 90. I also have tried a few other methods but I still was getting 90 in HttpResponse
Maybe using clean method be wrong and I should do something else!
The real code is huge and I have summarized it in here and other aspects of the problem are not explained in here. That is why I prefer and expect to get a response in which I am advised how to it in the form definition, not other methods such as converting it in the view.

in your clean method, you assign the result of your calculation method into self.cleaned_data,
while you are returning cleaned_data not self.cleaned_data.
it is different variable.
try this instead:
self.cleaned_data = super().clean()
grade_average = self.cleaned_data['grade_average']
self.cleaned_data['grade_average'] = grade_average/5
return self.cleaned_data

Related

Django multiple model update/create

I am a beginning programmer in Django/Python and I am now looking for a way to robustly create and update my models. I would expect this is a very common problem. Some example code of how to do this the right way would be very much appreciated.
Problems which I struggling with is that I am not sure where to put the save() command. Now there are multiple places where I put the save() method. And sometimes I have to multiple times hit the save button on the various views before a change on a low level trickless up to a higher level model.
In this example I use two simplified models named Medium and Circuit. The create methods for the two models are specified as well as a set_medium and set_circuit method, this shows how I am currently doing it.
class Circuit(models.Model):
medium = models.ForeignKey('medium.Medium', related_name='medium_related', on_delete=models.CASCADE)
temperature = models.FloatField(default=60, help_text='[degC]')
glycol_percentage = models.FloatField(default=0, choices = choices.GLYCOL_PERCENTAGE)
#classmethod
def create( cls,
temperature,
glycol_percentage):
circuit = cls( temperature = temperature,
glycol_percentage = glycol_percentage)
circuit.medium = Medium.create(circuit.temperature, circuit.glycol_percentage)
circuit = circuit.set_circuit(circuit)
circuit.save()
return circuit
def set_circuit(self, circuit):
circuit.medium.glycol_percentage = circuit.glycol_percentage
circuit.medium.temperature = circuit.temperature
circuit.medium = circuit.medium.set_medium(circuit.medium)
return circuit
class Medium(models.Model):
glycol_percentage = models.FloatField(default=0, choices = choices.GLYCOL_PERCENTAGE)
temperature = models.FloatField(default=60, help_text='[degC]')
# Calculated properties
rho = models.FloatField(default=1000, help_text='[kg/m3]')
#classmethod
def create( cls, temperature, glycol_percentage):
medium = cls( temperature = temperature,
glycol_percentage = glycol_percentage)
medium = medium.set_medium(medium)
medium.save()
return medium
def set_medium(self, medium):
medium.rho = services.rho(temperature=medium.temperature, glycol_percentage=medium.glycol_percentage)
return medium
Below is how I typically write my Create and Update views.
class CircuitCreateView(LoginRequiredMixin, CreateView):
model = Circuit
template_name = 'circuit/create.html'
form_class = CircuitForm
def form_valid(self, form):
circuit = Circuit.create( glycol_percentage = form.cleaned_data['glycol_percentage'],
temperature = form.cleaned_data['temperature'])
circuit.save()
return HttpResponseRedirect(reverse('circuit:detail', args=(circuit.id,)))
class CircuitUpdateView(LoginRequiredMixin, UpdateView):
model = Circuit
template_name = 'circuit/detail-update.html'
form_class = CircuitForm
def form_valid(self, form):
circuit = get_object_or_404(Circuit, pk=self.kwargs['pk_circuit'])
circuit.glycol_percentage = form.cleaned_data['glycol_percentage']
circuit.temperature = form.cleaned_data['temperature']
circuit = circuit.set_circuit(circuit)
circuit.save()
return HttpResponseRedirect(reverse('circuit:detail', args=(circuit.id,)))

How to execute a function when a variable's value is changed?

In Odoo 10, I want to change the value of a variable when the forecasted quantity of a product is changed. I tried using the #api.onchange decorator, but it doesn't work. The forecasted quantity change, but the variable keeps the same value. I have this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default = False)
#api.onchange('virtual_available')
def qtychanged(self):
self.was_changed = True
_logger.info('Product_Qty_Cahnged: %s',str(self.virtual_available))
In this code, if the forecasted quantity of a product would change, the variable was_changed should be set to True, but nothing happens.
After that, I tried to overwrite the write method for my custom class, like this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default=False)
#api.multi
def write(self, values):
if values['virtual_available']:
values['was_changed'] = True
# THE FOLLOWING LINES WERE IN THE ORIGINAL WRITE METHOD
res = super(MyProduct, self).write(values)
if 'standard_price' in values:
self._set_standard_price(values['standard_price'])
return res
But still, I have the same result. I can't seem to get that flag to change. So, any ideas?
Try this:
class MyProduct(models.Model):
_inherit = 'product.product'
was_changed = fields.Boolean(default = False)
#api.onchange('virtual_available')
def qtychanged(self):
self.write({'was_changed': True})
_logger.info('Product_Qty_Cahnged: %s',str(self.virtual_available))

Is there a converter between django.forms.Form and rest_framework.serializers?

I already have plenty of forms defined in my django 1.9 project. Now I need to export them as REST (DRF 3.5.3) as well.
With just a bit of hacking, I was able to provide GET and PUT methods. But I also need to provide the OPTIONS method and I can't seem to find anything that would help me do that.
So, is there something that would convert an instanced form to DRF Serializer / ViewSet?
No but you can do the other way around as explained in http://www.django-rest-framework.org/topics/html-and-forms/#rendering-forms.
drf-braces can do this.
from django import forms
from drf_braces.serializers.form_serializer import FormSerializer
class MyForm(forms.Form):
foo = forms.CharField(max_length=32)
bar = forms.DateTimeField()
class MySerializer(FormSerializer):
class Meta(object):
form = MyForm
https://github.com/dealertrack/django-rest-framework-braces/blob/master/docs/overview.rst
I didn't want to mess with all of my custom logic in the forms, so I just added an as_options method:
class APIViewForm(Form):
def as_dict(self):
return {fld.auto_id: self.initial.get(fld.name, None) for fld in self}
def as_options(self):
flds = {}
for fld in self:
flds[fld.name] = f = {}
fld = fld.field
f.update(dict(
required=fld.required,
read_only=fld.disabled,
label=fld.label,
))
if isinstance(fld, (CharField, URLField)):
f['type'] = 'field'
if fld.max_length:
f['max_length'] = fld.max_length
if fld.min_length:
f['min_length'] = fld.min_length
elif isinstance(fld, IntegerField):
f['type'] = 'integer'
if fld.max_value:
f['max_value'] = fld.max_value
if fld.min_value:
f['min_value'] = fld.min_value
elif isinstance(fld, ChoiceField):
f['type'] = 'choice'
f['choices'] = [dict(value=c[0], display_name=c[1]) for c in fld.choices]
elif isinstance(fld, DateTimeField):
f['type'] = 'datetime'
return dict(
name=self.__class__.__qualname__,
description='',
renders=['application/json'],
parses=['application/json'],
actions=dict(PUT=flds)
)
It seems to do the trick

Call a method as a field of ValuesQuerySet

I have a model and a method on it as follows:
class Results(models.Model):
t_id = models.TextField(blank=True)
s_result_id = models.TextField(blank=True,primary_key=True)
s_name = models.TextField(blank=True)
s_score = models.FloatField(blank=True, null=True)
... (some other fields with huge data)
def get_s_score(self):
return 100 * self.s_score
On a view, I am trying to call get_s_score method from inside values. I have to use values to avoid selecting other fields with huge data.
def all_recentsiteresults(request,t_id1):
Result = Results.objects.filter(t_id=t_id1).values('s_result_uid','s_name',get_s_score())
You can't use the model's method in the values() method. But you can use the only() method to decrease the memory usage:
Results.objects.only('s_result_id', 's_name', 's_score').filter(t_id=t_id1)

How to get one query from two models?

I have two models:
class ModManager(models.Manager):
def myfilter(self, options = dict()):
if options.has_key('not_image'):
kwargs['image__isnull'] = False
return self.filter(**kwargs)
class Model_1(models.Model):
...
objects = MyManager()
class Model_2(models.Model):
something = models.ForeignKey(Model_1)
something_else = ...
...
How to get all data from Model_2 related to Model_1 in MyManager? I want to get one query. I have so far:
in Model_1:
def get_model_2(self):
self.model_2_objs = self.model_2_set.all()
But it generates many queries when I calling get_model_2 function.