Update Existing Document : Mongo Alchemy - flask

I need some help with MongoAlchemy. I'm trying to create a web application with python, flask, Mongo DM and Mongo Alchemy (as an object document mapper) and I'm struggling with updating existing documents.
My problem is that I cannot update an existing document through it's object Id. Below I'm attaching my def for updating
#app.route('/update', methods =[ 'GET', 'POST' ])
def update():
if request.method == 'POST':
id = request.form['object_id'] # Getting values with html
patientzero = BloodDoonor.query.get_or_404(id)
first_name = request.form['name']# Getting values with htmlform
last_name = request.form['surname']# Getting values with html form
blood_type = request.form['blood_type']# Getting values with html
update_record = BloodDoonor.patientzero.update(BloodDoonor.last_name = last_name)
return render_template('update.html', result = result)
And flask gives me that error:
AttributeError AttributeError: type
object 'BloodDoonor' has no attribute 'patientzero'
I'm very new to Python and not very good in code. Please forgive me for the sloppy description I gave above. Any help would be appreciated.

To update an existing document just change the value of the object which you queried from db with form values and then just save that object:
#app.route('/update', methods =[ 'GET', 'POST' ])
def update():
if request.method == 'POST':
id = request.form['object_id']
patientzero = BloodDoonor.query.get_or_404(id)
patientzero.first_name = request.form['name']
patientzero.last_name = request.form['surname']
patientzero.blood_type = request.form['blood_type']
patientzero.save()
return render_template('update.html')

Related

What is the difference between using Django form and manually setting date fields?

I am getting date/time info from ajax to Django. I am using 2 different views. event_edit is working fine, but event_edit_new does not work. It return an error Enter a valid date/time.
My question is what is making difference. They are getting exactly same information but one is ok while other one is not.
Javascript code making ajax request:
var ajax_test = function(event){
$.ajax({
url: '/scheduler/event/' + event.eventId + '/edit2/',
method: 'POST', // 'POST' or 'PUT'
data: {
'Note': event.title,
'OpNum': event.resourceId,
'StartTime' : event.start.format(),
'StopTime' : event.end.format(),
'ScheduleNum': event.eventId,
}
}).done(function(res) {
console.log("done", res)
}).fail(function(error) {
console.error("error", error)
console.log(event.start.format());
});
}
2 views
def event_edit(request, pk):
schedule = get_object_or_404(Schedule, pk=pk)
schedule.OpNum = request.POST.get('OpNum')
schedule.Note = request.POST.get('Note')
schedule.StartTime = request.POST.get('StartTime')
schedule.StopTime = request.POST.get('StopTime')
schedule.ScheduleNum =request.POST.get('ScheduleNum')
schedule.save()
return HttpResponse('ok')
def event_edit_new(request, pk):
schedule = get_object_or_404(Schedule, pk=pk)
if request.method =='POST':
form = ScheduleForm(request.POST, request.FILES, instance = schedule)
if form.is_valid():
form.save()
return HttpResponse('ok')
else:
return HttpResponse('error')
else:
return HttpResponse('done')
In your first view, there is no validation applied to user data input:
schedule.StartTime = request.POST.get('StartTime')
schedule.StopTime = request.POST.get('StopTime')
request.POST does not validate any data so that will grab user data exactly as submitted and set it on a model. Note that it might work but it is not guaranteed to work if user will ever send datetime format the application does not understand. For example try submitting something like "invalid date" and you should get 500 error.
Your second view on the other hand uses a Django Form to validate user input. By using a form you are validating user input before processing it in any way. You did not paste how your form is structured however if you are getting Enter a valid date/time. this means Django form did not validate one of the datetime fields. There are couple of reasons why that might be:
submitted datetime does is not one of input_formats for a DateTimeField. You can customize the formats with:
class MyForm(forms.Form):
datetime_field = forms.DateTimeField(input_formats=['%Y-%m-%dT%H:%M:%SZ', ...])
submitted datetime is not one of Django's default supported datetime formats.
You can customize them with DATETIME_INPUT_FORMATS setting.

