I have created a ModelForm class to be able to create and edit database entries. Creating new entries works well, however, i dont know how to use ModelForms to edit/update an existing entry. I can instantiate a ModelForm with a database instance using:
form = MyModelForm(instance=MyModel.objects.get(pk=some_id))
However, when i pass this to a template and edit a field and then try to save it, i create a new database entry instead of updating "some_id"?
Edit1:
This is my view
def editData(request):
if request.method == 'POST':
form = MyModelForm(request.POST, request.FILES)
if form.is_valid():
editedEntry = form.save() # <-- creates new entry, instead of updating
Remember you still need to use the instance parameter when you instantiate on POST.
instance = MyModel.objects.get(whatever)
if request.method == "POST":
form = MyModelForm(request.POST, instance=instance)
...
else:
form = MyModelForm(instance=instance)
Also possible and slightly shorter:
instance = MyModel.objects.get(whatever)
form = MyModelForm(request.POST or None, instance=instance)
...
Related
I've deployed a formset using modelformset_factory. However rather than saving the entire formset, I need to loop through the forms in the formset, perform some logic on them, and save each one individually. At the moment I'm having to use the ID from each form in the formset to get the object it represents. Is there a cleaner way of doing this?
def accounts_import(request,pk):
account = get_object_or_404(Account, pk=pk)
# Create transactions queryset for use in formset
transactions = Transaction.objects.filter(account=account.monzo_account, import_type=None).order_by('-id')
FormSet = modelformset_factory(Transaction, form=TransactionsImportForm, extra=0)
if request.method == 'POST':
formset = FormSet(request.POST)
if formset.is_valid():
for form in formset:
object = Transaction.objects.get(id=form.cleaned_data['id'])
# Do some stuff on the object
object.save()
Ok looks like form.cleaned_data['id'] returns the object and not the ID, so I got what I wanted.
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})
I am trying to create a form which will allow users to update their name, I am using a forms.form instead of ModelForm because it gives you more control over the styling of the form because you can use widgets. when I go to save the form it says that updateNameForm has no attribute save
view
def UpdateName(request,user_id):
if request.method == "POST":
form = UpdateNameForm(request.POST,initial=initial)
if form.is_valid():
name = form.cleaned_data['name']
form.save()
else:
form = UpdateNameForm(initial=initial)
forms.py
class UpdateNameForm(forms.Form):
name = forms.CharField(
required=True,
label="*Status",
widget=forms.widgets.Select(attrs={'class' : 'span6 small-margin-top small-margin-bottom'})
)
A standard form class indeed has no save attribute - it doesn't know anything about any models to save to. You need to use a ModelForm.
Note also you need to pass the instance argument to the form to make it update an existing instance, rather than create a new one. You probably don't need initial at all.
def UpdateName(request,user_id):
user = get_user(user_id)
if request.method == "POST":
form = UpdateNameForm(request.POST,initial=initial)
if form.is_valid():
name = form.cleaned_data['name']
user.name = name
user.save()
else:
form = UpdateNameForm(initial=initial)
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 )
I am using django forms to add a new objects to the db. The code I currently have is:
if request.method == 'POST':
form = MyForm(data=request.POST)
if form.is_valid():
obj = form.save()
else:
form = MyForm()
return render_to_response('reflections/add_reflection.html', {'form':form},context_instance=RequestContext(request))
The code above currently adds a new object each time the form is submitted. What I want to happen is that the object is edited the next time the save button is pressed rather than adding a new record.
How would I do this?
Use
instance_id = None
if request.method == 'POST':
try:
instance = MyType.objects.get(id=request.POST.get('instance_id'))
except MyType.DoesNotExist:
instance = None
form = MyForm(data=request.POST, instance=instance)
if form.is_valid():
obj = form.save()
instance_id = obj.id
else:
form = MyForm(instance=None)
return render_to_response('reflections/add_reflection.html', {'form':form, 'instance_id': instance_id or ''},context_instance=RequestContext(request))
Once the object is saved, pass it's id in context to page
and add it to a hidden input field inside the form as name='instance_id'.
Happy Coding.
You either need to add a separate view for editing an existing object, or - better - to add the functionality to this view. To do the latter, you could pass in an instance of the object you want to edit with your modelform to else part of your clause:
else:
if existing_obj:
form = MyForm(instance=existing_obj) #this is editing your 'existing_obj'
else:
form = MyForm() # this is creating a brand new, empty form
You'll also need to update the POST-handling bit of code too. See the example here