I'm building a Flask backend. I have this route that should return the ID that matches the email
#app.route('/login', methods=['POST'])
def login():
email = request.json['data']
id = session.query(Users).filter_by(email=Users.estudent_email)
result = users_schema.dump(id)
return jsonify(result)
I'm currently sending it this data
{
"data": "name.lastname#email.com"
}
But it returns a whole bunch of data which is incorrect. It should return a single ID from the database that is assigned to the user that holds the email. What might be the cause? I'm using Marshmallow and SQLAlchemy ORM.
The problem is probably in this line:
id = session.query(Users).filter_by(email=Users.estudent_email)
You seem to have the equality check the wrong way around. Users.estudent_email references the entire field of the database, and email is a named argument in filter_by, not email that you defined in the previous line.
I can't test but I'm thinking you want:
id = session.query(Users).filter(Users.estudent_email==email)
or
id = session.query(Users).filter_by(email=email)
As for the serialization, and result = users_schema.dump(id), I have no idea because there is not enough context given to be sure how to make that work.
Related
I want to write a unittest for this method in Django.
def activate(request):
id = int(request.GET.get('id'))
user = User.objects.get(id=id)
user.is_active = True
user.save()
return render(request, 'user_authentication/activation.html')
I wrote sth like this:
def test_activate_view(self):
response = self.client.get('/activation', follow=True)
self.assertTemplateUsed(response, 'user_authentication/activation.html')
It doesn't work because I get an error:
id = int(request.GET.get('id'))
TypeError: int() argument must be a string or a number, not 'NoneType':
What should I change in my test ?
Your view reads data from request.GET - you need to pass this data:
response = self.client.get('/activation?id=1', follow=True)
You also fetch this user afterwards from your database. Therefor you need to load some fixture data. Create a fixture using manage.py dumpdata and load it in your unit test like that:
class UserTestCase(TestCase):
fixtures = ['fixture.json', 'users']
Read the docs about loading fixtures for detailed explanations.
Note regarding your approach
You should not use the users id for this use case. One can easily guess this id and activate accounts.
Someone might register once with a valid email address, receive your link with the id inside and can afterwards create a bunch of accounts without providing a valid email address.
Instead you might generate a unique and random secret (aka token) and associate this token with the user. Your view should accept those tokens and resolve the user based on it. This way one can no longer easily activate.
So far I am using colander to validate the data in my aiohttp application.
The problem I face is that I don't know how to do "deep" validation.
Given the following schema:
import colander
class User(colander.MappingSchema):
username = colander.SchemaNode(colander.String())
password = colander.SchemaNode(colander.String())
confirmation = colander.SchemaNode(colander.String())
I do both validate that the input datastructure has all the required fields are there (constraints are minimal for the sake of clarity) but I also need
to check that:
username is not already taken by another user
password and confirmation are the same
So in my controllers, the code looks like the following pseudo code:
def create_user(request):
user = await request.json()
schema = User()
# do schema validation
try:
user = schema.deserialize(user)
except colander.Invalid, exc:
response = dict(
status='error',
errors=errors.asdict()
)
return json_response(response)
else:
# check password and confirmation are the same
if user['password'] != user['confirmation']:
response = dict(
status='error'
errors=dict(confirmation="doesn't match password")
)
return json_response(response)
# check the user is not already used by another user
# we want usernames to be unique
if user_exists(user['user']):
response = dict(
status='error',
errors=dict(username='Choose another username')
)
return json_response(response)
return json_response(dict(status='ok'))
Basically there is two kinds of validation. Is it possible to have both logic in single colander schema? Is it a good pattern?
Obviously it's a matter of taste but IMHO it's better to keep data validation separate from application logic.
You'll also run into a few problems trying to confirm that the username is unique:
Colander would need to have knowledge about your application eg. get access to the database connection to check with the database that that username doesn't exist.
Colander (AFAIK) isn't setup for asyncio programming so it'll have problems coping with an async method which checks the user exists.
You really want to user creation to be ACID, so simultaneous calls to create_user with the same username cannot possibly create two users with the same username.
Checking passwords match is another story, that doesn't require any knowledge about the rest of the world and should fairly trivial with colander. I'm not expert on colander, but it looks like you can use a deferred validator to check the two passwords match.
A few other notes on your code:
create_user should be an async method
I don't know anything about your db, but to get any advantage from async programming user_exists should be async too
The user existence check should be wrapped into the ACID user creation. Eg. you should use postgres's on conflict or equivalent to catch a duplicate user as you create them rather than checking they exist first
To be properly restful and make testing easier your view should return the correct http response code on an error (currently you return 200 for all states). You should use 201 for created, 400 for invalid date and 409 or a username conflict.
For my site for auth I'm using https://flask-httpauth.readthedocs.io/en/latest/ . Now I'm trying to make it that it's using data from database. To do that i created database named Users and created columns named username and password.
To get data from this table after defining its class as model I've made get_user functions which looks like it:
#staticmethod
def get_user():
query = (Users
.select())
user = []
for s in query:
user.append(s)
return user
(I'm not sure if it's correct)
Next I had to modify get_pw function but I also wasn't sure how to modify it so I made it look like it:
#auth.get_password
def get_pw(username):
if username in Users.get_user():
return users.get(Users.get_user())
return None
Now after running the site I get prompt to give login and password but those that I set up in my database doesn't seem to work so there must be a problem with get_pw function. Also I'm using peewee SQL to manage database : http://docs.peewee-orm.com/en/latest/peewee/querying.html
You can get rid of your get_user method since you are issuing a very large select query that fetches all records from user table. The get_pw can be redefined as:
def get_pw(username):
user = Users.get(Users.name == username) #assuming you have a username field in model
return user.password #assuming a password field
Also, its a good practice to define your model class as a singular noun rather than plural. So, its better to call it User rather than Users.
This'll help you get started in no time: http://docs.peewee-orm.com/en/latest/peewee/quickstart.html#quickstart
I need to build a rest api using django. On GET requests my tool has to captures parameters from url and invoke a function for their manipulation.
For example: on input url myapp/name=john&birthdate=11July, the function compute(name,birthdate) computes a transformation on parameters returning a json as output. I don't understand how to proceed, considering that each tutorial i followed is about db interaction.
urls.py:
url(r'^myapp/$', views.myapp, name='myapp'),
views.py
def myapp(request):
name = request.GET.get('name', None)
birthdate = request.GET.get('birthdate', None)
if name and birthdate:
result = compute(name, birthdate)
return result
return None
You don't need a database for that. Although you need a database for Django to work.
I have a flask app with database. I need to localize some types of entities there.
The problem is, i am using Flask-Marshmallow for parsing/serializing my database objects.
And there is an endpoint, that grabs the root object (User) and all it related nested objects (Match), which in it's turn grab it's related objects (Question), which i need to localize.
So, having Accept-Language header can't be directly passed to nested->nested (Question) object.
It's some architecture issue, i believe, not a technical one. If someone ever face such a problem and know any workarounds, please let me know.
# views.py
#app.route('/self', methods=['GET'])
#auth.login_required
def get_user:
user = g.user
schema = UserSchema()
res = schema.dumps(user)
# UserSchema.py
class UserSchema(marshmallow.Schema):
id = fields.Int()
matches = fields.Nested('MatchSchema', many=True)
// etc.