I am trying to use same view for creating form and updating any object.
My code is as below, I tried in many ways nothing is working, since I am excluding the shof from form and adding it after form.is_valid() it makes lot of confusion. If I update it creates new object. I have two urls one without ql (create new) and one with ql (update existing), I have a class vdview which provides v.shof which needs to applied in the f.shop in form. please help fix this,
#csrf_protect
#login_required
def addmenu(request, qs, ql=None):
v = vdview(request, qs)
ctgobj = get_object_or_404(v.shopcategs, pk=ql) if ql else None # ctgobj = ShopCtg(shop=v.shof)
if ql:
form = ShopCtgForm(instance=ctgobj) # Tried ShopCtgForm(instance=ctgobj, data=request.POST)
else:
form = ShopCtgForm(data= request.POST)
if request.method == 'POST':
if form.is_valid():
f=form.save(commit=False)
f.shop = v.shof
f.save()
#form.save_m2m()
return redirect('vendor-shop', qs) #thing='%s added' %f.name)
else:
pass
#else:
# form = ShopCtgForm()
return render(request,'vendorshop.html', {'shop':v.shof, 'shopcategs':v.shopcategs, 'form': form,
'heading':'Create New Category', 'createcateg': 'createcateg', 'pkaddmenupk':'y' } )
Use try blocks to handle both scenarios. The simplified example below will look for a given model instance pk and if it doesn't find it, will assume you want to create it. try will prevent django from throwing an error if the model instance doesn't exist. Rather, it will just return the empty model form.
It does this first to render the correct form in the template (the first try block) then again in the second try block after request.method == 'POST': to submit new data or update existing data.
Views.py
from .models import Books
from .forms import BookForm
def create_and_update_book_view(request, pk):
books = Books.objects.get(id=pk)
try: # get pre-populated form with model instance data (for update)
form = BookForm(instance=books.id)
except: # If it doesn't exist, show an empty form (for create)
form = BookForm(request.POST or None)
if request.method == 'POST':
try: # Do the same as above
form = BookForm(instance=books.id)
except: # Same as above
form = BookForm(request.POST or None)
if form.is_valid():
form.save()
return render(request, "create_and_update_book_page.html", {'form':form})
Related
I'm trying to retrieve data from user. The form where i want to show the user information is also the same that i use to update this information.
Update3
After some updates I make this work and this is my code. If somenone have a better way to do this can share it :)
models.py
from django.db import models
from django.contrib.auth.models import User
# Create your models here.
class informacionFacturacion(models.Model):
usuario = models.ForeignKey(User, on_delete=models.CASCADE)
apellidos = models.CharField(max_length=100)
nombres = models.CharField(max_length=100)
[More fields...]
def __str__(self):
self.apellidos
forms.py
from .models import informacionFacturacion
#Create your forms here.
class informacionFacturacionForm(ModelForm):
class Meta:
model = informacionFacturacion
fields = [
"usuario",
"apellidos",
"nombres",
[More fields...]
]
views.py
#login_required
def datosPersonales(request):
#Filter query by user ID
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm()
#If query has content, edit record, else, create a new record
if query:
if request.method == "POST":
form = informacionFacturacionForm(request.POST or None, instance=query[0])
if form.is_valid():
edit_content = form.save()
edit_content.save()
else:
if request.method == "POST":
form = informacionFacturacionForm(request.POST)
if form.is_valid():
create_content = form.save(commit=False)
create_content.save()
return HttpResponseRedirect(reverse('datosPersonales'))
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Thanks for the support.
At first glance, it seems that the informacionFacturacion table is not being populated. Have you checked that the instance.save() is reached? (in other words, that the form is valid)
Second, in the template you want to use the informacionFacturacion object as the form elements, and you are handling them separately. Do:
if request.POST:
form = informacionFacturacionForm(request.POST)
if form.is_valid():
instance = form.save(commit=False)
instance.save()
else:
# handle here the form error's, maybe report it in the template
else:
query = informacionFacturacion.objects.filter(usuario=request.user)
form = informacionFacturacionForm(instance=query[0])
and render the form parameter insead of infoFacturacion:
{{ form.as_p }}
finally, make sure that your template form id's matches the form element names, otherwise the form won't be filled.
UPDATE
Based on your edit, now the error is in this line:
form = informacionFacturacionForm(request.POST, instance=query_id)
query_id is an int, and it is expecting a model. Change the following line:
query_id = informacionFacturacion.objects.get(usuario=request.user).id
to
query = informacionFacturacion.objects.get(usuario=request.user)
and the faulty line to:
form = informacionFacturacionForm(request.POST, instance=query)
that should work for now, although code can be simplified a lot.
EDIT 2
Here is what I assume you want:
#login_required
def datosPersonales(request):
query = informacionFacturacion.objects.filter(usuario=request.user)
if request.method == "POST": # This will handle the template form's POST
form = informacionFacturacionForm(request.POST)
if form.is_valid():
asd = form.save(commit=False)
asd.save()
# Here you may want to redirect to somewhere else
# Im not sure here, I guess that you want to handle the GET method if
# there is no form in the request. Post your template form to see what
# is happening.
else:
form = informacionFacturacionForm(instance=query)
# you dont need to save it, it is already in DB
context = {
"titulo": "Datos personales | Co.",
"body_class": "class= sidebar_main_open sidebar_main_swipe",
# I think here is your main issue, you are handling a form object
# AND a infoFacturacion object. You need to use just the
# form object in the template and render it accordingly.
"form": form,
"infoFacturacion": query,
}
template = "micuenta/datosPersonales.html"
return render(request, template, context)
Well, I was with the same problem on my sytem, so I made this solution, maybe it works to you! =D
I'm changing the value of the submit button and using the same form:
<button type="submit" id="submitButton" name="button" value="">Save</button>
If is a new task, I change the value of the button with JQuery:
$('#submitButton').val('new');
And if is an edition, I change the value again:
$('#submitButton').val('edit');
On my views.py, I check if is an edit or a new save by the value of the button:
def index(request):
tasks = Task.object.filter()
context = {
'tasks': tasks
}
if request.method == 'POST':
form = NewTask(request.POST or None)
if request.POST['button'] == 'new':
if form.is_valid():
context['is_valid'] = True
form.save()
form = NewTask()
else:
context['is_valid'] = False
if request.POST['button'] == 'edit':
instance = Task.object.filter(pk=request.POST['id']).first()
form = NewTask(request.POST, instance=instance)
if form.is_valid():
context['is_valid'] = True
form.save()
else:
context['is_valid'] = False
else:
form = NewTask()
context['form'] = form
return render(request, 'index.html', context)
I would like to be able to present a form to users with a dropdown list of existing records and a delete action for the selected record. So far all I can find are examples that pass the id of record to the form (such as below) and I can get this to work if I hard code the id in the function, but that's obviously not a solution. What am I missing? Thanks.
def DeleteRecord(request, id):
to_delete = get_object_or_404(MyModel, id=id)
#+some code to check if this object belongs to the logged in user
if request.method == 'POST':
form = DeleteRecordForm(request.POST, instance=to_delete)
if form.is_valid(): # checks CSRF
to_delete.delete()
return HttpResponseRedirect("/")
else:
form = DeleteRecordForm(instance=to_delete)
data = {'form': form}
return render(request, 'deleteprimerpair.html', data)
I need help with what might be a simple problem. I am writing a form to add a section to some unit. The unit will have X sections tied to it, sorted with indexes (indices?).
The problem arises when I try to pass the unit_id to the section. As the user will need to pass through the unit screen to add a section, I want it to be automatically assigned, it'll be in the URL too.
I am encountering problems adding it to the modelform, after submitting the value entered by the user.
def section_modify(request, unit_id, section_id=None):
unit = get_object_or_404(Models.Unit, id=int(unit_id))
if section_id is not None:
section = get_object_or_404(Models.Section, id=int(section_id))
else:
section = None
if request.method == "POST":
form = F.SectionForm(request.POST, instance=section)
if form.is_valid():
# I tried this part, but it didn't work:
# form.save(commit=False)
# form.unit_id = unit_id
form.save()
return HttpResponseRedirect('')
else:
form = F.SectionForm(instance=section)
return render(request, 'sectionEdit.html', {'form': form})
I am looking for the least hacky way to do this, django way.
Any help is much appreciated. Thank you for your time.
Try to add unit_id like this:
if form.is_valid():
# section will get unsaved model instance
# so you can assign property value and then save
section = form.save(commit=False)
section.unit_id = unit_id
section.save()
* UPDATED *
def section_modify(request, unit_id, section_id=None):
unit = get_object_or_404(Models.Unit, id=int(unit_id))
if section_id is not None:
section = get_object_or_404(Models.Section, id=int(section_id))
if section:
section.unit_id=unit.pk
section.save()
else:
section = None
if request.method == "POST":
form = F.SectionForm(request.POST, instance=section)
if form.is_valid():
if section:
form.save()
else:
section = form.save(commit=False)
section.unit_id=unit.pk
section.save()
return HttpResponseRedirect('')
else:
form = F.SectionForm(instance=section)
return render(request, 'sectionEdit.html', {'form': form})
So if we have section instance append unit_id to it else append unit'id after form submit.
it's not clear to me how to manage formsets in Django. This is my views.py:
def newAd(request):
newAdFormSet = modelformset_factory(Ad)
if request.method == 'POST':
formset = newAdFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return render_to_response('conf.html',
{'state':'Your ad has been successfull created.'},
context_instance = RequestContext(request),)
else:
formset = newAdFormSet()
return render_to_response('ad_form.html',
{'form':formset},
context_instance=RequestContext(request),)
It works but it always returns one prefilled form for each existing tuple plus, at the end, a blank form.
Now, i can't get how to say where it must return a blank form (to perform a new insert), and where it must instead return a single prefilled form (possibly passing the Ad's id) to perform an update.
modelformset_factory and formset helps to solve a lot, take your code for example
def newAd(request):
newAdFormSet = modelformset_factory(Ad, extra=1)
if request.method == 'POST':
formset = newAdFormSet(request.POST, request.FILES)
if formset.is_valid():
formset.save()
return render_to_response('conf.html',
{'state':'Your ad has been successfull created.'},
context_instance = RequestContext(request),)
else:
formset = newAdFormSet(queryset=Ad.objects.all())
return render_to_response('ad_form.html',
{'form':formset},
context_instance=RequestContext(request),)
Note the extra=1 in modelformset_factory line, it ensures there is only one extra blank form. And queryset=Ad.objects.all() in the second newAdFormSet inside else statement, it pre-fills forms for Ad objects from DB and correctly set PK in, mostly hidden, field for backend code to recognize submitted objects.
update
if you want to set Ad().codU to point to an User() instance, request.user for example, you could simply just set it by
instances = formset.save(commit=False)
for obj in instances:
obj.codU = request.user
obj.save()
I'm still not 100% clear what your question is, but it sounds like you don't want a formset at all. If you're only interested in adding or updating a single record at a time, you want a simple ModelForm, not a formset. So:
class AdForm(forms.ModelForm):
class Meta:
model = Ad
def add_update_ad(request, pk=None):
if pk is not None:
instance = Ad.objects.get(pk=pk)
else:
instance = Ad()
if request.POST:
form = AdForm(request.POST, instance=instance)
if form.is_valid():
new_instance = form.save()
return HttpResponseRedirect('my_confirmation_view')
else:
form = AdForm(instance=instance)
return render(request, 'ad_form.html', {'form': form})
I'm creating a form in one page, then in another page I'm trying to pull out the form (populated with the data saved in it already) and would like to make changes to it so that when I save it it overwrites the instance instead of creating another one.
def edit(request):
a = request.session.get('a', None)
if a is None:
raise Http404('a was not found')
if request.method == 'POST':
form = Name_Form(request.POST, instance=a)
if form.is_valid():
j = form.save( commit=False )
j.save()
else:
form = Name_Form( instance = a )
This is the code I have for the "editting form" view.. When I open this page the form is successfully prepopulated with all the data. However, when I make changes and save, it does not overwrite the existing instance, instead it creates a new one.
Any ideas?
Have a look here: https://docs.djangoproject.com/en/dev/ref/models/instances/#how-django-knows-to-update-vs-insert
I think this may help you.
Update:
What about trying a more "explicit" way.
Assume, id_of_Name stores only the id or pk of your model which you want to edit (I assume the model is called "Name"). Then just retrieve the id/pk from session to query your db for the model instance. Also try to directly call the save method on the form.
def edit(request):
id_of_Name = request.session.get('a', None)
if id_of_Name is None:
raise Http404('id_of_Name was not found')
instance = Name.objects.get(pk=id_of_Name)
if request.method == 'POST':
form = Name_Form(request.POST, instance=instance)
if form.is_valid():
form.save()
else:
form = Name_Form( instance = instance )