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,)))
Related
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
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
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)
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.
i having problem with this:
model.py (1)
class Profession(models.Model):
user= models.ForeignKey(User,unique=True)
principal_area = models.ForeignKey(Area,verbose_name='Area principal',related_name='area_principal')
others_areas = models.ManyToManyField(Area)
model.py (2)
class Area(models.Model):
area = models.CharField(max_length=150,unique=True)
slug = models.SlugField(max_length=200)
activa = models.BooleanField(default=True)
In Model 1 i have a field "principal_area" and other "others_areas".
How ill list all professional where "principal_area" OR "others_areas" are in Area model from my views?
Sorry if im not too clear
Take a look at Django's Q objects. Here is an example of how you could go about this:
area = Area.objects.get(**conditions)
Profession.objects.filter(
Q(principal_area = area) | Q(others_areas__in = [area])
)