Django - Trouble validating ModelForm - django

def io_simulation(request):
form = SimForm(request.POST)
print('FIRST' + str(request.POST))
if form.is_valid():
form.save()
return render(request, 'App/simulation.html', {'title': 'Simulation'})
This view function shows that my POST data is being sent correctly, but it's not reaching my database. This is the output of the print statement:
FIRST<QueryDict: {'csrfmiddlewaretoken': ['dzowQoB3lk2IOOc19QXQDPZ3soJaxglaP76cURfjB6GMU3VBkHDe7IDhIp2CPpyK'], 'sim_concentration_range': ['3'], 'sim_concentration_range_2': ['4'], 'sim_concentration_range_unit': ['ppm']}>
If I use io_simulation as the action for my form submission then I get a NoReverseMatch error, and I don't get my POST data printed out. If I use this other function as the action:
def save_sim_data(request):
if request.method == 'POST':
request.POST.get('sim_concentration_range')
request.POST.get('sim_concentration_range_2')
request.POST.get('sim_concentration_range_unit')
data=Sim()
data.sim_concentration_range = request.POST.get('sim_concentration_range')
data.sim_concentration_range_2 = request.POST.get('sim_concentration_range_2')
data.sim_concentration_range_unit = request.POST.get('sim_concentration_range_unit')
data.save()
return render(request, 'nowhere.html')
else:
return render(request,'no/errors.html')
Then I do see my POST data get printed (and it's correct (output in blockquote above)), but I still get nothing in my database.
I cannot make any sense of the views structure and debugging. What is going on?
Edits:
Forms.py:
class SimForm(forms.ModelForm):
sim_concentration_range = forms.DecimalField()
sim_concentration_range_2 = forms.DecimalField()
sim_concentration_range_unit = forms.ChoiceField()
class Meta:
model = Sim
fields = ('sim_concentration_range','sim_concentration_range_2','sim_concentration_range_unit')
models.py
class Sim(models.Model):
sim_concentration_range = models.DecimalField(max_digits = 100, decimal_places = 5, default=1)
sim_concentration_range_2 = models.DecimalField(max_digits = 100, decimal_places = 5, default=1)
sim_concentration_range_unit = models.TextChoices('sim_cc_unit', 'ppm ')
STEPS TAKEN FOR SOLUTION
- Remove variable definitions within forms.py SimForm function but outside of Meta class
class SimForm(forms.ModelForm):
class Meta:
model = Sim
fields = ('sim_concentration_range','sim_concentration_range_2','sim_concentration_range_unit')
- Change TextChoices field in models.py Sim class to CharField
- Removed save_sim_data function from views.py and removed action declarations for the form in its html
- Changed URL pattern to use io_simulation view

Because of you are using ModelForm, you don't have to override the fields. so you can just type it like this:
class SimForm(forms.ModelForm):
class Meta:
model = Sim
fields = ('sim_concentration_range','sim_concentration_range_2','sim_concentration_range_unit')

Related

Inconsistent behavoiur of save(commit=False) for a ModelForm in Django 2.2

I have a ModelForm that selects one field and excludes the rest, one of which is a ForeignKey that I need to populate manually before saving the form.
I'm in the process of fixing a bug that one of my views has and I'm making use of the request.session object to store information so that the GET and POST method funcions will be in synced by the session in locating the model at hand instead of separately iterating though the database to pin-point what model object the submitted data should be saved for.
I'm making use of the form_object.save(commit=False) funcionality in other places of the same view and it works as I need but for some reason there is a section of the view where it just doesn't populate the extra field before calling the eventual save() method and I get an IntegrityError for that column in the database, even if it is not null=False in my model declaration right now (and I think it'd rather should be..).
So here's my ModelForm:
class PesoFormApertura(ModelForm):
peso_apertura = forms.DecimalField(min_value=0,required=True)
class Meta:
model = Peso
fields = ('peso_apertura',)
here's the Model itself:
class Peso(models.Model):
prodotto = models.ForeignKey(ProdottoPesato,on_delete=models.CASCADE)
peso_apertura = models.DecimalField(max_digits=8,decimal_places=2, blank=False, null=True)
peso_calcolato = models.DecimalField(max_digits=8,decimal_places=2, blank=True, null=True)
peso_chiusura = models.DecimalField(max_digits=8,decimal_places=2, blank=True, null=True)
data = models.DateField(auto_now_add=True, blank = False)
def __str__(self):
return "{} - {} - {}".format(self.prodotto.nome, self.prodotto.get_categoria_display(), self.data)
def save(self, *args, **kwargs):
if self.peso_apertura == 0:
prodotto_associato = ProdottoPesato.objects.get(pk = self.prodotto.pk)
if prodotto_associato.permanente == False:
prodotto_associato.delete()
self.delete()
else:
super().save(*args, **kwargs)
else:
super().save(*args, **kwargs)
class Meta:
ordering = ['prodotto']
and here's the view part where the save() method is failing (where I placed a comment):
if not 'prodotto-da-correggere' in request.session:
for prodotto in tutti_prodotti:
pesi_questo_prodotto_oggi = prodotto.pesi_di_oggi()
for peso in pesi_questo_prodotto_oggi:
if peso.peso_apertura == None:
prodotto_da_elaborare = prodotto
peso_del_giorno = peso
break
if prodotto_da_elaborare:
finito = False
instance_peso = peso_del_giorno
form = PesoFormApertura(request.POST, instance = instance_peso)
if form.is_valid():
form.save(commit=False) # WORKS FINE
form.prodotto = prodotto_da_elaborare
form.save()
else:
form = PesoFormApertura(request.POST)
else: # HERE IS WHERE IT DOESN'T BEHAVE LIKE ABOVE
prodotto_da_elaborare = ProdottoPesato.objects.get(id=request.session['prodotto-da-correggere'])
peso_del_giorno = None
for peso in prodotto_da_elaborare.pesi_di_oggi():
if peso.peso_apertura == None or peso.peso_apertura > 0:
peso_del_giorno = peso
break
form_correzione = PesoFormApertura(request.POST, instance = peso_del_giorno)
if form_correzione.is_valid():
form_correzione.save(commit=False)
form_correzione.prodotto = prodotto_da_elaborare
form_correzione.save() # IT DOESN'T ADD THE INFORMATION TO THE COLUMN WHEN IT SAVES
request.session.flush()
The save() method works alright for the first part of the IF statement and just doesn't work for the rest of the snippet in the ELSE section.
So I'm wondering if the session has something to do with this.
When you call form.save() it returns the instance. You should modify and save that instance.
if form_correzione.is_valid():
peso = form_correzione.save(commit=False)
peso = prodotto_da_elaborare
peso.save()
You should change the other part of the view to use this approach as well. It looks like form.prodotto = prodotto_da_elaborare is having no effect, but you haven't noticed because prodotto is already set so you don't get an integrity error.

App works with ModelChoiceField but does not work with ModelMultipleChoiceField

I am trying to retrieve user input data in a django page. But I am unable to choose to multichoice field. I have tried multiple alternatives to no relief.
self.fields['site'].queryset=forms.ModelMultipleChoiceField(queryset=sites.objects.all())
self.fields['site'] = forms.ModelChoiceField(queryset=sites.objects.filter(project_id=project_id))
self.fields['site'].queryset = forms.MultipleChoiceField(widget=forms.SelectMultiple, choices=[(p.id, str(p)) for p in sites.objects.filter(project_id=project_id)])
forms.py
class SearchForm(forms.Form):
class Meta:
model= images
fields=['site']
def __init__(self,*args,**kwargs):
project_id = kwargs.pop("project_id") # client is the parameter passed from views.py
super(SearchForm, self).__init__(*args,**kwargs)
self.fields['site'] = forms.ModelChoiceField(queryset=sites.objects.filter(project_id=project_id))
views.py
def site_list(request, project_id):
form = SearchForm(project_id=project_id)
site_list = sites.objects.filter(project__pk=project_id).annotate(num_images=Count('images'))
template = loader.get_template('uvdata/sites.html')
if request.method == "POST":
image_list=[]
form=SearchForm(request.POST,project_id=project_id)
#form=SearchForm(request.POST)
#site_name=request.POST.get('site')
if form.is_valid():
site_name=form.cleaned_data.get('site')
print(site_name)
I expect to get a multiselect field but I end up getting this error:
Exception Value:
'site'
Exception Location: /home/clyde/Downloads/new/automatic_annotator_tool/django_app/search/forms.py in init, line 18
(line 18:self.fields['site'].queryset = forms.MultipleChoiceField(widget=forms.SelectMultiple, choices=[(p.id, str(p)) for p in sites.objects.filter(project_id=project_id)]))
You are not defining your form correctly. The documentation shows you how to do this.
In your case it would be something like this:
class SearchForm(forms.Form):
site = forms.ModelMultipleChoiceField(queryset=Sites.object.none())
def __init__(self,*args,**kwargs):
project_id = kwargs.pop("project_id")
super(SearchForm, self).__init__(*args,**kwargs)
self.fields['site'].queryset = Sites.objects.filter(project_id=project_id))
You also appear to be confusing regular Form and ModelForm, as Meta.model is only used in ModelForm whereas you are using a regular Form. I suggest you read up on the difference in the documentation before you proceed.

django form use excluded field

with django 1.5.1 I try to use the django form for one of my models.
I dont want to add the "user" field (Foreignkey) somewhere in the code instead of letting the user deceide whoes new character it is.
My Code:
Model:
class Character(models.Model):
user = models.ForeignKey(User)
creation = models.DateTimeField(auto_now_add=True, verbose_name='Creation Date')
name = models.CharField(max_length=32)
portrait = models.ForeignKey(Portrait)
faction = models.ForeignKey(Faction)
origin = models.ForeignKey(Origin)
The form:
class CreateCharacterForm(forms.ModelForm):
class Meta:
model = Character
fields = ['name', 'portrait', 'faction', 'origin']
The view:
def create_character(request, user_id):
user = User.objects.get(id=user_id)
if request.POST:
new_char_form = CreateCharacterForm(request.POST)
if new_char_form.is_valid():
new_char_form.save()
return HttpResponseRedirect('%s/characters/' % user_id)
else:
return render_to_response('create.html',
{'user': user, 'create_char':new_char_form},
context_instance=RequestContext(request))
else:
create_char = CreateCharacterForm
return render_to_response('create.html',
{'user': user, 'create_char': create_char},
context_instance=RequestContext(request))
I have tried to use a instance to incluse the userid already. i've tried to save the userid to the form before saving it, or changing the save() from my form.
I keep getting the error that character.user cant be null
I have to tell that im pretty new to django and im sure one way or another it should be possible
Can someone please help me out?
Its explained well in document model form selecting fields to use
You have to do something like this in your view
...
if request.POST:
new_char_form = CreateCharacterForm(request.POST)
if new_char_form.is_valid():
#save form with commit=False
new_char_obj = new_char_form.save(commit=False)
#set user and save
new_char_obj.user = user
new_char_obj.save()
return HttpResponseRedirect('%s/characters/' % user_id)
else:
...

django prepopulate modelform - nothing happens

This must be a very simple thing however I can not seem to get through it..
I trying to build a form where the user can update a ModelForm. First he inserts a user id and afterwards I want to show him the form pre-populate with the original data so he can change only the fields that he wants.
After some the help of my friend google, stackoverflow and the django documentation, I've come to this:
views.py
user = User.objects.get(user_id=usr)
if request.method == 'POST':
form = TableForm(request.POST)
if form.is_valid():
#do something
else:
form = TableForm(instance=user)
return render_to_response('template.html',{'form':form})
forms.py
class TableForm(forms.ModelForm):
pres_clinic = forms.ModelChoiceField(queryset=PresClinic.objects.all(),
widget=SelectWithPop(), label=ugettext("Clinic presentation"),
required=False)
MAYBECHOICES = (
('', '---------'),
(ugettext('Yes'), ugettext('Yes')),
(ugettext('No'), ugettext('No')))
bcg_scar = forms.ChoiceField(choices=MAYBECHOICES, label=ugettext(
"BCG scar"), required=False)
mantoux_register = forms.ChoiceField(choices=MAYBECHOICES,
label=ugettext("Mantoux register"), required=False)
date_diag = forms.DateField(widget=DateTimeWidget, label=ugettext(
"Diagnosis date"), required=False)
situation = forms.ModelChoiceField(queryset=Situation.objects.all(),
widget=SelectWithPop(), label=ugettext("Patient status"),
required=False)
date_situation = forms.DateField(widget=DateTimeWidget, label=ugettext(
"Date patient status"), required=False)
class Meta:
model = Table
fields = ('pres_clinic', 'bcg_scar', 'mantoux_register',
'date_diag', 'situation', 'date_situation')
def clean(self):
cleaned_data = self.cleaned_data
diag = cleaned_data.get('date_diag')
errors = []
now = datetime.date.today()
if diag is not None and diag != u'':
if diag > now:
errors.append(ugettext('The field "Diagnosis date" should be '
'smaller than the actual date'))
if errors:
raise ValidationError(errors)
return cleaned_data
template:
{{ form }} # presents the empty form and not the data from that user
The version of django is 1.4
Can anyone tell me what is wrong and why I'm not able to see the form populated?
Thank you very much
You need to define a dictionary to be used for the initial data and change from TableForm(instance=user) to TableForm(initial=dict), for example something like:
user = User.objects.get(user_id=usr)
if request.method == 'POST':
form = TableForm(request.POST)
if form.is_valid():
#do something
else:
data = {'pres_clinic' : 'value', 'bcg_scar' : 'value', 'mantoux_register' : 'value'}
form = TableForm(initial=data)
return render_to_response('template.html',{'form':form})
I would also put the render to response out of the if statement so if the form isn't valid the page should reload and show any errors.
More information on the django docs here
I hope this helps!
You can try 'model_to_dict'
from django.forms.models import model_to_dict
user = User.objects.get(user_id=usr)
if request.method == 'POST':
form = TableForm(request.POST)
if form.is_valid():
#do something
else:
form = TableForm(initial=model_to_dict(user))
return render_to_response('template.html',{'form':form})

Import csv data into database in Django Admin

I've tried to import a csv file into a database by tweaking the modelform inside the admin doing this:
models.py:
class Data(models.Model):
place = models.ForeignKey(Places)
time = models.DateTimeField()
data_1 = models.DecimalField(max_digits=3, decimal_places=1)
data_2 = models.DecimalField(max_digits=3, decimal_places=1)
data_3 = models.DecimalField(max_digits=4, decimal_places=1)
Forms.py:
import csv
class DataImport(ModelForm):
file_to_import = forms.FileField()
class Meta:
model = Data
fields = ("file_to_import", "place")
def save(self, commit=False, *args, **kwargs):
form_input = DataImport()
self.place = self.cleaned_data['place']
file_csv = request.FILES['file_to_import']
datafile = open(file_csv, 'rb')
records = csv.reader(datafile)
for line in records:
self.time = line[1]
self.data_1 = line[2]
self.data_2 = line[3]
self.data_3 = line[4]
form_input.save()
datafile.close()
Admin.py:
class DataAdmin(admin.ModelAdmin):
list_display = ("place", "time")
form = DataImport
admin.site.register(Data, DataAdmin)
But i'm stuck trying to import the file i put in "file_to_import" field. Getting AttributeError in forms.py : 'function' object has no attribute 'FILES'.
What i'm doing wrong?
After a long search i found an answer: Create a view inside the admin using a standard form
Form:
class DataInput(forms.Form):
file = forms.FileField()
place = forms.ModelChoiceField(queryset=Place.objects.all())
def save(self):
records = csv.reader(self.cleaned_data["file"])
for line in records:
input_data = Data()
input_data.place = self.cleaned_data["place"]
input_data.time = datetime.strptime(line[1], "%m/%d/%y %H:%M:%S")
input_data.data_1 = line[2]
input_data.data_2 = line[3]
input_data.data_3 = line[4]
input_data.save()
The view:
#staff_member_required
def import(request):
if request.method == "POST":
form = DataInput(request.POST, request.FILES)
if form.is_valid():
form.save()
success = True
context = {"form": form, "success": success}
return render_to_response("imported.html", context,
context_instance=RequestContext(request))
else:
form = DataInput()
context = {"form": form}
return render_to_response("imported.html", context,
context_instance=RequestContext(request))
The rest is part of this post:
http://web.archive.org/web/20100605043304/http://www.beardygeek.com/2010/03/adding-views-to-the-django-admin/
Take a look at django-admin-import, it does more or less exactly what you want -- you can upload a XLS (not a CSV, but that should not matter) and lets you assign columns to model fields. Default values are also supported.
https://pypi.org/project/django-admin-import/
Additionally, it does not take away the possibility to modify individual records by hand because you don't have to replace the default model form used in the administration.
In the save() method, you don't have any access to the request object - you can see that it's not passed in. Normally you would expect to have a NameError there, but I suspect that you've got a function elsewhere in the file called request().
At the point of saving, all the relevant data should be in cleaned_data: so you should be able to do
file_csv = self.cleaned_data['file_to_import']
At that point you'll have another problem, which is when you get to open - you can't do that, as file_to_import is not a file on the server filesystem, it's an in-memory file that has been streamed from the client. You should be able to pass file_csv directly to csv.reader.