Django: Cannot validate a form without an initial foreignkey value - python

I have a form in django views.py.
diagnosis.patient is a foreignkey of demographics.patient_id.
my_diagnosis form is not valid because patient is empty. Is there a way to fix this?
def input(request):
context = RequestContext(request)
print context
ret = cache.get('input-rendered')
if request.method == 'POST':
my_demographics = DemographicForm(request.POST, prefix="demo")
my_diagnosis = DiagnosisForm(request.POST, prefix='diag')
if (my_demographics.is_valid() ):
print "dem and diag validation"
my_demographics_object = my_demographics.save(commit=False)
my_demographics_object.author = request.user
my_demographics_object.save()
#my_diagnosis = DiagnosisForm(request.POST, prefix='diag', initial={'patient':my_demographics_object.patient_id} )
print "my dem id"
print my_demographics_object.patient_id
if (my_diagnosis.is_valid()):
my_diagnosis_object=my_diagnosis.save(commit=False)
my_diagnosis_object.patient = my_demographics_object.patient_id
my_diagnosis_object.author = request.user
my_diagnosis_object.save()
This is my Diagnosis form in forms.py:
class DiagnosisForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(DiagnosisForm, self).__init__(*args, **kwargs)
self.fields['diagnosis_circumstances_date']= forms.DateField(label=('Date'),required=False,
widget=DateTimePicker(options={"format": "YYYY-MM-DD",
"pickTime": False,
"startDate": "1900-01-01"}))
self.helper=FormHelper(form=self)
self.fields['icd_10_desc']= forms.ModelChoiceField(queryset=icd_10.objects.all(),
widget=autocomplete_light.ChoiceWidget("icd_10Autocomplete"))
self.fields['icd_10_desc'].label = "ICD-10 description"
diagnosis_option_value = (
('b-thalassaemia syndromes', 'b-thalassaemia syndromes',),
('a-thalassaemia syndromes', 'a-thalassaemia syndromes'),
('Sickle cell syndromes', 'Sickle cell syndromes'),
('Other haemoglobin variants','Other haemoglobin variants'),
('Red cell membrane disorders','Red cell membrane disorders'),
('Red cell enzyme disorders','Red cell enzyme disorders'),
('Congenital dyserythropoietic anaemias','Congenital dyserythropoietic anaemias')
)
self.fields['diagnosis_option']=forms.MultipleChoiceField(choices=diagnosis_option_value, widget=forms.CheckboxSelectMultiple())
diagnosis_circumstances_value = (
('Antenatal diagnosis','Antenatal diagnosis'),
('Neonatal diagnosis','Neonatal diagnosis'),
('By the presence of affected related','By the presence of affected related'),
('Clinical diagnosis', 'Clinical diagnosis'),
('Other','Other')
)
self.fields['diagnosis_circumstances']=forms.MultipleChoiceField(choices=diagnosis_circumstances_value, widget=forms.CheckboxSelectMultiple())
#self.fields['patient'].queryset = Demographic.objects.filter(patient_id=self.instance.patient)
self.helper.field_class = 'col-md-8'
self.helper.label_class = 'col-md-3'
#self.helper.form_class = 'forms-horizontal'
self.helper.layout = Layout(
Fieldset (
# 'patient',
'<b>Diagnosis information</b>',
Div(
#HTML(u'<div class="col-md-2"></div>'),
Div('age_of_diagnosis',css_class='col-md-6'),
Div('age_at_onset_of_symptoms',css_class="col-md-6"),
css_class='row',
),
'diagnosis_option',
'record_of_genotype',
'icd_10_desc',
'icd_10_code',
'orpha_code',
'comment',
),
FormActions(
Submit('submit', "Save changes"),
Submit('cancel',"Cancel")
),
)
self.helper.form_tag = False
self.helper.form_show_labels = True
class Meta:
model = Diagnosis
exclude = ['patient']
exclude = ('author',)
list_display = ('title', 'pub_date', 'author')
This is the result of my_diagnosis.errors:
<ul class="errorlist"><li>patient<ul class="errorlist"><li>This field is required.</li></ul></li></ul>

If you are setting the patient in the view, then just leave the patient form out of the list of fields for you model form:
DiagnosisForm(forms.ModelForm):
class Meta:
model = Diagnosis
fields = ('myfield1', 'myfield2', ...)
You can use exclude if you prefer:
DiagnosisForm(forms.ModelForm):
class Meta:
model = Diagnosis
exclude = ('author', 'patient',)
The problem in your current form is that you have
exclude = ['patient']
exclude = ('author',)
The second exclude replaces the first. You should have:
exclude = ['author', 'patient']
See the model form docs on selecting the fields to use for more info.

Related

Adding help text to a django from

