I have a BooleanField (ran_bug) in my Randomisation models that is displayed as a checkbox.
Click on the checkbox sould show 2 other fields that are not mandatory (ran_dem_nom and ran_dem_dat).
My problem is that, when I 'check' the checkbox, it return 'on' instead of true.
And I got an error when I try to registered data:
django.core.exceptions.ValidationError: ["'on' value must be either True, False, or None."]
models.py
class Randomisation(models.Model):
ran_ide = models.AutoField(primary_key=True)
pay_ide = models.ForeignKey(Pays, on_delete = models.CASCADE) # related country
ran_str_num = models.CharField("Logical numerotation", max_length=2, null=True, blank=True)
ran_bra = models.CharField("Arm", max_length=1, null=True, blank=True)
bra_lib = models.CharField("Arm label", max_length=50, null=True, blank=True)
ran_act = models.IntegerField("Activated line", null=True, blank=True)
pat = models.CharField("Patient number", max_length=12, unique=True, null=True, blank=True)
ran_nai = models.IntegerField("Patient birthdate (year)", blank=True)
ran_sex = models.IntegerField("Sex", null=True, blank=True)
ran_st1 = models.IntegerField("Stratification variable 1", blank=True)
ran_st2 = models.IntegerField("Stratification variable 2", blank=True)
ran_bug = models.BooleanField("Use of alternative randomization procedure?", null=True, blank=True)
ran_dem_nom = models.CharField("Name of the person asking for randomization", max_length=12, null=True, blank=True) # hide at pageload
ran_dem_dat = models.DateField("Date of demand", null=True, blank=True) # hide at pageload
ran_log = models.CharField("User", max_length=12, null=True, blank=True)
ran_dat = models.DateTimeField("Date", null=True, auto_now_add=True, blank=True)
forms.py
class RandomizationEditForm(forms.Form):
def __init__(self, request, *args, **kwargs):
super(RandomizationEditForm, self).__init__(*args, **kwargs)
self.user_country = Pays.objects.get(pay_ide = request.session.get('user_country'))
self.user_site_type = request.session.get('user_site_type')
PAYS = Pays.options_list(self.user_country,self.user_site_type,'fr')
SEXE = Thesaurus.options_list(2,'fr')
STRATE_1 = Thesaurus.options_list(3,'fr')
STRATE_2 = Thesaurus.options_list(4,'fr')
YES = [(None,''),(0,'Non'),(1,'Oui'),]
self.fields["pay_ide"] = forms.IntegerField(label = "Pays", initial=2, widget=forms.HiddenInput())
self.fields["pat"] = forms.CharField(label = "Numéro patient (XXX-0000)")
self.fields['pat'].widget.attrs.update({
'autocomplete': 'off'
})
self.fields["ran_nai"] = forms.IntegerField(label = "Date de naissance (année)", widget=forms.TextInput)
self.fields['ran_nai'].widget.attrs.update({
'autocomplete': 'off'
})
self.fields["ran_sex"] = forms.ChoiceField(label = "Sexe", widget=forms.Select, choices=SEXE)
self.fields["ran_st1"] = forms.ChoiceField(label = "Gravité de la maladie COVID-19", widget=forms.Select, choices=STRATE_1)
self.fields["ran_bug"] = forms.BooleanField(label = "Recours à la procédure de secours ?", required = False)
self.fields["ran_dem_nom"] = forms.CharField(label = "Nom de la personne qui demande la randomisation", required = False)
self.fields['ran_dem_nom'].widget.attrs.update({
'autocomplete': 'off'
})
self.fields["ran_dem_dat"] = forms.DateField(
# input_formats=settings.DATE_INPUT_FORMATS,
label = "Date de la demande",
initial = timezone.now(),
required = False,
)
self.fields['ran_dem_dat'].widget.attrs.update({
'autocomplete': 'off'
})
JS
$(function(){
$("#div_id_ran_dem_nom").hide();
$("#div_id_ran_dem_dat").hide();
});
// affichage des champs en fonction de la valeur sélectionnée dans la liste
$("#div_id_ran_bug").on("change", function(event){
console.log($("#id_ran_bug").val())
if ($("#id_ran_bug").is(":checked")){
$("#div_id_ran_dem_nom").show();
$("#div_id_ran_dem_dat").show();
}
else {
$("#div_id_ran_dem_nom").hide();
$("#div_id_ran_dem_dat").hide();
}
});
views.py
def randomization_edit(request):
if request.method == "POST":
form = RandomizationEditForm(request, data=request.POST or None)
if form.is_valid():
# Récupération des données permettant la randomisation
randomisation = Randomisation.objects.filter(Q(pay_ide=form.data.get('pay_ide')) & Q(ran_act=1) & Q(ran_st1=form.data.get('ran_st1')) & Q(pat=None)).first()
randomisation.pat = form.data.get('pat')
randomisation.ran_nai = form.data.get('ran_nai')
randomisation.ran_sex = form.data.get('ran_sex')
randomisation.ran_bug = form.data.get('ran_bug')
randomisation.ran_dem_nom = form.data.get('ran_dem_nom')
randomisation.ran_dem_dat = form.data.get('ran_dem_dat')
print('ran_bug',form.data.get('ran_bug'))
randomisation.ran_log = request.user.username
randomisation.ran_dat = timezone.now()
randomisation.save()
return redirect('randomization:confirmation', pk = randomisation.pk)
else:
form = RandomizationEditForm(request)
return render(request, 'randomization/edit.html', {'form': form})
OK, i resolve my problem: form.cleaned_data['ran_bug'] instead of form.data.get('ran_bug')
Related
I have already posted (see link below) to 'valid' my ER diagram.
I try to develop a form based on 'trought' model with nested inlineformset.
It works when I define fields in the UtilisateurCreateView class but I want to customize the 'trought' parent's form to be able to:
set initial pro_ide value with value send by GET
hidden this pro_ide field
customize uti_ide field label
So I define a UtilisateurProjetCreateForm based on the 'throught' model like I'm used to do but I got an error:
Cannot assign "'Slater, Kelly (k.slater#surf.com)'": "UtilisateurProjet.uti_ide" must be a "Utilisateur" instance.
moreover, as this form is based on 'throught' model, I am not sure I should define forms.ChoiceField...
models.py
class Projet(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
pro_ide = models.AutoField(primary_key = True)
# utilisateurs = models.ManyToManyField(Utilisateur, through='UtilisateurProjet')
pro_nom = models.IntegerField("Nom du projet")
pro_log = models.CharField("Log utiisateur", max_length=20, null=True, blank=True)
pro_dat = models.DateTimeField("Date log",auto_now_add=True)
pro_act = models.IntegerField("Projet en cours ?", null=True, blank=True)
class Meta:
db_table = 'tbl_pro'
verbose_name_plural = 'Projets'
ordering = ['pro_ide']
permissions = [
('can_add_project','Can add project'),
]
def __str__(self):
return f"{self.pro_nom}"
class Utilisateur(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
uti_ide = models.AutoField(primary_key = True)
# pro_ide = models.ForeignKey(Projet, on_delete = models.CASCADE) # related project
projets = models.ManyToManyField(Projet, through='UtilisateurProjet')
uti_nom = models.CharField("Nom", max_length=20)
uti_pre = models.CharField("Prénom", max_length=20)
uti_mai = models.CharField("Email", max_length=40)
uti_sit = models.CharField("Equipe", max_length=20, null=True, blank=True)
uti_pro = models.CharField("Fonction/profil", max_length=200, null=True, blank=True)
uti_dem_dat = models.DateTimeField("Date demande",auto_now_add=True, null=True, blank=True)
uti_val = models.IntegerField("Demande validée ?", null=True, blank=True)
uti_val_dat = models.DateTimeField("Date validation",null=True, blank=True)
uti_log = models.CharField("Log utilisateur", max_length=20, null=True, blank=True)
uti_dat = models.DateTimeField("Date log",auto_now_add=True, null=True, blank=True)
class Meta:
db_table = 'tbl_uti'
verbose_name_plural = 'Utilisateurs'
ordering = ['uti_ide']
def __str__(self):
return f"{self.uti_nom}, {self.uti_pre} ({self.uti_mai})"
class UtilisateurProjet(models.Model):
_safedelete_policy = SOFT_DELETE_CASCADE
pro_uti_ide = models.AutoField(primary_key = True)
uti_ide = models.ForeignKey(Utilisateur, on_delete=models.CASCADE)
pro_ide = models.ForeignKey(Projet, on_delete=models.CASCADE)
class Meta:
db_table = 'tbl_pro_uti'
class Application(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
app_ide = models.AutoField(primary_key = True)
# uti_ide = models.ForeignKey(Utilisateur, on_delete = models.CASCADE) # related utilisateur
pro_uti_ide = models.ForeignKey(UtilisateurProjet, on_delete = models.CASCADE) # related utilisateur-projet
app_app_nom = models.IntegerField("Nom application", null=True, blank=True)
app_dro = models.IntegerField("Droit sur application", null=True, blank=True)
app_sta = models.IntegerField("Statut (création/Modification/Suppression", null=True, blank=True)
app_log = models.CharField("Log utilisateur", max_length=20, null=True, blank=True)
app_dat = models.DateTimeField("Date log",auto_now_add=True, null=True, blank=True)
class Meta:
db_table = 'tbl_app'
verbose_name_plural = 'Applications'
ordering = ['app_ide']
views.py
# https://stackoverflow.com/questions/29981690/django-form-validation-on-class-based-view
class UtilisateurCreateView(FormView):
template_name = 'project/utilisateurprojet_form.html'
form_class = UtilisateurProjetCreateForm
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
if self.request.POST:
data["utilisateur"] = self.request.user.username # nom de l'utilisateur connecté
data["projet"] = get_object_or_404(Projet, pro_ide = self.request.GET['projet'])
data["application"] = ApplicationFormset(self.request.POST)
else:
data["application"] = ApplicationFormset()
return data
def form_valid(self, form):
context = self.get_context_data()
application = context["application"]
self.object = form.save(commit=False)
self.object.uti_log = context["utilisateur"]
self.object.save()
if application.is_valid():
application.instance = self.object
application.save()
return super().form_valid(form)
def get_success_url(self):
return reverse("project:index")
forms.py
ApplicationFormset = inlineformset_factory(
UtilisateurProjet, Application,
fields=('app_app_nom','app_dro'),
widgets={
'app_app_nom': forms.Select(choices=NAME),
'app_dro': forms.Select(choices=ACCESS)
},
extra=3,
can_delete=True,
)
class UtilisateurProjetCreateForm(forms.ModelForm):
PROJETS = [(Projet.objects.get(pro_ide=1),'Coverage Africa'),]
UTILISATEURS = [(Utilisateur.objects.get(uti_ide=1),'Slater'),]
pro_ide = forms.ChoiceField(label = "Nom projet", widget = forms.Select, choices = PROJETS, initial = Projet.objects.get(pro_ide=1), disabled=True)
uti_ide = forms.ChoiceField(label = "Nom, prénom de l'utilisateur", widget = forms.Select, choices = UTILISATEURS)
class Meta:
model = UtilisateurProjet
fields = ('pro_ide','uti_ide')
related post
I had to use ModelChoiceFiled in my ModelForm:
class UtilisateurProjetCreateForm(forms.ModelForm):
PROJETS = Projet.objects.all()
UTILISATEURS = Utilisateur.objects.all()
pro_ide = forms.ModelChoiceField(queryset = PROJETS, label = "Nom projet", widget = forms.Select, initial = Projet.objects.get(pro_ide=1))
uti_ide = forms.ModelChoiceField(queryset = UTILISATEURS, label = "Nom, prénom de l'utilisateur", widget = forms.Select)
class Meta:
model = UtilisateurProjet
fields = ('pro_ide','uti_ide')
I have followed this tutorial to implement inlneformset.
CreateView works (data is registered in database) but UpdateView doesn't.
UpdateView is correctly displayed with correct data.
But it seems like subform (application inlineformset) is never valid and I don't understand why?
forms.py:
NAME = Thesaurus.options_list(2,'fr')
ACCESS = Thesaurus.options_list(3,'fr')
ApplicationFormset = inlineformset_factory(
Utilisateur, Application,
fields=('app_app_nom','app_dro'),
widgets={
'app_app_nom': forms.Select(choices=NAME),
'app_dro': forms.Select(choices=ACCESS)
},
extra=3,
can_delete=True,
)
models.py:
class Projet(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
pro_ide = models.AutoField(primary_key = True)
pro_nom = models.IntegerField("Nom du projet", null=True, blank=True)
pro_log = models.CharField("Log utiisateur", max_length=20, null=True, blank=True)
pro_dat = models.DateTimeField("Date log",auto_now_add=True)
pro_act = models.IntegerField("Projet en cours ?", null=True, blank=True)
log = HistoricalRecords()
class Meta:
db_table = 'tbl_pro'
verbose_name_plural = 'Projets'
ordering = ['pro_ide']
permissions = [
('can_add_project','Can add project'),
]
class Utilisateur(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
uti_ide = models.AutoField(primary_key = True)
pro_ide = models.ForeignKey(Projet, on_delete = models.CASCADE) # related project
uti_nom = models.CharField("Nom", max_length=20, null=True, blank=True)
uti_pre = models.CharField("Prénom", max_length=20, null=True, blank=True)
uti_mai = models.CharField("Email", max_length=40, null=True, blank=True)
uti_sit = models.CharField("Equipe", max_length=20, null=True, blank=True)
uti_pro = models.CharField("Fonction/profil", max_length=200, null=True, blank=True)
uti_dem_dat = models.DateTimeField("Date demande",auto_now_add=True, null=True, blank=True)
uti_val = models.IntegerField("Demande validée ?", null=True, blank=True)
uti_val_dat = models.DateTimeField("Date validation",auto_now_add=True, null=True, blank=True)
uti_log = models.CharField("Log utilisateur", max_length=20, null=True, blank=True)
uti_dat = models.DateTimeField("Date log",auto_now_add=True, null=True, blank=True)
log = HistoricalRecords()
#classmethod
def options_list(cls,pro_ide):
projet = Projet.objects.get(pro_ide=pro_ide)
utilisateurs = Utilisateur.objects.filter(pro_ide=projet.pro_ide)
the_opts_list = [(utilisateur.uti_ide, utilisateur.uti_nom+', '+utilisateur.uti_pre) for utilisateur in utilisateurs]
the_opts_list.insert(0, (None, ''))
return the_opts_list
class Meta:
db_table = 'tbl_uti'
verbose_name_plural = 'Utilisateurs'
ordering = ['uti_ide']
class Application(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
app_ide = models.AutoField(primary_key = True)
uti_ide = models.ForeignKey(Utilisateur, on_delete = models.CASCADE) # related utilisateur
app_app_nom = models.IntegerField("Nom application", null=True, blank=True)
app_dro = models.IntegerField("Droit sur application", null=True, blank=True)
app_sta = models.IntegerField("Statut (création/Modification/Suppression", null=True, blank=True)
app_log = models.CharField("Log utilisateur", max_length=20, null=True, blank=True)
app_dat = models.DateTimeField("Date log",auto_now_add=True, null=True, blank=True)
log = HistoricalRecords()
class Meta:
db_table = 'tbl_app'
verbose_name_plural = 'Applications'
ordering = ['app_ide']
class Administration(SafeDeleteModel):
_safedelete_policy = SOFT_DELETE_CASCADE
adm_ide = models.AutoField(primary_key = True)
app_ide = models.ForeignKey(Application, on_delete = models.CASCADE) # related application
adm_nom = models.CharField("Nom d'utilisateur dans l'application", max_length=20, null=True, blank=True)
adm_dem = models.IntegerField("Demande traitée ?", null=True, blank=True)
adm_dem_dat = models.DateTimeField("Date traitement de la demande",auto_now_add=True)
adm_log = models.CharField("Log utilisateur", max_length=20, null=True, blank=True)
adm_dat = models.DateTimeField("Date log",auto_now_add=True)
log = HistoricalRecords()
class Meta:
db_table = 'tbl_adm'
verbose_name_plural = 'Adminitrations'
ordering = ['adm_ide']
permissions = [
('can_manage_project','Can manage project'),
]
UpdateView:
class UtilisateurUpdateView(UpdateView):
model = Utilisateur
fields = ['uti_nom','uti_pre','uti_mai','uti_sit','uti_pro']
def get_context_data(self, **kwargs):
data = super().get_context_data(**kwargs)
if self.request.POST:
data["utilisateur"] = self.request.user.username
data["application"] = ApplicationFormset(self.request.POST, instance=self.object)
else:
data["application"] = ApplicationFormset(instance=self.object)
return data
def form_valid(self, form):
context = self.get_context_data()
application = context["application"]
self.object = form.save()
self.object.save()
if application.is_valid(): # ***** NEVER VALID *****
application.instance = self.object
print('application.instance',application.instance)
application.app_app_nom = application.instance.cleaned_data['app_app_nom']
application.app_dro = application.instance.cleaned_data['app_dro']
application.app_log = context["utilisateur"]
application.uti_ide = 1
application.save()
return super().form_valid(form)
def get_success_url(self):
return reverse("project:index")
I have resolve my problem: I forget to insert form_set id in my html template (app_ide in my case)
I have override init in RandomisationFOrm and have an error I did not have before
I understand the error: in my models Randomization ran_num field is UNIQUE
and when I try to save a form when I call randomisation_edit view with the same ran_num it raise error
but before overriding __init__, this error was manage by Django itself
I try to add validation as below but raise another error: 'RandomisationForm' object has no attribute 'clean_data' -> I do the same for other field without this error...
def clean_ran_num(self):
data = self.clean_data['ran_num']
if data == 'CIV-CO-001':
raise forms.validationError('test')
return data
I try to add validation in the global 'clean' method but it do not apply...
I do not understand...
models.py
class Randomisation(models.Model):
# ran_num = models.CharField("Patient code", max_length=10, unique=True, null=True, blank=True,validators=[validate_patient_code])
ran_ide = models.AutoField(primary_key=True)
ran_num = models.CharField("Patient code", max_length=10, unique=True, null=True, blank=True)
ran_dat = models.DateField("Date of randomization", null=True, blank=True)
ran_inv = models.CharField("Investigator", max_length=20, null=True, blank=True)
ran_pro = models.IntegerField("Procedure used to randomized", null=True, blank=True)
ran_pro_per = models.CharField("if telephone, name of the person reached on the phone", max_length=20, null=True, blank=True)
ran_crf_inc = models.IntegerField("Was the CRF inclusion 2 Eligibility fulfilled?", null=True, blank=True)
ran_tbc = models.IntegerField("Is TB diagnosis possible, probable or definite?", null=True, blank=True)
ran_crf_eli = models.IntegerField("Was the CRF Inclusion 2 Eligibility fulffiled?", null=True, blank=True)
ran_cri = models.IntegerField("Is the conclusion All criteria fulfilled for randomisation", null=True, blank=True)
ran_sta = models.IntegerField("British Medical Council Staging (worst stage reported between first symptoms and now)", null=True, blank=True)
ran_vih = models.IntegerField("HIV/AIDS status", null=True, blank=True)
ran_bra = models.IntegerField("TB treatment assigned", null=True, blank=True)
ran_med = models.CharField("Batch number", max_length=6, null=True, blank=True)
ran_log_dat = models.DateTimeField("Date", null=True, blank=True)
ran_log = models.CharField("Name of the person who performs randomisation on site", max_length=10, null=True, blank=True)
forms.py
class RandomisationForm(forms.ModelForm):
# surcharge méthode constructeur (__init__) pour avoir accès aux variables de sessions
# https://stackoverflow.com/questions/3778148/django-form-validation-including-the-use-of-session-data
def __init__(self, request, *args, **kwargs):
self.request = request
super(RandomisationForm, self).__init__(*args, **kwargs)
# vérification que le numéro patient saisi correspond bien au site actuellement sélectionné
# i.e. profil 'International'
def clean(self):
data = self.cleaned_data['ran_num']
if data[4:6] != self.request.session.get('selected_site'):
raise ValidationError(_('Patient code is different from the selected site'))
TYPES = [
(None, ''),
(1, _('On-line')),
(2, _('Telephon')),
]
YESNO = [
(None, ''),
(1, _('Yes')),
(0, _('No')),
]
TB = [
(None, ''),
(1, _('Possible')),
(2, _('Probable')),
(3, _('Definite')),
]
SEVERITY = [
(None, ''),
(1, _('Mild')),
(2, _('Severe')),
]
HIV = [
(None, ''),
(0, _('Negative')),
(1, _('Positive')),
]
ran_dat = forms.DateField(
label = _("Date of randomization"),
initial = datetime.datetime.now,
required = True,
)
ran_num = forms.CharField(label = _("Patient number"), required=True) # ajout
ran_inv = forms.CharField(label = _("Investigator"), required=True)
ran_pro = forms.ChoiceField(label = _("Type"), widget=forms.Select, choices=TYPES)
ran_pro_per = forms.CharField(label = _("if telephone, name of the person reached on the phone"), required=False)
ran_crf_inc = forms.ChoiceField(label = _("Was the CRF inclusion 1 TB diagnosis fulfilled?"), widget = forms.Select, choices = YESNO)
ran_crf_eli = forms.ChoiceField(label = _("Was the CRF Inclusion 2 Eligibility fulffiled?"), widget = forms.Select, choices = YESNO)
ran_tbc = forms.ChoiceField(label = _("Is TB diagnosis possible, probable or definite?"), widget = forms.Select, choices = TB)
ran_cri = forms.ChoiceField(label = _("Is the conclusion All criteria fulfilled for randomisation"), widget=forms.Select, choices = YESNO)
ran_sta = forms.ChoiceField(label = _("British Medical Council Staging (worst stage reported between first symptoms and now)"), widget = forms.Select, choices = SEVERITY)
ran_vih = forms.ChoiceField(label = _("HIV/AIDS status"), widget = forms.Select, choices = HIV)
class Meta:
model = Randomisation
# Tous les champs sauf les champs de log et les champs TB treatment et Drug batch number
fields = ('ran_num','ran_dat','ran_inv','ran_pro','ran_pro_per','ran_crf_inc','ran_tbc','ran_crf_eli','ran_cri','ran_sta','ran_vih',)
def clean_ran_crf_inc(self):
data = self.cleaned_data['ran_crf_inc']
if int(data) == 0:
raise forms.ValidationError(_("This criteria is mandatory for randomization"))
return data
def clean_ran_crf_eli(self):
data = self.cleaned_data['ran_crf_eli']
if int(data) == 0:
raise forms.ValidationError(_("This criteria is mandatory for randomization"))
return data
def clean_ran_cri(self):
data = self.cleaned_data['ran_cri']
if int(data) == 0:
raise forms.ValidationError_(("This criteria is mandatory for randomization"))
return data
views.py
def randomisation_edit(request):
if request.method == "POST":
form = RandomisationForm(request, data=request.POST or None)
if form.is_valid():
randomisation = form.save()
# randomisation
rand = Randomiser(randomisation.ran_num, randomisation.ran_vih, randomisation.ran_sta)
# Mise à jour de la base de données -> Patient code pour rendre indisponible la ligne
# pour une prochaine randomisation
# ListeRandomisation
# 1.Récupération de la ligne dans la liste de rando
bras = rand['bras']
# 2.Mise à jour de la ligne dans la liste de rando
patient = ListeRandomisation.objects.get(ran_ide = bras)
patient.ran_dis = randomisation.ran_num # pat
patient.save()
# Medicament
# 1.Récupération de la ligne dans la liste de correspondance médicament
medicament = rand['medicament']
# 2.Mise à jour de la ligne dans la liste de correspondance médicament
medicament = Medicament.objects.get(med_ide = medicament)
medicament.ran_dis = randomisation.ran_num # pat
medicament.save()
# mise à jour de la variable de session can_randomize
request.session['can_randomize'] = is_randomizable(medicament.ran_dis)
# Mise à jour de la table Randomisation avec le bras et le numéro de boite attribués
randomisation.ran_bra = patient.ran_bra
randomisation.ran_med = medicament.med_num
randomisation.ran_log_dat = datetime.now()
randomisation.ran_log = request.user.username
randomisation.save()
return redirect('randomization:confirmation', pk = randomisation.pk)
else:
form = RandomisationForm(request)
return render(request, 'randomization/randomisation_edit.html', {'form': form})
When you override the Form.clean method you have to call super(RandomisationForm, self).clean() or you will loose the unique constraint checks.
From the docs:
https://docs.djangoproject.com/en/3.0/ref/forms/validation/#cleaning-and-validating-fields-that-depend-on-each-other
The call to super().clean() in the example code ensures that any validation logic in parent classes is maintained. If your form inherits another that doesn’t return a cleaned_data dictionary in its clean() method (doing so is optional), then don’t assign cleaned_data to the result of the super() call and use self.cleaned_data instead:
Django is giving me this error. The solution I've tried does not seem to work. It is asking me to make this an instance of Medication...Am I not already doing that? I'm trying to have two serializers cat and medication under the one careLogSerializer. Is that even possible? How can I best solve this error?
builtins.ValueError
ValueError: Cannot assign "OrderedDict([('name', 'carelog3'), ('duration', 'short'), ('frequency', '4')])": "CareLog.medication" must be a "Medication" instance.
Here is my serializer....
class CareLogSerializer(serializers.HyperlinkedModelSerializer):
cat = CatSerializer()
medication = MedicationSerializer()
# cat = CatSerializer(read_only=True) this allows put BUT TURNS OFF POST
class Meta:
model = CareLog
fields = (
'cat',
'slug',
'foster_manager',
'weight_unit_measure',
'weight_before_food',
'food_unit_measure',
'amount_of_food_taken',
'food_type',
'weight_after_food',
'stimulated',
'medication',
'medication_dosage_given',
'medication_dosage_unit',
'notes',
'created',
'photo',
)
extra_kwargs = {
'foster_manager': {
'read_only': True,
'required': False,
'lookup_field': 'id',
},
'medication': {
'read_only': True,
'required': False,
'lookup_field': 'slug',
},
'cat': {
'read_only': True,
'required': False,
'lookup_field': 'slug',
},
}
#staticmethod
def create(validated_data):
cat_data = validated_data.pop('cat')
cat_obj = Cat.objects.get(**cat_data)
return CareLog.objects.create(cat=cat_obj, **validated_data)
#staticmethod
def update(instance, validated_data):
instance.weight_unit_measure = validated_data['weight_unit_measure']
instance.weight_before_food = validated_data['weight_before_food']
instance.food_unit_measure = validated_data['food_unit_measure']
instance.amount_of_food_taken = validated_data['amount_of_food_taken']
instance.food_type = validated_data['food_type']
instance.weight_after_food = validated_data['weight_after_food']
instance.stimulated = validated_data['stimulated']
instance.stimulation_type = validated_data['stimulation_type']
instance.notes = validated_data['notes']
instance.save()
Here is my model
class CareLog(models.Model):
WEIGHT_MEASURE_CHOICES = (
('OZ', '(oz) Ounces'),
('LB', '(lb) Pounds'),
('G', '(G) Grams')
)
OUNCES = 'OZ'
POUNDS = 'LB'
GRAMS = 'G'
VOLUME_MEASURE_CHOICES = (
('ML', '(ml) Milliliters'),
('CC', '(cc) Cubic Centimeters'),
('OZ', '(oz) Ounces'),
('G', '(G) Grams')
)
MILLILITERS = 'ML'
CUBIC_CENTIMETERS = 'CC'
FOOD_TYPE_CHOICES = (
('MN', 'Mom (Nursing)'),
('BO', 'Bottle'),
('BS', 'Bottle / Syringe'),
('SG', 'Syringe Gruel'),
('GG', 'Syringe Gruel / Gruel'),
('G', 'Gruel')
)
BOTTLE = 'BO'
BOTTLE_SYRINGE = 'BS'
SYRINGE_GRUEL = 'SG'
SYRINGE_GRUEL_GRUEL = 'GG'
GRUEL = 'G'
STIMULATION_CHOICES = (
('UR', 'Urine'),
('FE', 'Feces'),
('UF', 'Urine / Feces'),
)
URINE = 'UR'
FECES = 'FE'
URINE_FECES = 'UF'
cat = models.ForeignKey(Cat)
slug = AutoSlugField(max_length=255, unique=True, blank=True, null=True)
foster_manager = models.ForeignKey(User, on_delete=models.CASCADE, blank=True, null=True)
weight_unit_measure = models.CharField(max_length=2, choices=WEIGHT_MEASURE_CHOICES, default=GRAMS)
weight_before_food = models.IntegerField(blank=True, null=True)
food_unit_measure = models.CharField(max_length=2, choices=WEIGHT_MEASURE_CHOICES, default=GRAMS)
amount_of_food_taken = models.IntegerField(blank=True, null=True)
food_type = models.CharField(max_length=2, choices=FOOD_TYPE_CHOICES, blank=True, null=True)
weight_after_food = models.IntegerField(blank=True, null=True)
stimulated = models.BooleanField(default=False)
stimulation_type = models.CharField(max_length=2, choices=STIMULATION_CHOICES, blank=True, null=True)
medication = models.ForeignKey(Medication, blank=True, null=True)
medication_dosage_given = models.FloatField(blank=True, null=True)
medication_dosage_unit = models.CharField(max_length=2, choices=VOLUME_MEASURE_CHOICES, blank=True, null=True,
help_text="If left blank this will default to "
"the default unit for the medication.")
notes = models.TextField(blank=True, null=True)
created = models.DateTimeField(auto_now_add=True)
photo = models.FileField(upload_to="kitty_photos", blank=True, null=True)
def save(self, *args, **kwargs):
# Update Cat's weight if 'Weight After Food' is updated
if self.weight_after_food:
self.cat.weight = self.weight_after_food
self.cat.save()
# Get all previous cat feedings
feedings = CareLog.objects.filter(cat=self.cat).order_by('-id')
if feedings:
# if the list of cat feedings contains the current, get rid of current from the list
if feedings[0] == self:
feedings = feedings[1:]
# TODO You broke it you fix it:
# If the feeding is a weight loss log it as the first/second/third
if self.weight_after_food < feedings[0].weight_after_food:
if self.cat.first_weight_loss:
self.cat.second_weight_loss = True
elif self.cat.second_weight_loss:
self.cat.third_weight_loss = True
elif self.cat.third_weight_loss:
self.cat.many_weight_losses = True
elif not self.cat.first_weight_loss:
self.cat.first_weight_loss = True
# Save Cat Object
self.cat.save()
if self.medication and not self.medication_dosage_unit:
self.medication_dosage_unit = self.medication.dosage_unit
super(CareLog, self).save(*args, **kwargs)
def __str__(self):
return "{cat}: {timestamp}".format(cat=self.cat.name, timestamp=self.created)
In your create method you need to do for medication same operation as for cat. Create object first and assign it to CareLog:
#staticmethod
def create(validated_data):
cat_data = validated_data.pop('cat')
cat_obj = Cat.objects.get(**cat_data)
med_data = validated_data.pop('medication')
med_obj = Medication.objects.create(**med_data)
return CareLog.objects.create(cat=cat_obj, medication=med_obj, **validated_data)
Otherwise Django trying to set as foreignkey's value dict object and raise the error.
I'm trying to create a new function but I'm getting this Django error :
'SocieteIntervention' object has no attribute 'update'
I have several models in my application :
class Societe(models.Model):
Nom = models.CharField(null= False, max_length=30, verbose_name='Nom de Société')
Etat = models.CharField(max_length = 30, choices = CHOIX_ETAT_SOCIETE, null=False, verbose_name="Etat")
Adresse = models.CharField(max_length=30, verbose_name='Adresse')
Ville = models.CharField(max_length=30, verbose_name='Ville')
Zip = models.IntegerField(verbose_name='Code Postal')
Region = models.CharField(max_length=30, verbose_name='Région')
Pays = CountryField(blank_label='Sélectionner un pays', verbose_name='Pays')
Mail = models.CharField(max_length=40, verbose_name='Email')
Web = models.CharField(max_length=40, verbose_name='Site Web')
Telephone = models.CharField(max_length=20, verbose_name='Téléphone Fixe')
Fax = models.CharField(max_length=20, verbose_name='Fax')
SIREN = models.BigIntegerField(verbose_name='N° SIREN')
SIRET = models.BigIntegerField(verbose_name='N° SIRET')
NAF_APE = models.CharField(max_length=5, verbose_name='Code NAF-APE')
RCS = models.CharField(max_length = 30, verbose_name='Code RCS')
CHOIX_TVA = models.CharField(max_length = 30, choices=CHOIX_TVA, verbose_name='Assujeti à la TVA')
TVA = models.CharField(max_length=13, verbose_name='N° TVA Intracommunautaire')
Type = models.CharField(max_length = 30, choices = CHOIX_SOCIETE, verbose_name = 'Type de Société')
Effectif = models.CharField(max_length = 30, choices = CHOIX_EFFECTIF, verbose_name = 'Effectif')
Capital = models.IntegerField(verbose_name = 'Capital de la Société (euros)')
Creation = models.DateTimeField(auto_now_add=True)
InformationsInstitution = models.CharField(max_length=30, null=False, verbose_name='Informations Institution')
Utilisateur = models.CharField(max_length=100, null=False, verbose_name="Utilisateur", default=" ")
def save(self, *args, **kwargs):
for field_name in ['Nom', 'Ville', 'Region']:
val = getattr(self, field_name, False)
if val:
setattr(self, field_name, val.upper())
super(Societe, self).save(*args, **kwargs)
class SocieteContrat(models.Model):
Societe = models.ForeignKey(Societe, related_name="Societe", verbose_name="Société")
PointsTotal = models.FloatField(verbose_name="Nombre points total")
PointsRestant = models.FloatField(verbose_name="Nombre points restants", null=True)
def __unicode__(self):
return unicode (self.id, self.Societe, self.PointsTotal, self.PointsRestant)
class SocieteIntervention(models.Model):
Societe = models.ForeignKey(Societe, related_name="Societe1", verbose_name="Société")
Date = models.DateField(verbose_name="Date de l'Intervention")
Temps = models.IntegerField(verbose_name="Durée Intervention (min)")
Description = models.CharField(max_length=200, verbose_name="Description")
Niveau = models.CharField(max_length = 30, choices = CHOIX_NIVEAU, verbose_name = 'Niveau Intervention/Intervenant')
PointsConsommes = models.FloatField(verbose_name=u"Nombre points consommés", null=True)
class CoefficientIntervention(models.Model):
Technicien = models.FloatField(verbose_name="Coefficient Technicien")
Ingenieur = models.FloatField(verbose_name="Coefficient Ingénieur")
Consultant = models.FloatField(verbose_name="Coefficient Consultant")
Architecte = models.FloatField(verbose_name="Coefficient Architecte")
def __unicode__(self):
return unicode (self.id, self.Technicien, self.Ingenieur, self.Consultant, self.Architecte)
My objective is : Create service contracts with a number of points. Points are deducted according to a coefficient. This coefficient depending on your status : Technician, Engineer, ...
I create this function in my view :
#login_required
def Identity_Contrat(request, id) :
societe = get_object_or_404(Societe, pk=id)
contrat = get_object_or_404(SocieteContrat, pk=id)
coefficient = CoefficientIntervention.objects.last()
if request.method == 'POST':
form = InterventionFormulaire(request.POST or None)
if form.is_valid() :
post = form.save()
Liste_Intervention = SocieteIntervention.objects.filter(Societe__id=id).values_list("Temps")
Value = Liste_Intervention.last()[0]
Type_Intervention = SocieteIntervention.objects.filter(Societe__id=id).values_list("Niveau")
if Type_Intervention.last() == (u'Ing\xe9nieur',) :
Consomme = Value * coefficient.Ingenieur
elif Type_Intervention.last() == ('Technicien',) :
Consomme = Value * coefficient.Technicien
elif Type_Intervention.last() == ('Consultant',) :
Consomme = Value * coefficient.Consultant
elif Type_Intervention.last() == ('Architecte',) :
Consomme = Value * coefficient.Architecte
PointsConsommes = SocieteIntervention.objects.latest('id').update(PointsConsommes=Consomme)
messages.success(request, 'Le formulaire a été enregistré !')
return HttpResponseRedirect('http://localhost:8000/Identity/Contrat/Societe/'+id)
else:
messages.error(request, "Le formulaire est invalide !")
else:
form = InterventionFormulaire()
context = {
"coefficient" : coefficient,
"societe" : societe,
"contrat" : contrat,
"form" : form,
}
return render(request, 'Identity_Societe_Contrat.html', context)
I fill the form, I save it with PointsConsommes == NULL,then I'm trying to update it with the value calculated previously.
How I can update the field PointsConsommes when the form is saved ? I don't overcome to update it with .update.
You can try to use update_fields:
PointsConsommes = SocieteIntervention.objects.latest('id')
PointsConsommes.PointsConsommes = Consomme
PointsConsommes.save(update_fields=['PointsConsommes'])