How to perform the delete method in drf django

How to perform the delete request in Django drf? How will I pass the params for the request?
Kindly help with the solution. I am very new in this drf-django-python programming.
class DeleteView(APIView):
def delete(self, request,format=None):
id = request.POST['book_id']
email = request.POST['email']
book = models.Book.objects.filter(book_id=id)
book_uploader = serializers.BookSerializer(book[0]).data['uploader']['email']
logged_in = request.user
print(log)
if book_uploader == logged_in :
books = models.BookUserRelationship.objects.filter(book= id, user__email=email)
books.delete()
return Response("Successfully removed", status=status.HTTP_204_NO_CONTENT)
else :
return Response("Not able to remove")
In comments you noticed that parameters will be embedded in url but you are trying to get values from POST dict.
If your url is something like
/books/id/email/
You should use request.kwargs dict like request.kwargs.get('email')
But if your url is like
/books/id/?email=someemail#google.com
id would be in request.kwargs but email in request.query_params
Notice that every url variable is in the request.query_params dict.
IMPORTANT
If you have ID url param without named group, viewset would not be able to get this from request.kwargs by name

Django How to save and retrieve survey state in database

How can I save and retrieve a django form state to database?
Users are filling in a lengthy survey and want to save the survey state in between.
My ideas were:
Option 1. Saving request.POST to database (doesn't work), and then:
SurveyForm(my_saved_form_state or request.POST)
Option 2. Saving cleaned_data to database (does work) and then:
SurveyForm(my_saved_form_state or request.POST or None)
but the cleaned_data doesn't instantiate the form! Only the full request.POST (a QueryDict) seems to do that. How to proceed?
So I solved it, finally.
Saving the POST data to database:
postdata = {}
for key in request.POST.iterkeys():
if len(request.POST.getlist(key)) > 1:
postdata[key] = request.POST.getlist(key) # for checkboxes
else:
postdata[key] = request.POST.get(key, u'') # for all others
person.saved_answers = postdata
person.save()
Loading it from database:
saved_answers = ast.literal_eval(person.saved_answers) # convert unicode string into python object
SurveyForm(saved_answers)

Can Django class base view handle REST API?

I am using Django generic view. For some reasons, I am not allowed to use other Rest Framework (e.g. Tastypie) to handle rest API.
I would like to see if I can use the generic view that can deal with CRUD http method.
Can anyone point me to an example?
So far my url is like this:
url(r'^user/$', views.UserView.as_view(), name='user'),
I am not sure how can one url handle all CRUD methods.
Thanks.
Here is an example of how it can be done, it really depends on your requirements and as you have not supplied any I will just talk about my use case instead which is EXTJS.
Here is the url.py, the action is 'c' for create and 'd' for delete. objtype is the name of the model and app is the application in which the model can be found (you might not need that).
url(r'^model_json/(?P<action>[a-z]+)/(?P<objtype>[A-Za-z0-9-_]+)', 'jsonhelper.views.flatdata_cud', {'ext':True,'app':rhinomodels }, name = 'model_cud_json'),
The URL from EXTjs will look this this for creating a new User. Of cause the User details are posted as json data which is available in the HTTP POST.
127.0.0.1:8000/model_json/c/User
Here is my code. get_fk_model is an internal function that will return the associated model of a fk object or None if its not of a fk type.
import json
#login_required
#csrf_exempt
def flatdata_cud(request, objtype, action, id = None, idfield = None, follow_related = False, app = None):
""" Implements the Create Update and Delete functions for ExtJS data store porxy's """
djmodel = getattr(app, objtype)
if not djmodel:
return errorMsg("Model not found, %s"%(objtype))
if request.method != 'POST':
return errorMsg("Must be a post action, %s"%(request.method))
data = json.loads(request.body)
if type(data) == dict:
data = [data,]
kwargs = {}
id_list = []
def check_value(data):
for k in data:
fkmodel = get_fk_model(djmodel, k)
if fkmodel: # we have a ForeignKey, change value to be an object of this type
data[k] = fkmodel.objects.get(id = data[k] )
return data
for d in data:
d = check_value(d)
id = None
if action == 'c':
rec = djmodel()
if d.has_key('id'): d.pop('id')
else:
id = d.pop('id')
rec = djmodel.objects.get(id = id)
if action == 'd':
rec.delete()
else:
for i in d.keys():
setattr(rec, i, d[i])
rec.save()
id_list.append( id if id else rec.id )
kwargs['id__in'] = id_list
return flatdata(request, objtype, id = id, idfield = idfield, follow_related = follow_related, add_filter = kwargs, app = app)
As the last step I return flatdata which returns to EXTjs a new json object of how the object look after the update.

submitting form results into db - django

i created a form to save a post into db for my blog project. I've designed index page. now i am tryin to create a form to create new posts. before that i was using ' manage.py shell'
here is my view :
def addpost(request):
form = addForm()
if request.method=="POST":
titleform = request.POST['title']
bodyform = request.POST['body']
checkform = request.POST['isdraft']
if form.is_valid():
n = Post(title = titleform, body = bodyform, isdraft=checkform)
n.save()
return HttpResponseRedirect('/admin/')
else:
pass
return render(request,'userside/add.html',{'form':form,})
my model.py:
class Post(models.Model):
title = models.CharField(max_length = 100)
body = models.TextField()
slug = AutoSlugField(populate_from='title',unique=True)
posted = models.DateField(auto_now_add=True)
isdraft = models.BooleanField()
def __unicode__(self):
return self.title
#permalink
def get_absolute_url(self):
return ('view_blog_post',None, {'postslug':self.slug})
class addForm(forms.Form):
title = forms.CharField(max_length=100)
body = forms.CharField(widget=forms.Textarea)
isdraft = forms.BooleanField()
if i submit form as 'isdraft' field is False(unchecked) ; it gives error like:
MultiValueDictKeyError at /admin/addpost/
"Key 'isdraft' not found in "
and if i submit the form as 'isdraft' field is True(checked) ; it gives nothing. just refreshing form. no adding data into db.
i am doing sth wrong..
thank you
edit : Dmitry Beransky's answer worked for checkbox error. but it still doesnt add any data into db. just refreshes the form.
The whole point of using a form is that it takes care of validation and cleaning, that is converting values to the proper data types. That's why you should be accessing form.cleaned_data rather than reques.POST, and you should be doing it inside the if form.is_valid() check.
Edit
I've just noticed that you're never passing request.POST to the form. So form.is_valid() will never be true.
Please go back and read the documentation about using a form in a view.
If a checkbox is not checked in your HTML form, it's name/value is not going to be included in the data that the browser sends to your server. Which meanst that the request.POST dictionary is not going to contain an entry for 'isdraft' which in turn will cause a key error when you try to read the isdraft value. A solution is to change the way you read the value from the posted data to:
checkform = request.POST.get('isdraft', False)
rather than throw an error if isdraft isn't found in the dictionary, this will set checkform to False (the default value in case of a missing key)
Maybe your form does not validate at all. Have you checked if your code even reaches those lines after the if form.is_valid() statement ? If they do, what you've done there is right and should create the db row for your new entry, though you could have used
Post.objects.create(....) , and that would have taken away the need for calling the method save().
Some points though:
instead of checking for request.POST , check for request.method == 'POST' , cause there might be a post which has an empty POST dict ( in case no arguments have been submitted ), in that case request.POST fails to provide the right check .
see the docs for more info : request.POST
instead of using request.POST['var_name'] , use request.POST.get('var_name', 'default_value') , cause doing this like request.POST['var_name'] might result in some exceptions ( in case for example the argument is not provided , like what happened for your checkform variable )
Try accessing those variables through form.cleaned_data
and finally , you don't need the else statement in the end , just use the indentation :)