How to save document using classmethod with mongoengine - mongoengine

I try to use class method in mongoengine to define a method that hash the password and write data to mongodb, then call the method outside the class, here is my code
model.py
from mongoengine import Document, connect, fields
connect("mongoUserDB", host="127.0.0.1", port=27017)
class Users(Document):
userID = fields.StringField(unique=True)
password = fields.StringField()
#classmethod
def signup(cls,**kwargs):
print(kwargs.get("password",cls.password))
cls.password = pbkdf2_sha256.encrypt(kwargs.get("password",cls.password))
print(cls.password)
Users(**kwargs).save()
api.py
from flask import render_template
from blueprint_poc.auth import bp
from models import Users
#bp.route("/sign-up", methods=['GET', 'POST'])
def sign_up():
Users().signup(userID='aaa',password='b')
It did write data to the db, but only with userID info,the password field is missing.
I am not sure what went wrong, any advice for this.

Related

Why is when i do put request using Django rest framework I got 200 but when i try to see one of fields it shows null using get request not the put one

I was trying to do put request on Postman and it's successful, but when I try the get method to get same result one of the fields which is car_year shows null.
from django.shortcuts import render
from django.http import HttpResponse,JsonResponse
from rest_framework.parsers import JSONParser
from .models import Driver
from .serializers import DriverSerializer
from django.views.decorators.csrf import csrf_exempt
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from rest_framework import generics
from rest_framework import mixins
from rest_framework.views import APIView
# Create your views here.
class GenericAPIView(generics.GenericAPIView,mixins.ListModelMixin,mixins.CreateModelMixin,mixins.UpdateModelMixin,mixins.RetrieveModelMixin,mixins.DestroyModelMixin):
serializer_class = DriverSerializer
queryset = Driver.objects.all()
lookup_field = 'id'
def get(self,request,id=None):
if id:
return self.retrieve(request)
else:
return self.list(request)
def post(self,request):
return self.create(request)
def put(self,request,id=None):
return self.update(request,id)
from django.db import models
# Create your models here.
class Driver(models.Model):
name=models.CharField(max_length=100)
email=models.EmailField(max_length=100)
phone_number=models.IntegerField(max_length=None)
car_model=models.CharField(max_length=100)
car_year=models.IntegerField(max_length=None)
def __str__(self):
return self.name
from rest_framework import serializers
from .models import Driver
class DriverSerializer(serializers.ModelSerializer):
class Meta:
model=Driver
fields=['id','name','email','phone_number','car_model','car_year'] ```
Instead of using that very GenericAPIView class that you've made, look into using a ModelViewSet. Besides that, you are missing the permissions_classes in your APIView.
Try this:
from rest_framework import viewsets, permissions
class DriverViewSet(viewsets.ModelViewSet):
queryset = Driver.objects.all()
serializer_class = DriverSerializer
permission_classes = [permissions.IsAuthenticated]
Also, your serializer looks fine.
car_year and phone_number are IntegerFields and you've set the max_length on them. That max_length=None should be removed.
Try the things I mentioned and it should would fine. I'm guessing it's most likely the view you are using but it could also be the integer field.
Also, if this is going to be a production app, the phone_number field shouldn't be an integer but rather a string, or better yet, you can use the django-phonenumber-field library.

How can I fetch more than one attribute from a serializer

My models have multiple attributes, all of which are being serialized.
According to the user's request, I want my API to return only limited information
This is my model's code
from django.db import models
class User(models.Model):
name = models.CharField(max_length=50)
age = models.PositiveSmallIntegerField()
description = models.CharField(max_length=200)
def __str__(self) -> str:
return self.name
This is my Serializer's code
from rest_framework import serializers
from .models import User
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = "__all__"
This is my View's code
from rest_framework.decorators import api_view
from rest_framework.response import Response
from .models import User
from .serializers import UserSerializer
from rest_framework import serializers
from rest_framework import status
from django.http import JsonResponse
#api_view(['GET'])
def viewUsers(request):
users = User.objects.all()
serializer = UserSerializer(users, many=True)
return JsonResponse({'id': serializer.data['id'], 'name': serializer.data['name']})
The code below works if I want to return a single attribute/field
return JsonResponse(serializer.data['id'])
but when I try to fetch more than one attribute by the dictionary method, it throws this error
list indices must be integers or slices, not str
many=True passed to UserSerializer indicates that serializer.data will contain a list of dicts where each particular dict will be a result of serializing User instance to expected dict
Taking into account serializer.data is a list then if you try to execute serializer.data['id'] it raises
list indices must be integers or slices, not str
You may want to update the return statement to
return JsonResponse([{'id': item['id'] for item in serializer.data}])
or specify that you expect only id field to be returned by the serializer
class UserSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ("id",)
and then in the view
return JsonResponse(serializer.data)

MongoEngine returns nothing

I'm creating a basic flask web application and want to get some data from my mongo database. In my views.py I have that:
from app import app
from app.models import User
#app.route('/')
def index():
return "Hello world"
#app.route("/users")
def about():
users = User.objects()
return users.to_json()
models.py:
from flask_mongoengine import MongoEngine
from app import db
class User(db.Document):
snp = db.StringField(required=False)
g = db.StringField(required=False)
card = db.StringField(required=False)
phone = db.StringField(required=False)
passport = db.StringField(required=False)
group = db.StringField(required=False)
meta = {'collection': 'User'}
def to_json(self):
return {
"name": self.snp
}
When I enter http://127.0.0.1:5000/users I get []. Find returns nothing but in my mongo database I have collection User with two document:
{"_id":{"$oid":"6089d5d13dc15d0a2c5f607e"},"snp":"testov1 test1 testovich1","g":"f","card":"12345","phone":"8888888881","passport":"8888 48484848","group":"users"}
and
{"_id":{"$oid":"6089d5fd3dc15d0a2c5f607f"},"snp":"testov2 test2 testovich2","g":"m","card":"1676767","phone":"88566768881","passport":"8888 234343434","group":"users"}
Connection to database is correct.
I'm new to flask and mongoEngine.
If you print users, you will see a list of 'User' objects, Actually When you try to get all users with User.objects() , the result is of type <class 'flask_mongoengine.BaseQuerySet'>, so calling users.to_json() is wrong since it is not an instance of class User .
But if you get only one user with something like User.objects().first(), the result would be of type "User", and then you can call user.to_json().

Flask-Login using Radius

I am trying to setup Flask-Login where the user database is on a RADIUS server.
I can validate credentials just fine against it, but most online examples use SQLAlchemy. Do I still need to use SQLAlchemy if I am not using my own database for Flask?
I am getting errors when the User(Mixin) class is ran.
AttributeError: 'str' object has no attribute 'is_active'
My User class is simple since I do not need have my own DB, just need the 4 methods from the docs.
class User(UserMixin):
pass
Here is some code for trying this just with a dictionary as the DB:
from flask import Flask, url_for, render_template, redirect
from forms import LoginForm
from flask_login import LoginManager, UserMixin, login_required, login_user
users_db = {'user1': 'pass1'}
app = Flask(__name__)
login_manager = LoginManager()
login_manager.init_app(app)
#login_manager.user_loader
def load_user(user_id):
if user_id in users_db:
print('user found in DB')
return user_id
else:
return None
class User(UserMixin):
pass
app.config['SECRET_KEY'] = 'abc123'
#app.route('/', methods=('GET', 'POST'))
def Login():
form = LoginForm()
if form.validate_on_submit():
print('validated')
username = form.username.data
login_user(username)
next = flask.request.args.get('next')
if not is_safe_url(next):
return flask.abort(400)
return flask.redirect(next or flask.url_for('hi'))
return render_template('login.html', form=form)
#app.route('/hi')
def hi():
return """<h1>Hi</h1>
{% if current_user.is_authenticated %}
Hi {{ current_user.name }}!
{% endif %}"""
#app.route('/secure')
#login_required
def secure():
return "This is a secure page."
#app.route("/logout")
#login_required
def logout():
logout_user()
return redirect('https://cisco.com')
What would be obviously wrong here, or what could I be conceptually not understanding?
Thanks!!!
Your user_db only contains strings. You have to create an instance of the User class and return the instance on login.
See https://flask-login.readthedocs.io/en/latest/
PS I am on mobile, if this is not enough info, I'll update my answer later.
This article also introduces the login mechanism
https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins

Python 3, ODM (umongo), difficulty with relationship fields

I'm having some trouble getting relationships fields to work in umongo. Each Document definition is in a separate file.
In this example i have two basic entities, account and target.
each target has a reference to an account.
// account/schema.py
from datetime import datetime
from pymongo import MongoClient
from umongo import Instance, Document, fields, validate
import os
log = Config.config_logger(__name__)
mongo_url = os.environ.get('MONGO_URL')
db = MongoClient(mongo_url).mydb
instance = Instance(db)
#instance.register
class AccountSchema(Document):
user_id = fields.StringField(required=True, unique=True)
user_name = fields.StringField(required=True)
account_type = fields.StringField(required=True)
class Meta:
collection = db.account
# Make sure that unique indexes are created
AccountSchema.ensure_indexes()
try:
sub = AccountSchema(user_id='my8htwwi', account_type='SUBSCRIPTION', user_name='myuser')
sub.commit()
freeloader = AccountSchema(user_id='ouygouyg', account_type='FREE', user_name='myotheruser')
freeloader.commit()
except Exception:
log.info('account already created')
I've added some manual data there at the bottom, and that works fine when I execute this file, or import it elsewhere.
I define second entity schema for 'target'
// target/schema.py
from datetime import datetime
from pymongo import MongoClient
from umongo import Instance, Document, fields, validate
import os
mongo_url = os.environ.get('MONGO_URL')
db = MongoClient(mongo_url).mydb
instance = Instance(db)
#instance.register
class TargetSchema(Document):
account = fields.ReferenceField('AccountSchema', required=True)
date = fields.DateTimeField(
default=lambda: datetime.utcnow(),
allow_none=False
)
somefield = fields.IntegerField(required=True)
value = fields.IntegerField(required=True)
class Meta:
collection = db.target
# Make sure that unique indexes are created
TargetSchema.ensure_indexes()
service.py
from models.account.schema import AccountSchema
from models.target.schema import TargetSchema
class Service:
self._odm = TargetSchema
....
def save_test(data):
account = AccountRepo().find({'user_id': self._user_id})
# account returns a valid object
item = self._odm(
account=account,
somefield=123123,
value=1234
)
return item.commit()
When I call save_test method, I keep keep getting:
umongo.exceptions.NotRegisteredDocumentError: Unknown document class `AccountSchema`
I get the same error if i try and pass the class object AccountSchema in instead
from models.account.schema import AccountSchema
#instance.register
class TargetSchema(Document):
account = fields.ReferenceField(AccountSchema, required=True)
my feeling is it's about the order that I instantiate/import the instances, but trying to move them around, for example into __init__.py, doesn't seem to change anything.
Or how in each schema definition:
db = MongoClient(mongo_url).target
instance = Instance(db)
All examples I've been able to find keep the referencefield class definition in the same file, so I'm not really sure how to make the different registered instances 'aware' of each other.
so the issue was not declaring and registering all classes to the same db instance.
i.e. in the __init__.py for the models folder i moved:
from umongo import Instance, Document, fields, validate
from pymongo import MongoClient
db = MongoClient(mongo_url).mydb
instance = Instance(db)
then in each schema file:
from models import db
from models import instance

Resources