Create Webapp2 auth user with date property - google-app-engine

I have this basic model:
class User(auth_models.User):
username = ndb.StringProperty()
email = ndb.StringProperty()
first_name = ndb.StringProperty()
last_name = ndb.StringProperty()
employee_start_date = ndb.DateProperty()
However, when I create the user:
success, obj = self.auth.store.user_model.create_user(
"auth:"+ username,
unique_properties = ['email'],
email = emailaddress,
first_name = firstname,
last_name = lastname,
employee_start_date = startdate)
I get the following error:
NotImplementedError: Property employee_start_date does not support <type 'datetime.date'> types.
(Note: creating the user is successful if I don't include the employee_start_date)
Now, from what I can tell by searching the internet, this is because the user_model is an expando model, and for some reason it doesn't support date fields. However, I don't know that for sure.
I also tried adding it immediately after creating the user, but I get the same error message with this:
obj.employee_start_date = startdate
obj.put()
Is there a way to add a date property to this user model?

The startdate value that you try to assign to employee_start_date is not of type date, but datetime. In order for your code to work, you have two options:
1) Change employee_start_date to datetime:
employee_start_date = ndb.DateTimeProperty()
2) Make startdate variable as date and not datetime.

to use your own User class, make sure to set
config = {'webapp2_extras.auth':{
'user_model': 'your_auth.User'
}}
for the webapp2.WSGIApplication config argument

Related

DRF created_by updated_by fail during migrations

