Populating a form in template and updating new data - python

I tried this, but there is no update done in django.
def update_product(request):
a= ProductForm(instance=Product.objects.get(product_id =2))#static id
render_to_response('profiles/updateproduct.html',{'form': a},RequestContext(request))
if request.method == "POST":
form = ProductForm(request.POST, instance=a)
if form.is_valid():
j=form.save(commit=False)
j.save
confirmation_message = "product information updated successfully!"
return HttpResponse("hhhh")
else:
form = ProductForm( instance = a )

You never actually call the model's save method since you are missing (). you must supply these in order to call the method.
j = form.save(commit=False)
j.save()
As a side note, since you are not doing anything to the model before saving it, you can simply replace these two lines with
j = form.save()
no real need here for the commit=False part.

Related

How to manage Django form validation with dynamically generated forms

Let's say I have the following html page:
LIVE CODE
Let's say that in each row there is a form (I have to implement it), How can I do so that when I click on 'save' button (also to be implemented) all the inputs of each row are sent in the request.POST and I can process them individually in the backend.
This is my view for a new expense:
def new_expense(request):
data = {
'title': "New Expense",
}
data['projects'] = Project.objects.filter(is_visible=True).values('id')
data['expense_category'] = dict((y, x) for x, y in EXPENSE_CATEGORY)
data['expense_type'] = dict((y, x) for x, y in EXPENSE_TYPE)
form = ExpenseForm()
if request.method == "POST":
reset = request.POST['reset']
form = ExpenseForm(request.POST)
if form.is_valid():
form.save()
if reset == 'true':
form = ExpenseForm()
data['form'] = form
return render(request, "expense/new_expense.html", data)
I would like to create a similar view for multiple new expense creation.
One approach to this problem can be handling each row individually. You can use a very simple and effective tool called django_htmx for this task. Here is a nice article about how to handle formsets (like) rows: Build dynamic forms with Htmx. Your case seems to be a very good candidate for the example in this article.

Django: Pass a variable/parameter to form from view? [duplicate]