I want to add help text/tool tip when a user hovers over a form field.
I have a model form based on this model:
class MyModel(TimeStampedModel):
MY_CHOICES = [tuple([x,x]) for x in range(1,8)]
p1 = models.IntegerField("P1", default='1', help_text='text1')
p2 = models.IntegerField("P2", default='1', , help_text='text2')
Parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
The form itself looks like:
class MyModelForm(ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.form_id = 'id-CaseForm'
self.helper.form_class = 'blueForms'
self.helper.form_method = 'post'
self.helper.form_tag = False
self.helper.help_text_inline = False
self.helper.form_show_labels = False
self.helper.layout = Layout(
Row(Field(PrependedText('p1', 'field_label1', wrapper_class='col-12 col-lg-6 pe-0 stretchprepend'))),
Row(Field(PrependedText('p2', 'field_label2', wrapper_class='col-12 col-lg-6 pe-0 stretchprepend'))))
CHOICES = [tuple([x,x]) for x in range(1,8)]
p1 = IntegerField( label='field_label1', widget=Select(choices=CHOICES))
p2 = IntegerField( label='field_label2', widget=Select(choices=CHOICES))
class Meta:
model = MyModel
fields = ['p1', 'p2',]
And this is displayed as a crispy form in the template:
{% crispy MyModelForm %}
I want the user to see some help text when they hover over the fields. This help text could be the help_text from the model, or I am happy to put it somewhere else (although it should go in either the model or the form, not in the template). Any help appreciated.

How to limit displayed django form choices depending on the url a user is at?

I have users arrive at /drug_assess/?p=drugtype1 or /drug_assess/?p=drugtype2
The view for the page :
class CaseView(LoginRequiredMixin, TemplateView):
model = Case
template_name = "se_balance/se_balance.html"
def get(self, *args, **kwargs):
p = self.request.GET.get("p", None)
sideeffect_formset = SideeffectFormSet(queryset=SideEffect.objects.none(),)
return self.render_to_response(
{ "page_title": p.capitalize(),
"sideeffect_formset": sideeffect_formset,
"sideeffect_formsethelper": SideEffectFormSetSetHelper,
}
)
renders a formset:
SideeffectFormSet = inlineformset_factory(
Case,
SideEffect,
fields=("se_name", "concern"),
widgets={'concern': RangeInput()},
extra=0,
min_num=1,
validate_min=True,
)
That is based on this model:
class SideEffect(TimeStampedModel):
SE_CHOICES = [
("weight_gain", "Weight Gain"),
("parkinsonism", "Parkinsonism"),
("dystonia", "Dystonia"),
("tardive_dyskinesia", "Tardive Dyskinesia"),
("akathisia", "Akathisia"),
("prolactin", "Hyperprolactinaemia"),
("qtc", "QT Prolongation"),
("cholinergic", "Anticholinergic Side Effects"),
("sedation", "Sedation"),
("none", "None"),
]
se_name = models.CharField("",max_length=200, choices=SE_CHOICES, default="none")
concern = models.IntegerField("",default=50)
case = models.ForeignKey(Case, on_delete=models.CASCADE)
The user sees a dropdown that has all the options from SE_CHOICES available but I want to only show a subset of these depending on whether the user is at /drug_assess/?p=drugtype1 or /drug_assess/?p=drugtype2

DeclarativeFieldsMetaclass object argument after ** must be a mapping, not int

I am trying to pass kwargs to my forms.py file, when the form is loaded I get an error saying my car_id is not defined on my forms.py file. I know this is because of the below line of code but I do not know how to fix it.
form = SelectCarModelForm()
forms.py
def __init__(self, *args, **kwargs):
self.car_id = kwargs.pop('car_id', None)
super(SelectCarModelForm, self).__init__(*args, **kwargs)
self.fields['car_model'] = forms.ModelChoiceField(
empty_label = "Select a Model",
queryset = CarModel.objects.filter(model=car_id),
widget = Select(attrs={'class': 'span12 small-margin-top small-margin-bottom'}),
required=True
)
view
if request.method == "POST":
form = SelectCarModelForm(request.POST)
if form.is_valid():
model = form.cleaned_data['car_model']
# Go to the next form in the process.
return redirect('view_car')
# Initial form
else:
form = SelectCarModelForm()
return render(
request,
template_name = 'cars/forms/view_car_models.html',
dictionary = {
'form':form,
}
)
You either do this:
# pass a `car_id` value when instantiating the form
form = SelectCarModelForm(car_id=<some_value>)
and if that's not feasible, maybe this:
def __init__(self, *args, **kwargs):
self.car_id = kwargs.pop('car_id', None)
super(SelectCarModelForm, self).__init__(*args, **kwargs)
if self.car_id is not None:
self.fields['car_model'] = forms.ModelChoiceField(
empty_label = "Select a Model",
queryset = CarModel.objects.filter(model=car_id),
widget = Select(attrs={'class': 'span12 small-margin-top small-margin-bottom'}),
required=True
)
else:
self.fields['car_model'] = forms.ModelChoiceField(
empty_label = "Select a Model",
queryset = CarModel.objects.filter(model=<SOME-OTHER-CRITERIA),
widget = Select(attrs={'class': 'span12 small-margin-top small-margin-bottom'}),
required=True
)

How to change form fields' value before validation?

I have an FloatField in my models.py that has to store (among other things) minutes, seconds and milliseconds. It's no biggie to store them in the format of ss.ms, but I have to provide a possibility to insert them via ModelForm in the format of mm.ss.ms.
Problem is, form validation disapproves of mm.ss.ms for FloatField and I'm struggling to find a workaround.
_clean functions are great, but run after the Django validations. How to clean data from form before it gets validated by Django?
EDIT:
models.py
from django.db import models
class Result(models.Model):
date = models.DateField()
result = models.FloatField()
rank = models.IntegerField(blank=True, null=True)
forms.py
class AddResult(forms.ModelForm):
class Meta:
model = Result
fields = ('result', 'rank', 'date')
def __init__(self, *args, **kwargs):
self.profile = kwargs.pop('profile', None)
super(AddResult, self).__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.label_class = 'form-label-div'
self.helper.field_class = 'form-field-div'
self.helper.label_class = 'col-xs-4'
self.helper.field_class = 'col-xs-8'
self.helper.layout = Layout(
Div(
Div(
'result',
css_class="col-xs-4",
),
Div(
'rank',
css_class="col-xs-4",
),
css_class="row",
),
Div(
Div(
'date',
css_class="col-xs-4",
css_id="date-picker"
),
Div(
css_class="col-xs-4",
css_id="date-picker"
),
css_class="row",
)
)
def save(self, commit=True):
result = super(AddResult, self).save(commit=False)
if self.profile:
result.profile = self.profile
result.save()
PS! Originally I wrote that I had a problematic IntegerField, but that was some kind of a brain fart. We're talking about a FloatField of course. The main question remains the same.
I would suggest you not to use models forms instead use a forms.form and in your view before the ** form.is_valid() ** try to retrieve the form fields with the help of REQUEST method.
May be this helps.

Django form insert record instead of update record

I am having some issues trying to update some records in Django:
When i try to update some record, the app insert a new one, I don't know why i have this behavior.
Model
class DetalleRecepcion(models.Model):
id_proveedor = models.ForeignKey(Proveedor,db_column='id_proveedor',primary_key=True, verbose_name='Proveedor')
anio = models.IntegerField( null=False)
mes = models.IntegerField(verbose_name='Mes')
fecha_recepcion = models.DateField(verbose_name='Fecha Recepcion')
usuario = models.CharField(max_length=15, blank=True)
num_archivos = models.IntegerField(primary_key=True, verbose_name='No de archivos')
class Meta:
managed = False
db_table = 'mpc_detalle_recepcion'
view:
#login_required(login_url='/login/')
def DetRecView(request):
idp = request.GET.get('i')
anio = request.GET.get('a')
mes = request.GET.get('m')
if request.method == 'POST':
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
form = DetRecForm(request.POST or None, instance =r)
if form.is_valid():
form.save()
return HttpResponse('<script type="text/javascript">window.close()</script>')
else:
r = DetalleRecepcion.objects.get(id_proveedor=idp,anio=anio,mes=mes)
r.usuario = request.user
form = DetRecForm(instance=r)
return render_to_response('detrec.html',
{'form':form},
context_instance=RequestContext(request))
Form:
class DetRecForm(forms.ModelForm):
fecha_recepcion = forms.DateField(widget=DateInput(),)
def __init__(self,*args,**kwargs):
super(DetRecForm,self).__init__(*args,**kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Field('id_proveedor',
'anio',
'mes',
'usuario',
readonly = True
),
Fieldset('',
'fecha_recepcion',
'num_archivos',
Submit('save','Grabar'),
HTML('<a class="btn btn-danger" id="cerrar">Cancelar</a>')
)
)
class Meta:
model = DetalleRecepcion
I use the same view and form definition for others models to render edit forms and with this other models works great and the records are updated.
I don't understand what it's happen.
I rewrite the form, view definition for this model and I don't know what it is the problem.
The database is a legacy database and the tables doesn't have any kind of relationship or constraint.
By the way I am using Django crispy form
Thanks in advance
If you using same form for create and update views, then you need provide clean method on your unique field and raise ValidationError when object exists.
But in your case, I assuming you using Composite Primary Key on fields: id_proveedor, num_archivos, you should override clean method of the whole form:
class DetRecForm(forms.ModelForm):
fecha_recepcion = forms.DateField(widget=DateInput())
def __init__(self, *args, **kwargs):
super(DetRecForm, self).__init__(*args, **kwargs)
self.helper = FormHelper(self)
self.helper.layout = Layout(
Field('id_proveedor',
'anio',
'mes',
'usuario',
readonly=True
),
Fieldset('',
'fecha_recepcion',
'num_archivos',
Submit('save', 'Grabar'),
HTML('<a class="btn btn-danger" id="cerrar">Cancelar</a>')
)
)
def clean(self):
cleaned_data = super(DetRecForm, self).clean()
id_proveedor = self.cleaned_data['id_proveedor']
num_archivos = self.cleaned_data['num_archivos']
qs = self.Meta.model.objects.filter(id_proveedor=id_proveedor, num_archivos=num_archivos)
if self.instance:
qs = qs.exclude(pk=self.instance.id)
if qs.count() > 0:
raise forms.ValidationError(u'Such object exists!')
return cleaned_data
class Meta:
model = DetalleRecepcion
Try to get object by pk for instance
DetalleRecepcion.objects.get(pk=kwargs['pk'])

Categories