django using specific instance for ModelForm object - django

For GET form_page.html,
my view has a specific my_id to instantiate a form.
(ie, when a user first sees this form_page, an instance is already created for him,
and he's actually modifying it for the first time)
form = MyForm(instance=MyClass.objects.get(pk=my_id))
For POST form_page.html,
I'd like to update the same instance using the same my_id.
I guess I could have a separate hidden field for this my_id and get it when user POST the form.
But this seems not as easy as I expected.
How/where should I embed this my_id so that I can use it to update the same instance?

Usually I keep the id in the url
url(r'^(?P<id>[\d]+)/edit/$', "edit"),
def edit(request, id=None, **kwargs):
if id:
instance = get_object_or_404(Model, pk=id)
else:
instance = Model()
form = ModelForm(request.POST or None, request.FILES or None, instance=instance)
if request.method == 'POST' and form.is_valid():
instance = form.save()
return redirect(instance)
return TemplateResponse(request, 'edit.html', {'form': form, })

Related

get_or_create not creating my object with attributes that I need

So I am attempting to get_or_create a conversation object. Now, if the object is already created, the code works fine. But if it's not created, it will create the conversation object, BUT not with the members that I am trying to pass. An empty conversation object. members is a manytomany field to User. What am I doing wrong here?
views/message
def message (request, profile_id):
if request.method == 'POST':
form = MessageForm(request.POST)
if form.is_valid():
form.save()
return redirect('dating_app:messages', profile_id)
else:
conversation, created = Conversation.objects.filter(members = request.user).filter(members= profile_id).get_or_create()
other_user = conversation.members.filter(id=profile_id).get()
form = MessageForm({'sender': request.user, 'conversation': conversation})
context = {'form' : form, 'other_user': other_user }
return render(request, 'dating_app/message.html', context)
models.py/Conversation
class Conversation(models.Model):
members = models.ManyToManyField(settings.AUTH_USER_MODEL)
So, I figured out by using 'add()' to add my members after I created my object since it's a many to many field.
conversation, created = Conversation.objects.filter(members = request.user).filter(members= profile_id).get_or_create()
conversation.members.add(request.user, profile_id)

Deleting records in Django via forms

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)

Insert or update data with Django formsets

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})

Django Overwrite existing instance in table

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 )

form instance of a model gives id=None Django

I'm misunderstanding something! If my model is not saved, it does not have an id associated with it. So if I have something like this:
views.py (inserting or editing existing info uses the same modelform)
def insert_or_modify(request, id=None):
if id is not None:
book = BookModel.objects.get(pk=id)
else:
book = BookModel()
if request.method == 'POST':
form = BookInfoForm(request.POST, request.FILES, instance=book)
if form.is_valid():
form.save()
....
return render_to_response(...)
I also have an image and use upload_to for the imagefield. There are two problems: id is None and I'm not sure how to manipulate/save the instance=book so that I would actually get an id. The second problem is the location I save my data to is way off. Even though the template tag book.img.url has the desired location of the book at http:127.0.0.1:8000/folder1/media/id/, the actual location is somewhere else:
Where I want to save my image to:
/project/folder1/media/id/
where id is the book id.
What I actually get:
/project/id/
(But 'id' becomes 'None' since it doesn't exist!)
My previous code worked. It would save to the correct location, but with this current code, it doesn't work. So the saving issue doesn't seem like it's due to settings.py since it worked previously.
EDIT: removed non-code from code formatting area
EDIT: I found out why I wasn't saving to the correct location. As it turned out, I forgot to uncomment something when I last modified settings.py. Saving to the location works now! Sorry guys!
EDIT: I think the id=None problem is caused by form.save(). If I avoid doing that and just save to the model directly, I don't have this problem.
Id assigns only on saving objects when you use autoincrement id field (default).
You can save item before handling image, and then save image.
May be you can not worry about image name - becouse django file storages dont have troubles with same image names. So if you just save file "image.png", and then save another file with name "image.png" - then it will be saved as "image_1.png"
def add_or_create(request, item_id=None):
item = get_object_or_404(BookModel, id=item_id) if item_id else None
form = BookInfoForm(request.POST or None, request.FILES or None, instance=book) # assume it is ModelForm
if form.is_valid():
book = form.save()
For the first part:
def insert_or_modify(request, id=None):
if id:
book = BookModel.objects.get(pk=id)
if request.method == 'POST':
form = BookInfoForm(request.POST, request.FILES, instance=book)
if form.is_valid():
save_book = form.save()
# use save_book as your instance of BookModel
....
else:
if request.method == 'POST':
form = BookInfoForm(request.POST, request.FILES)
if form.is_valid():
save_book = form.save()
# use save_book as your instance of BookModel
....
save_book = form.save() allows you to then use save_book as your saved instance of BookModel, and save_book.id is its id.
def create_id(instance,some_id=None):
if some_id is None:
obj=Post.objects.first()
new_id=obj.id
new_id+=1
return new_id
else:
return some_id
def pre_save_post_receiver(sender, instance, *args, **kwargs):
if not instance.id:
instance.id = create_id(instance)
pre_save.connect(pre_save_post_receiver, sender=Post)