I have a Model as follows:
class TankJournal(models.Model):
user = models.ForeignKey(User)
tank = models.ForeignKey(TankProfile)
ts = models.IntegerField(max_length=15)
title = models.CharField(max_length=50)
body = models.TextField()
I also have a model form for the above model as follows:
class JournalForm(ModelForm):
tank = forms.IntegerField(widget=forms.HiddenInput())
class Meta:
model = TankJournal
exclude = ('user','ts')
I want to know how to set the default value for that tank hidden field. Here is my function to show/save the form so far:
def addJournal(request, id=0):
if not request.user.is_authenticated():
return HttpResponseRedirect('/')
# checking if they own the tank
from django.contrib.auth.models import User
user = User.objects.get(pk=request.session['id'])
if request.method == 'POST':
form = JournalForm(request.POST)
if form.is_valid():
obj = form.save(commit=False)
# setting the user and ts
from time import time
obj.ts = int(time())
obj.user = user
obj.tank = TankProfile.objects.get(pk=form.cleaned_data['tank_id'])
# saving the test
obj.save()
else:
form = JournalForm()
try:
tank = TankProfile.objects.get(user=user, id=id)
except TankProfile.DoesNotExist:
return HttpResponseRedirect('/error/')
You can use Form.initial, which is explained here.
You have two options either populate the value when calling form constructor:
form = JournalForm(initial={'tank': 123})
or set the value in the form definition:
tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123)
Other solution: Set initial after creating the form:
form.fields['tank'].initial = 123
If you are creating modelform from POST values initial can be assigned this way:
form = SomeModelForm(request.POST, initial={"option": "10"})
https://docs.djangoproject.com/en/1.10/topics/forms/modelforms/#providing-initial-values
I had this other solution (I'm posting it in case someone else as me is using the following method from the model):
class onlyUserIsActiveField(forms.ModelForm):
def __init__(self, *args, **kwargs):
super(onlyUserIsActiveField, self).__init__(*args, **kwargs)
self.fields['is_active'].initial = False
class Meta:
model = User
fields = ['is_active']
labels = {'is_active': 'Is Active'}
widgets = {
'is_active': forms.CheckboxInput( attrs={
'class': 'form-control bootstrap-switch',
'data-size': 'mini',
'data-on-color': 'success',
'data-on-text': 'Active',
'data-off-color': 'danger',
'data-off-text': 'Inactive',
'name': 'is_active',
})
}
The initial is definded on the __init__ function as self.fields['is_active'].initial = False
As explained in Django docs, initial is not default.
The initial value of a field is intended to be displayed in an HTML . But if the user delete this value, and finally send back a blank value for this field, the initial value is lost. So you do not obtain what is expected by a default behaviour.
The default behaviour is : the value that validation process will take if data argument do not contain any value for the field.
To implement that, a straightforward way is to combine initial and clean_<field>():
class JournalForm(ModelForm):
tank = forms.IntegerField(widget=forms.HiddenInput(), initial=123)
(...)
def clean_tank(self):
if not self['tank'].html_name in self.data:
return self.fields['tank'].initial
return self.cleaned_data['tank']
If you want to add initial value and post other value you have to add the following :
or None after request.POST
form = JournalForm(request.POST or None,initial={'tank': 123})
If you want to add files or images also
form = JournalForm(request.POST or None,request.FILES or None,initial={'tank': 123})
I hope this can help you:
form.instance.updatedby = form.cleaned_data['updatedby'] = request.user.id
I also encountered the need to set default values in the form during development. My solution is
initial={"":""}
form=ArticleModel(request.POST)
if form.has_changed():
data = {i: form.cleaned_data[i] for i in form.changed_data}
data.update({key: val for key, val in init_praram.items() if key not in form.changed_data})
use form.has_changed ,if form.fields is required you can use this method
How I added the initial to the form:
I read #Sergey Golovchenko answer.
So I just added it to the form in if request.method == 'POST':.
But that's not where you place it, if you want to see what value it got before posting the form.
You need to put it in the form where the else is.
Example here from views.py
def myForm(request):
kontext = {}
if request.method == 'POST':
# You might want to use clean_data instead of initial here. I found something on a stack overflow question, and you add clean data to the Forms.py, if you want to change the post data. https://stackoverflow.com/questions/36711229/django-forms-clean-data
form = myModelForm(request.POST, initial={'user': request.user})
if form.is_valid():
form.save()
return redirect('/')
else:
# you need to put initial here, if you want to see the value before you post it
form = myModelForm(initial={'user': request.user})
kontext['form'] = form
return render(request, 'app1/my_form.html', kontext)

Django: Change value in request.POST to 0 if empty

I have the following form:
When one of the tickets is empty, my form sends me an error with that every field is required, now I am trying to check if the form value is empty, if it's empty I want to change it to 0, so form.is_valid() can be true.
The attached code doesn't work. It says string index out of range.
def reserve_ticket(request):
if request.method == 'POST':
quantities = request.POST.getlist('quantity')
for i in range(len(quantities)):
if not request.POST['quantity'][i]:
request.POST['quantity'][i] = 0
form = ReserveForm(request.POST)
if form.is_valid():
print("Hello world")
return HttpResponse("Hello world")
else:
return HttpResponse("Back to homepage")
It's not very clean to try to alter the post data. Instead, make the field optional in your form with required=False (or blank=True in the model field) so that there aren't form errors when the field is missing.
If it's a model form, you could set a default value on the field. Or, for a regular form you could override clean_<fieldname> and return 0 when the value isn't specified.

django display data saved from multicheckbox in template

I am trying to make an publishing option, so i use this
class Article(models.Model):
publish_options = models.CharField(max_length=50)
Now in my form, i used forms.CheckboxSelectMultiple widget. so i have this
PUBLISH_VISIBILITY = (
('All', 'All'),
('Paid-users', 'Paid-users'),
('Free Users', 'Free Users'),
('Public', 'Public'),
)
class PortalNoteForm(ModelForm):
publish_options = forms.MultipleChoiceField(widget=forms.CheckboxSelectMultiple, choices=PUBLISH_VISIBILITY)
class Meta:
model = Article
Now in my view i get the values for the checkbox like this
if request.method == 'POST':
form = PortalNoteForm(request.POST)
if form.is_valid():
school_article = form.save(commit=False)
school_article.publish_options = form.cleaned_data['publish_options']
school_article.school_creator = admin
school_article.save()
return HttpResponseRedirect(reverse('going to somewhere'))
else:
form = PortalNoteForm()
context = {'form':form, 'notes':notes}
Okay this works fine saving the value of the publish_option but as a list, even if you select only one checkbox its value comes as a list. Now the problem here is i cant get to stop these publish_options value from displaying as a list in django template. I have tried iterating over them but no way. I really need help.
Well you already had a form, why do you still getting data from request.POST? Form is suppose to take request.POST and convert data into a more convenient way for you to use:
views.py
def view_func(request):
form = PortalNoteForm(request.POST or None)
if form.is_valid():
options = form.cleaned_data['public_options']
# now you have options so use it

Django forms initial value user_full_name

Is the any solution to get django's user_full_name as a initial value for form? My idea was to display a django's form on the end of shopping to finish a order. I want also do put into a form total value, but this is for later.
I did something like this:
user_dane = request.user.get_full_name
koszyk = request.session.get('koszyk', [])
produkty = list(Produkt.objects.filter(pk__in=koszyk))
suma_cen = Produkt.objects.filter(pk__in=koszyk).aggregate(suma=Sum('cena'))
suma_wszystkich_cen = suma_cen['suma']
form=ZamowienieForm(initial={'imie_nazwisko':user_dane, 'kwota_do_zaplaty':suma_wszystkich_cen})
but this is working only when request.method is POST.
if request.method =='POST':
form = ZamowienieForm()
According to documentation I shouldn't initial a empty form with POST... Is there any chance to have a user full name into a form?
Here is the form class:
class ZamowienieForm(forms.ModelForm):
class Meta:
model = Zamowienie
fields = ('imie_nazwisko', 'kwota_do_zaplaty', 'miejscowosc',
'ulica','numer_domu', 'numer_mi‌​eszkania', 'kod_pocztowy',)
class NewMeta:
readonly = ('imie_nazwisko','kwota_do_zaplaty',)
Maybe try something like this inside ZamowienieForm class
def __init__(self, *args, **kwargs):
super(ZamowienieForm, self).__init__(*args, **kwargs)
self.fields['imie_nazwisko'] = self.initial.get('imie_nazwisko')
self.fields['kwota_do_zaplaty'] = self.initial.get('kwota_do_zaplaty')
Although I don't understand why "initial" is not working out of the box
In this case, you only need to initialize your form once, and not inside a conditional check if the request is a GET or POST:
def your_view(request):
form = ZamowienieForm(
request.POST or None,
initial={'imie_nazwisko': request.user.get_full_name(),
'kwota_do_zaplaty': suma_wszystkich_cen}
)
if request.method == 'POST' and form.is_valid():
# do whatever
This way you are always passing in the initial value, and if request.method == 'GET', then None is passed as the first positional argument to the form.
Also, user.get_full_name is an instance method, not a property, so using request.user.get_full_name only returns the bound method, not the actual value. You have have to call the function using ()
Finally, this will only work for users that are authenticated. The anonymous user object in Django won't return any user-specific information.

Categories

Resources