I want to add an created_by and updated_by field to all my DB objects. I created a common model for this that will be used by most other objects. I have sorted out most obstacles so far. But the make migrations script ends with an error:
My model:
class CommonModel(models.Model):
"""Common fields that are shared among all models."""
created_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT,
editable=False, related_name="+")
updated_by = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.PROTECT,
editable=False, related_name="+")
created_at = models.DateTimeField(auto_now_add=True,
editable=False)
updated_at = models.DateTimeField(auto_now=True,
editable=False)
class Meta:
abstract = True
class Tag(CommonModel):
"""Tag to be used for device type"""
name = models.CharField(max_length=255)
def __str__(self):
return self.name
The error I get is :
You are trying to add a non-nullable field 'created_by' to devicetype without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
Provide a one-off default now (will be set on all existing rows with a null value for this column)
Quit, and let me add a default in models.py
The only "solution" I found searching the Internet was to define default='', run the makemigrations again and then manually edit the files afterwards to remove the default=''.
I cannot believe that this is the proper way to do this and that there is no solution for this yet.
You need to set a default value for created_at and update_at, since they are not null=True.
The message you get during migration is not an error. If you want to provide a default value, select fix 1., it should show the below prompt,
Please enter the default value now, as valid Python
The datetime and ` modules are available, so you can do e.g. timezone.now
Type 'exit' to exit this prompt
>>>
Here you can set the default value using the datetime or django.utils.timezone module.

Peewee : How to update specific fields?

I'm using Peewee for working with database. I have a User tables with 3 fields: username, password and last_login. When a user login to the system i want to update last_login. I've use following lines of code:
from peewee import *
import datetime
class User(Model):
username = CharField(unique=True)
password = CharField()
last_login = DateTimeField(default=datetime.datetime.now())
class Meta:
database = MySQLDatabase('mydb', user='root', charset='123456')
u=User(username="user1", last_login=datetime.datetime.now())
u.save()
Although i haven't specified any value for password, it is overwritten after u.save() is called. How should i force peewee to only update last_login field?
Replace u.save() with:
u.save(only=[User.last_login])
As the API's documentation says:
only (list) – A list of fields to persist – when supplied, only the given fields will be persisted.
So you should specify a list of fields you want to be changed.
You can use the only argument when calling save(). http://docs.peewee-orm.com/en/latest/peewee/api.html#Model.save
When a user login to the system i want to update last_login. I've use following lines of code:
If you want to do this, you should do an atomic update, however:
User.update({User.last_login: datetime.datetime.now()}).where(User.username == 'whatever').execute()
The following code will demonstrate how to create, get and update a record in the database:
now = datetime.datetime.now()
# create a user
u = User.create(username="user1", password="bla", last_login=now)
# now `u` has your user, you can do: print u.username, u.password, u.last_login
# get an existing user from the db
u = User.get(User.username == "user1")
print u.username, u.password, u.last_login
sleep(1)
now = datetime.datetime.now()
# update an existing user
u = User.update(password="blabla", last_login=now).where(User.username == "user1")
u.execute()
If you want to save only modified fields, you may use the method below:
class User(Model):
username = CharField(unique=True)
password = CharField()
last_login = DateTimeField(default=datetime.datetime.now())
class Meta:
database = MySQLDatabase('mydb', user='root', charset='123456')
# This method saves only modefied fields
only_save_dirty = True
u=User(username="user1", last_login=datetime.datetime.now())
u.save()

Get the ID in a child entity of NDB GAE Datastore

I'm going in circles on getting the id of NDB Datastore.
I have setup the webapp2.RequestHandler to catch the email and get the ID. Basically my goal is to delete an entity, but if I pass the email address to get the ID of the entity, I'm stump, because it gives me results I was just getting. I used ID instead of key_name.
I tried finding the ID by querying via email, but it seems like using query does not have a method attribute to find the id.
def get(self,email):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
contacts = Contact.query(Contact.email==email,ancestor=user_key)
self.response.write(contacts.id) # there is no attribute such as Contact.id
I tried to find the ID by getting the key, but when I displayed the key, it showed me whatever value I have in the email variable
def get(self,email):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
contact_key = ndb.Key('Contact',email,parent=user_key)
self.response.write(contact_key.id())
Real Question: So, given that I do not have the ID, how do I find the correct ID inside an entity if I saved my entities via id and not key_name?
Here are the mixture of codes that I'm trying out.
def get(self,email):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
contact_key = ndb.Key('Contact',email,parent=user_key)
contacts = Contact.query(Contact.email==email,ancestor=user_key)
contact = contacts.get()
contact_key.delete()
# self.response.write(contact.name) # this works
self.response.write(contact_key.id()) # this does not work because I do not have the entity id, and I'd like to get it blindfolded. Is there a way?
Here is my Model for Contact.
class Contact(ndb.Model):
name = ndb.StringProperty()
phone = ndb.StringProperty()
email = ndb.StringProperty()
dateCreated = ndb.DateTimeProperty(auto_now_add=True)
dateUpdated = ndb.DateTimeProperty(auto_now=True)
The docs state:
The identifier may be either a key "name" string assigned by the application or an integer numeric ID generated automatically by the Datastore.
Since you are defining the name property on your Contact class, this is used as the identifier. (You don't want that because in real world different users can have same names)
So if you want NDB to generate numeric IDs for your entities, rename the name property to something else, e.g. username.
Update: let's go step by step:
Problem with the first example is that you are trying to get id on the Query. Query class has no id property defined on it. You should call get() on it:
# get() or fetch() should be called on query to return some data
contacts = Contact.query(Contact.email==email,ancestor=user_key).get()
self.response.write(contacts.id) # there is no attribute such as Contact.id
Problem with the second piece of code is that you are just initialising a Key and providing email as id - the second param of constructor is the id and you are providing email as value. Hence you are getting the email out. Also, there is no database operation here.
Note: the identifiers, which are id, key, urlsafe, or value (for the query) should be passed from the HTTP Request by webapp2.RequestHandler from a parsed url or HTTP POST, GET, PUT, or DELETE.
If you do not have any identifiers or values passed from an HTTP request, it could be difficult to access the specific entity (or the record). So, it is important to take note to pass a form of identifier or value to access the specific entity (or the record in database terms).
So, you can do the following to get the id:
Access by value:
def get(self,email):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
contacts = Contact.query(Contact.email==email,ancestor=user_key)
contact = contacts.get()
id = contact.key.id() # this access the entity id directly because you have the data.
self.response.write(id)
Access by urlsafe:
def get(self,urlString):
user = users.get_current_user()
if user:
contact_key = ndb.Key(urlsafe=urlString) #urlString refers to the key of contact
contact = contact_key.get()
id = contact.key.id() # this access the entity id directly because you have the data.
self.response.write(id)
Access by HTTP POST Request:
def post(self):
user = users.get_current_user()
if user:
user_key = ndb.Key('UserPrefs',user.email())
email = self.request.get('email')
contacts = Contact.query(Contact.email==email,ancestor=user_key)
contact = contacts.get()
id = contact.key.id() # this access the entity id directly because you have the data.
self.response.write(id)

How Can I Automatically Populate SQLAlchemy Database Fields? (Flask-SQLAlchemy)

I've got a simple User model, defined like so:
# models.py
from datetime import datetime
from myapp import db
class User(db.Model):
id = db.Column(db.Integer(), primary_key=True)
email = db.Column(db.String(100), unique=True)
password = db.Column(db.String(100))
date_updated = db.Column(db.DateTime())
def __init__(self, email, password, date_updated=None):
self.email = email
self.password = password
self.date_updated = datetime.utcnow()
When I create a new User object, my date_updated field gets set to the current time. What I'd like to do is make it so that whenever I save changes to my User object my date_updated field is set to the current time automatically.
I've scoured the documentation, but for the life of me I can't seem to find any references to this. I'm very new to SQLAlchemy, so I really have no prior experience to draw from.
Would love some feedback, thank you.
Just add server_default or default argument to the column fields:
created_on = db.Column(db.DateTime, server_default=db.func.now())
updated_on = db.Column(db.DateTime, server_default=db.func.now(), server_onupdate=db.func.now())
I prefer the {created,updated}_on column names. ;)
SQLAlchemy docs about column insert/update defaults.
[Edit]: Updated code to use server_default arguments in the code.
[Edit 2]: Replaced onupdate with server_onupdate arguments.
date_created = db.Column(db.DateTime, default=db.func.current_timestamp())
date_modified = db.Column(db.DateTime, default=db.func.current_timestamp(),
onupdate=db.func.current_timestamp())

GAE change field name/attribute

Is it possiible to change attribute name on db.Model kind? i have some field name created with dash (e.g. field-name) that resulting error.
class DataBulk(db.Model):
group_id = db.IntegerProperty()
group_name = db.StringProperty()
geo_pos = db.GeoPtProperty()
group-leader = db.StringProperty() <-----------error
imported = db.IntegerProperty(default=0)
Anyone can tell me what's wrong?
You must use valid Python names to define properties like that. Strictly speaking you can define the name that is stored in datastore, passing an argument "name" to the property:
class DataBulk(db.Model):
group_id = db.IntegerProperty()
group_leader = db.StringProperty(name='group-leader')

Resources