Pymongo $Unset doesn't do anything - python

I'm using pymongo and flask to put information about which desktops a person owns from a database onto a webpage in a table. Simple enough. But I have a button which is supposed to remove a desktop from the database using $pull.
The mongo document looks like this:
{
"_id" : ObjectId("55c4a89a80071a0ef20e4df1"),
"Hostname" : "XXXXXXXXX",
"BUILD OS" : "WINDOWS 7 ENTERPRISE",
"Current User" : "CAMPELK",
"Primary User" : "CAMPELK",
"Location" : "XXXXX",
"Model" : "vmware inc. vmware virtual platform",
"BUILD Version Full" : "5.1.00.00",
"BUILD Version" : 5.1,
}
(I've had to censor some data due to workplace rules)
The name of the desktop model is returned from a drop down menu form as a string like this:
#app.route('/contact_desktop', methods=['GET', 'POST'])
def contact2():
form1= name_search()
name = form1.name.data
choices = DI.make_dictionary()
form2 = ContactFormDesktop()
models = DI.return_model(name)
if request.method == 'POST':
DI.remove_give_back_desktop(models, form2.choose_desktop.data, name)
return render_template('thanks.html', thing = "desktop")
And the remove_give_back_desktop() method is supposed to remove the field which matches the model string returned by the form:
def return_model(name):
models = list()
for entry in db.names.find({}):
model = entry["models"]
models.append(model)
return models
def remove_give_back_desktop(model1, model2, name):
for entry in model1:
if entry == model2:
db.desktops.update_one({"Current User":name, "Model": entry},{"$unset":{"Model":""}})
However, nothing is happening when I click the button in the html page, no errors are thrown and the code runs just fine otherwise, but the field that was supposed to be removed is still there.
The update $unset method works in the mongo terminal when I manually insert the name and model, so is my syntax wrong for pymongo or is there a deeper problem?
Thanks!

Related

Update Contacts using Python, Django and Graph

I'm trying to update contacts using Python and Microsoft Graph within a profile page I've created using Django.
I can access contacts and get all the data I need, however I can't work out how to update the fields.
The only information I can find is on the Graph website, however I can't work out how to translate this into usable code:
PATCH PATCH https://graph.microsoft.com/beta/me/contacts/
Content-type: application/json
{
"title": "Mr",
"givenName": "Steve"
}
I assume there is a way to just put this together as a simple link but I cannot work it out. I've tried the following:
PATCH https://graph.microsoft.com/beta/me/contacts/{id}/title/Mr
PATCH https://graph.microsoft.com/beta/me/contacts/{id}/title:Mr
PATCH https://graph.microsoft.com/beta/me/contacts/{id}/title/$value==Mr
but they all produce errors
There are no tutorials for doing this with Python on the Microsoft site and it's proving very difficult to find any info on it. So hopefully someone can help out.
Cheers!
!!!!!!!!!!!!! UPDATE !!!!!!!!!!!!!!!!!!
Here is my current code which still sadly does nothing:
In my views.py:
def profile(request):
if request.session['has_id']==False:
contact_id = request.session['contact_id'] = request.POST.get('edit')
request.session['has_id'] = True
else:
contact_id = request.session['contact_id']
context = ct.profile(request,id=request.session.get('contact_id'),init=initialize_context,get_tok=get_token)
if request.method=="PATCH":
ct.update(contact_id,'title',request.PATCH.get('title'))
return render(request, 'tutorial/profile.html', context)
and my updater:
def update(id,key,value):
url = '{}/me/contacts/{}'.format(graph_url,id)
payload = {key : value}
head = {
"Content-type" : "application/json",
}
requests.patch(url=url,data=payload,headers=head)
Finally worked it out, I thought I'd tried something like this yesterday but apparently not.
Here's how to do it!
views.py
def profile(request):
if request.session['has_id']==False:
contact_id = request.session['contact_id'] = request.POST.get('edit')
request.session['has_id'] = True
else:
contact_id = request.session['contact_id']
context = ct.profile(request,id=request.session.get('contact_id'),init=initialize_context,get_tok=get_token)
if request.method=="PATCH":
ct.update(contact_id,'title',request.PATCH.get('title'))
return render(request, 'tutorial/profile.html', context)
contacts_helper.py:
def update(token,id,key,value):
graph_client = OAuth2Session(token=token)
url = '{}/me/contacts/{}'.format(graph_url,id)
payload = {key : value}
graph_client.patch(url,data=json.dumps(payload),headers={'Content-type': 'application/json'})
Obviously if you're looking at this you've probably already set up auth_helper.py and graph_helper.py but if you haven't then you should head over the Microsoft Graph website and follow these instructions:
https://developer.microsoft.com/en-us/graph/get-started/python

CouchDB write/read only (no edit) user

Toolchain/frameworks
I'm using django==2.1.3 and python-cloudant==2.1.3 and running CouchDB ver. 2.2.0, and pretty much doing all of my setup/configuration through Fauxton. I like to think that I know my way around python/django in general, and I'm testing this approach in a small little project to see how it works
Problem Description
Suppose I have a fairly simple CRUD application with just 1 model:
class Asset(models.Model):
asset_id = models.CharField(max_length=32)
asset_name = models.CharField(max_length=32)
and I have a view that I use to create the asset
class CreateAssetView(views.View):
def get(self, request, *args, **kwargs):
#some code here
def post(self, request, *args, **kwargs):
#some code here|
#log request data into database
client = CouchDB('myusername', 'mypassword', url='http://127.0.0.1:5984', connect=True)
db = client['assets']
log_data = {'view_name': self.view_name, 'post_data': post_data,'user': request.user.username,
'time': str(timezone.now())}
db.create_document(log_data)
return render(...)
I understand that I should be doing the logging portion using a middleware (which I plan to) and probably just use django's CreateView in that case, I'm doing this approach for now just during early development.
What I'm having a problem wrapping my head around is creating a user with myusername and mypassword that has the permissions to:
Write new documents
Read old documents
not edit already created documents
I could even settle for 1 and 3 only (and only use admin to read). I spent a little bit of time playing around with Fauxton's interface for permissions, but I can only basically create a user and assign a role (couldn't even get to assigning a password :/)
clarification
The Asset is not a CouchDB document, that's a normal SQL model, I only want to dump the logs with post data to CouchDB
Any help/gudiance/documentation pointers would be really appreciated
Overview
Couchdb has one overriding level of administrator setup in configuration instead of setup in the _users database and assigned the _admin permission to prevent any possibility of being locked out.
Each individual database then has a rough level security policy of 2 levels:
admins
members
specified via:
names
roles
making 4 fields.
These levels control access slightly differently for the 2 types of documents a db can contain:
id: _design/* - Design documents can contain functions that will be executed in some context
id: other - Normal documents are just normal data
Both levels of database access have read access to all documents in the database, but admins have write access to _design documents. Write access to normal documents is usually given to all users granted any access to the db, but can be limited by validate design documents.
To Summarize
The process for setting a unique security policy up is:
Experience the provided validate design document as a consumer while setting up _users.
Setup a new database and its basic security giving your users member access.
Add a design doc to the new database with a validate function that restricts member write access.
1 Setting up _users entries
Add a role to a user
As an admin add role: ["logger"] to a user's doc and save it, note that this must be done by admin due to this part of the default _users design document:
// DB: _users doc: _design/_auth
function(newDoc, oldDoc, userCtx, secObj) {
..
if (oldRoles.length !== newRoles.length) {
throw({forbidden: 'Only _admin may edit roles'});
}
Change the password for the user.
Either the admin or the user can change their password by setting password:"mynewpassword" in their document (which couchdb will transform into a hashed/salted password during the save process). This works for a user since they can add/modify fields aside from their name and roles, as long as a user is editing their own doc:
// DB: _users doc: _design/_auth
function(newDoc, oldDoc, userCtx, secObj) {
..
if (userCtx.name !== newDoc.name) {
throw({
forbidden: 'You may only update your own user document.'
});
}
// then checks that they don't modify roles
You could repeat this process with a user you assign an adminlogger role to create a delegated administrator that you assign permissions to can reconfigure a database or you can continue to use the couchdb admin with its _admin role for all administration.
2 Setup a new database and its basic security
Create a db named logger
assign the logger a security policy:
{
"admins": {
"names": [
],
"roles": [
"adminlogger"
]
},
"members": {
"names": [
],
"roles": [
"logger"
]
}
}
3. Create a new validate design document in the new db
As either _admin user or a user with the adminlogger role create a new validate design doc by copying the _users design document, removing the _rev and modifying the function:
// DB: logger doc: _design/auth
function(newDoc, oldDoc, userCtx, secObj) {
// Don't let non-admins write a pre-existing document:
if (!is_server_or_database_admin()) {
if (!!oldDoc) {
throw({
forbidden: 'You may not update existing documents.'
});
}
}
// Where the function to define admins can be copied verbatim from the doc:
var is_server_or_database_admin = function(userCtx, secObj) {
// see if the user is a server admin
if(userCtx.roles.indexOf('_admin') !== -1) {
return true; // a server admin
}
// see if the user a database admin specified by name
if(secObj && secObj.admins && secObj.admins.names) {
if(secObj.admins.names.indexOf(userCtx.name) !== -1) {
return true; // database admin
}
}
// see if the user a database admin specified by role
if(secObj && secObj.admins && secObj.admins.roles) {
var db_roles = secObj.admins.roles;
for(var idx = 0; idx < userCtx.roles.length; idx++) {
var user_role = userCtx.roles[idx];
if(db_roles.indexOf(user_role) !== -1) {
return true; // role matches!
}
}
}
return false; // default to no admin
}
}
If you followed these steps then the user you gave the logger role in step 1 can run your code to write new documents only in logger database configured in steps 2 and 3.

How to use a queryset result to filter other queryset in DJango ORM?

I am trying to call a view using AJAX, but I have a problem. I have a token for the submit, the function that calls to Django view is working, I followed all the instructions of this link: https://realpython.com/blog/python/django-and-ajax-form-submissions/, but in the console I get the following error:
500: DoesNotExist at /Buscar/Producto/
InventarioProducto matching query does not exist.
/Buscar/Producto/ is the URL connected to the view, that is working, I think that is not the problem.
After importing the models, I tried the following in Django shell:
resp_producto=Producto.objects.filter(codigo_producto=9786071411532)
resp_inventario=InventarioProducto.objects.get(producto_codigo_producto__in=resp_producto)
resp_precio=Precio.objects.filter(producto_codigo_producto__in=resp_producto,estado_precio='1').order_by('-idprecio')[:1]
In the shell, if I print the variables were I saved the querysets, I can see the results, so i don't know why this is not working on the view.
9786071411532 is a product code that exist in the MySQL database, it is saved in a column named codigo_producto, which is the same name of a field saved in the model Producto, actually it is a primary key.
Explaining the models:
InventarioProducto has a field that is a foreigin key from Producto. The field in the model InventarioProducto is called producto_codigo_producto, and the primary key of Producto is called codigo_producto. So producto_codigo_producto referes to codigo_producto.
The model Precio has the same foreign key with the same name used in the model InventarioProducto, so they work in the same way.
Also I make sure that all the data that I'm requesting really exists.
Here is the view:
def BuscarProducto(request):
if request.method == 'POST':
txt_codigo_producto = request.POST.get('id_codigo_producto')
response_data = {}
resp_producto=Producto.objects.filter(codigo_producto=txt_codigo_producto)
resp_inventario=InventarioProducto.objects.get(producto_codigo_producto__in=resp_producto)
resp_precio=Precio.objects.filter(producto_codigo_producto__in=resp_producto,estado_precio='1').order_by('-idprecio')[:1]
response_data['result'] = 'Create post successful!'
response_data['codigoproducto'] = resp_producto.codigoproducto
response_data['lote'] = resp_inventario.idinventario_producto
response_data['descripcion_producto'] = resp_producto.descripcion_producto
response_data['precio'] = resp_precio.valor_precio
return HttpResponse(
json.dumps(response_data),
content_type="application/json"
)
else:
return HttpResponse(
json.dumps({"nothing to see": "this isn't happening"}),
content_type="application/json"
)
I've moved the SOLVED text to an answer:
I changed this:
resp_inventario=InventarioProducto.objects.get(producto_codigo_producto__in=resp_producto)
To this:
resp_inventario=InventarioProducto.objects.filter(producto_codigo_producto__in=resp_producto)

passing user data with Python-Flask and mongoDB

So basically I have an "/add" route where it is used to manually seed in test user data to mongodb and I want to be able to pass that user's ID to the URL for the route "/agreement" so when the user is on the agreement page, their "_id" will be mapped to that URI and the info they enter on the agreement page will update their data that we seeded in the "/add" route.
#app.route('/add')
def add():
users = mongo.db.users
users.insert({
"_id" : "autogenID",
"_comment" : " File structure for files in client collection",
"client_name" : "Name_of_firm",
"contact_name" : "Name_of_contact",
"contact_email" : "Email_ID_of_contact",
"contact_password" : "passowrd_encryped_bcrypt",
"client_industry" : "client_industry",
"monthly_checks_processed": "monthly_checks_processed",
"parent_id" : "client_id",
"child_id" : [{
"child_id": "client_id",
"child_id": "client_id"
}],
"agreement_authorised" : "boolean_yes_no",
"agreement" : "agreement_text",
"client_card" : [{
"name_on_card": "client_name",
"credit_card_number": "credit_card_number_bycrypt",
"expiration_date" : "expiration_date_bycrypt",
"credit_card_cvc" : "credit_card_cvc_bycrypt",
"active" : "boolean_yes_no"
}]
})
all_users = users.find()
for user in all_users:
print user
#app.route('/agreement', methods=['GET', 'POST'])
def agreenment(id):
user = mongo.db.users.find("_id")
print user
return render_template('agreement.html', user=user)
I think the issue lies in the agreement resource where maybe I should write /agreement/<id> but I think I am missing a fundamental understanding of where the <id> is instantiated. I also don't completely understand what the function of the agreement parameter is but I put (id) because this seems like something I would have to do in order to get the user's info passed to another resource.
I also think user = mongo.db.users.find("_id") might not be correct as well as return render_template('agreement.html', user=user). Part of me thinks that maybe I should do redirect instead of render but if anyone can lend a hand I would greatly appreciate it.
Try this:
#app.route('/agreement/<user_id>', methods=['GET', 'POST'])
def agreement(user_id):
user = mongo.db.users.find_one({"_id": user_id})
print user
return render_template('agreement.html', user=user)
URL parameter names in Flask are specified in the route parameter, and they have to match the decorated function's signature.
Querying in Mongo is done by passing a dict specifying the constraints, so db.users.find_one({"_id": user_id}) will return a single result with _id matching the user_id variable.
Edit: Actually, as per the documentation, you can just do:
db.users.find_one(user_id).

Django form with dynamic fields and manytomany relationschips

I am a beginner Django user and have been stuck with this problem for weeks now.
Consider the following model
class Post(models.Model):
title = models.CharField(max_length=65)
author = models.ForeignKey(User)
date = models.DateField(auto_now_add=True)
content = models.TextField()
tags = models.ManyToManyField(Tag)
images = models.ManyToManyField(Image)
def __unicode__(self):
return self.title
I would like the User to be able to upload pictures to the with his model. I would like to be able to validate if
The user has at least uploaded one image and limit the maximum number of images to a certain number.
Basically do the same for tags. But with tags I would also like Django to check if the tags already exists and if so add it to the model.
Let the user push a button that says add Tag / add Image to make a new field pop up.
Problems I have encountered so far.
I am required to save a model before I can add many to many relations. This is a bit annoying because if an error occurs halfway down the road is might be possible that half the model is saved and the other is invalid.
I know that I can add extra field to the DOM using js however I got no clue how to process those in the View function.
For problem 1, this makes sense because if you create a model which is refered to by other models, said model key must exist. What I'd suggest you do is look into saving multiple models with a transaction.
2 is pretty easy, just use jQuery/Javascript to show/hide the appropriate fields in the browser based on the user's selection event.
Based on your comment, here's an example of how I handle data to and from the server
//Submit data to server, assuming you have already extracted out the relevant data values
$("some_button").click(function(e){
$.ajax({
url : "someUURLLocation/",
type : "POST",
data : {"data" : JSON.stringify({"field1" : var1, "field2" :var2}),
dataType : "json",
success : function(results){
if (results.success == "true") {
//handle DOM insertion and other stuff
} else
alert(results.message);
}
});
}
urls.py:
from django.conf.urls import patterns, url
from $APPNAME import views
urlpatterns = patterns("",
...
...
url(r'^someURLLocation/$', views.handleDataSubmission),
...
)
views.py:
from django.http import HttpResponse
from django.utils import simplejson
def handleDataSubmission(request):
data = simplejson.loads(request.POST.get("data", None))
if data is not None:
newPost = Post.objects.create( field1 = data["field1"], field2 = data["field2"])
dataReturn = [{"val1" : newPost.title, "val2" : newPost.date}]
return HttpResponse(simplejson.dumps({"success" : "true", "data" : dataReturn}), mimetype = "application/json")
else:
return HttpResponse(simplejson.dumps({"success" : "false", "message" : "Invalid data received by server"}), mimetype = "application/json")

Categories