I have 2 Handlers. One is called MainHandler, which renders a small form to sign up a user(create an account). Upon submitting email and pwd, MainHandler checks the account doesn't exist already, validates the fields, and then creates a new User entity. Then redirects to HomeHandler (/home) and sends the user email as a URL query parameter, i.e.
"http://localhost:8000/home?email=jack#smith.com"
My question is, is that the best way to do it?? At HomeHandler there's another form that allows the user to enter an address that will be a child of the user. Using the email, I run a query to find the user. If I don't send over the user email how will HomeHandler know which user is entering the address? If I have other handlers that will receive other data to be stored and associated with the user, do I have to keep sending the user email every time? Seems like there should be a better way to do it, but I can't figure it out.
class User(db.Model):
email = db.EmailProperty()
password = db.StringProperty()
class Address(db.Model):
line1 = db.StringProperty()
line2 = db.StringProperty()
class MainHandler(webapp2.RequestHandler):
def get(self):
renders a template with a form requesting email and pwd
def post(self):
Validates form and checks account doesn't already exist
if (user doesn't already exist and both email and pwd valid):
newuser = User(email=email, password=password);
newuser.put();
self.redirect("/home?email=%s"%email)
class HomeHandler(webapp2.RequestHandler):
def get(self):
Renders another form requesting a physical address (2 lines)
def post(self):
email=self.request.get("email")
addressLine1 = self.request.get("address1")
addressLine2 = self.request.get("address2")
q = db.Query(User).filter('email =', email)#Construct query
userMatchResults = q.fetch(limit=1)#Run query
homeAddress = Address(parent=userMatchResults[0])
homeAddress.line1 = addressLine1
homeAddress.line2 = addressLine2
homeAddress.put()
app = webapp2.WSGIApplication([('/', MainHandler), ('/home', HomeHandler)], debug=True)
You do not have to redirect. You can send the second form in the post of Mainhandler.
And you can combine both handlers, If the post of the main handler can detect if the post request origin is the first or the second form. An easy way to do this, is adding a hidden input field to both forms, with the name of the form. This field will be part of the post data.
But there are many other ways to preserve the state between requests.
Related
I have a blog create view, where admin or staff user can only create blog, it is restricted from normal user and it is working fine.
Goal: Now I want to display the create blog button on the website to admin or staff user only if they logged in from their account.
I have user detail view that is calling on the very beginning of site loading, How can I check if the user is admin or staff user or normal user in response?
I am using React in frontend with redux.
What I have done so far
path('user/', UserDetailsView.as_view(), name='rest_user_details'),
class UserDetailsView(RetrieveUpdateAPIView):
serializer_class = UserDetailsSerializer
permission_classes = (IsAuthenticated,)
def get_object(self):
return self.request.user
def get_queryset(self):
return get_user_model().objects.none()
One possible solution is to overwrite your UserDetailsSerializer and added a field like is_admin_user.
We are going to use serializerMethodField from Django-Restframework serializers.
class UserDetailsSerializer(serializers.ModelSerializer):
is_admin_user = serializers.SerializerMethodField()
class Meta:
model = User
fields = ('is_admin_user',) // And all other necessary fields
def get_is_admin_user(self, obj):
return obj.is_staff # this will return true for self.is_staff user
Our main goal is to pass some information to frontend about user role, so that from this information we can decide whether to show create blog button or not.
I'm wondering what the best approach is to store user authentication data in a neo4j database with django using the inbuilt auth system.
Has anybody got any experience of doing so?
I'm imagining that it has something to do with subclassing the AbstractBaseUser and BaseUserManager but for the life of me I can't figure it out.
Would very much appreciate a code snippet if anybody has achieved this before.
Many Thanks
If you want to extend the Django User model, first check this article. It shows different ways of extending the User model. In my last workaround I needed all the information in Neo4j so I adapt my model to have the fields of the user in my model (It was a model of Student). Whenever a new student register to the app, I have a signal to react after the save (post_save) and it stores the password and the username. You can explore the Django signals here
For the model I have:
class StudentProfile(DjangoNode):
first_name = StringProperty(max_length=30)
last_name = StringProperty(max_length=150)
email = EmailProperty()
birth = DateProperty()
username = StringProperty(max_length=150, unique=True)
password = ''
For the signal:
#receiver(post_save, sender=StudentProfile, dispatch_uid='create_user_student')
def create_user_student(sender, instance, created, **kwargs):
if created:
user = User.objects.create_user(instance.username)
user.set_password(instance.password)
user.save()
#receiver(post_delete, sender=StudentProfile, dispatch_uid='delete_user_student')
def delete_user_student(sender, instance, **kwargs):
User.objects.filter(username=instance.username).delete()
Besides the main view of the StudentProfile, I have a view that uses the built-in Django authentication system:
from django.contrib.auth import authenticate, login as do_login, logout as do_logout
...
#api_view(["POST"])
def login(request):
username = request.data.get('username')
password = request.data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
do_login(request, user)
return Response({'login': 'ok'}, status=status.HTTP_200_OK)
return Response({'login': 'Error on credentials'}, status=status.HTTP_403_FORBIDDEN)
I have just started working on Django, angularjs , The issue currently i am facing is I have created a model in django as following
**class Car_Booking(models.Model):
owner = models.ForeignKey('auth.User', related_name='booking_user')
car_id=models.IntegerField(max_length=4,default=1)
extra_field1=models.CharField(max_length=100,null=True)
extra_field2=models.CharField(max_length=50,null=True)
extra_field3=models.CharField(max_length=50,null=True)**
The Serializer is as following
**class CarBookingSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
class Meta:
model = Car_Booking
fields = ('car_id','owner','extra_field1','extra_field2','extra_field3')**
And view is as following
**class CarBookingViewSet(viewsets.ModelViewSet):
"""
This viewset automatically provides `list`, `create`, `retrieve`,
`update` and `destroy` actions.
Additionally we also provide an extra `highlight` action.
"""
queryset = Car_Booking.objects.all()
serializer_class = CarBookingSerializer
permission_classes = (permissions.AllowAny,
def perform_create(self, serializer):
serializer.save(owner=self.request.user)**
Now i developed a front end on Angularjs, the templelates i built were on the same server say localhost:8000 so when i call the view to insert the data by passing car_id, extra_field1, extra_field2 and extra_field 3 it gets saved successfully because i already get logged in and saved the user information into the cookies so i guess the Owner field is resolved automatically. Now when i call the same view from the IONIC framework on server localhost:5000(port is differnt) it give me the error, "Owner must be a user instance". I have searched a lot but can not find how to send the user authentication information, or save it accross the domains. Secondly i have tried to pass the owner_id but when i write the owner_id into the serializer it says "Owner_id is not a valid modlebase" but while calling throught the command prompt i can set the owner_id, Any Help on the following questions
***1. How can i send the username and password along the Post URL
How can i set the owner_id instead of OWNER object instance.***
Regards
All,
I am in the process of learning Google App Engine / Webapp2 and i'm having trouble saving an object to the datastore, redirecting to another page/handler, then fetching that object from the datastore. Forgive me if there is an easy answer to this question. The following is a description of the code I have.
I have a base handler:
class BaseHandler(webapp2.RequestHandler):
def set_secure_cookie(self, name, val):
cookie_val = make_secure_val(val)
self.response.headers.add_header(
'Set-Cookie',
'%s=%s; Path=/' % (name, cookie_val))
def get_secure_cookie(self, name):
cookie_val = self.request.cookies.get(name)
return cookie_val and check_secure_val(cookie_val)
def login(self, user):
self.set_secure_cookie('user', str(user.name))
# Called before every request and stores user object
def initialize(self, *a, **kw):
webapp2.RequestHandler.initialize(self, *a, **kw)
username = self.get_secure_cookie('user')
self.user = username and User.by_name(str(username))
I have a Signup page which inherits from BaseHandler:
class Signup(BaseHandler):
def get(self):
# Get the page
def post(self):
has_error = False
# Extract and validate the input
if has_error:
#Re-render the form
else:
new_user = User.register(self.username, self.password, self.email)
new_user.put()
self.login(new_user)
self.redirect("/blog/welcome")
If the user is a new user, the User db.Model object is created, the user is stored to the datastore, a user cookie is set and we are redirected to the Welcome handler:
class Welcome(BaseHandler):
def get(self):
if self.user:
self.render('welcome.html', username = self.user.name)
else:
self.redirect('/blog/signup')
The intent here is that upon redirect, BaseHandler.initialize() would get called and would set self.user of the new user I just created.
Here is what I know:
- When signing up a new user, I am redirected back to the signup page.
- If I then manually navigate to /blog/welcome, the page loads correctly with the new username populated.
If I add the following logging statements into Welcome.get():
username = self.get_secure_cookie('user')
logging.info("Cookie %r obtained inside of Welcome.get().", username)
logging.info("Found user %r", User.by_name(str(username)))
The cookie is obtained for the new username but no User object is found. Again, if I navigate directly to /blog/welcome, the logs report that the cookie is obtained and the User object is found for the new user.
The User object looks like so:
def users_key(group = 'default'):
return db.Key.from_path('users', group)
class User(db.Model):
name = db.StringProperty(required = True)
password = db.StringProperty(required = True)
email = db.StringProperty()
#classmethod
def by_name(cls, name):
u = User.all().filter('name =', name).get()
return u
#classmethod
def register(cls, name, password, email = None):
return User(parent = users_key(),
name = name,
password = password,
email = email)
Is there something about the datastore that is causing this first query to get the new user to return nothing? How should I proceed in debugging this? Is there additional reading I should do? (I have tried to provide all necessary code snippets but I can provide additional code if required.)
Just guessing, but I suspect self.username, self.password and self.email in your RequestHandler are not set to anything. I'm assuming you're getting those paramters from the request POST data, but that's not happening in the code shown.
The other potential problem is that your query is eventually consistent, and may not reflect recent changes (ie new User entity). It would be much better if you fetch the user by it's key or id with a get() call instead of a query via filter().
My app requires users to login using their google account.
I have this set in my App.yamp file:
url: /user/.*
script: user.py
login: required
Now when any user tries to access files under /user/secret.py he will need to authenticate via google, which will redirect the user back to /user/secret.py after successful authentication. Now the problem I am facing is when the user is redirected back to the app, I cannot be sure if this is the first time the user has logged in or is it a regular user to my site who has come back again from just the user object which google passes using users.get_current_user() .
I thus need to maintain state in the datastore to check if the user already exists or not everytime. If he does not exist i need to create a new entry with other application specific settings.
My question is: Is there some easier way to handle this? without having to query the datastore to figure if this is a first time user or a regular one?
No, Google doesn't keep track of if a user has logged in to your app before. Since you presumably need to store some sort of state against the user, the simplest way is to try and retrieve the user's record from the datastore. If they don't have one, you can send them to the registration screen to gather this information. You can use memcache to cache a user's information and avoid extra datastore round-trips.
I tend to use my own user and session manangement
For my web handlers I will attach a decorator called session and one called authorize. The session decorator will attach a session to every request, and the authorize decorator will make sure that the user is authorised
(A word of caution, the authorize decorator is specific to how I develop my applications - the username being the first parameter in most requests)
So for example a web handler may look like:
class UserProfile(webapp.RequestHandler):
#session
#authorize
def get(self, user):
# Do some funky stuff
# The session is attached to the self object.
someObjectAttachedToSession = self.SessionObj.SomeStuff
self.response.out.write("hello %s" % user)
In the above code, the session decorator attaches some session stuff that I need based on the cookies that are present on the request. The authorize header will make sure that the user can only access the page if the session is the correct one.
The decorators code are below:
import functools
from model import Session
import logging
def authorize(redirectTo = "/"):
def factory(method):
'Ensures that when an auth cookie is presented to the request that is is valid'
#functools.wraps(method)
def wrapper(self, *args, **kwargs):
#Get the session parameters
auth_id = self.request.cookies.get('auth_id', '')
session_id = self.request.cookies.get('session_id', '')
#Check the db for the session
session = Session.GetSession(session_id, auth_id)
if session is None:
self.redirect(redirectTo)
return
else:
if session.settings is None:
self.redirect(redirectTo)
return
username = session.settings.key().name()
if len(args) > 0:
if username != args[0]:
# The user is allowed to view this page.
self.redirect(redirectTo)
return
result = method(self, *args, **kwargs)
return result
return wrapper
return factory
def session(method):
'Ensures that the sessions object (if it exists) is attached to the request.'
#functools.wraps(method)
def wrapper(self, *args, **kwargs):
#Get the session parameters
auth_id = self.request.cookies.get('auth_id', '')
session_id = self.request.cookies.get('session_id', '')
#Check the db for the session
session = Session.GetSession(session_id, auth_id)
if session is None:
session = Session()
session.session_id = Session.MakeId()
session.auth_token = Session.MakeId()
session.put()
# Attach the session to the method
self.SessionObj = session
#Call the handler.
result = method(self, *args, **kwargs)
self.response.headers.add_header('Set-Cookie', 'auth_id=%s; path=/; HttpOnly' % str(session.auth_token))
self.response.headers.add_header('Set-Cookie', 'session_id=%s; path=/; HttpOnly' % str(session.session_id))
return result
return wrapper
def redirect(method, redirect = "/user/"):
'When a known user is logged in redirect them to their home page'
#functools.wraps(method)
def wrapper(self, *args, **kwargs):
try:
if self.SessionObj is not None:
if self.SessionObj.settings is not None:
# Check that the session is correct
username = self.SessionObj.settings.key().name()
self.redirect(redirect + username)
return
except:
pass
return method(self, *args, **kwargs)
return wrapper
Can you not just set a Cookie the first time the user logs in and check for this? If they're a new user it won't be there and but if they're an old user it will be. It's not 100% accurate since some users might clear their cookies but it might do depending on what it is you want to achieve.
If you're using Django in your application managing Cookies is pretty straightforward.
I agree that managing your own authenticated users is the best way to approach this problem. Depending on your application scope obviously but at the very least an AuthUser(Model) class that contains the UserProperty for the users that have logged in with your account.
...
class AuthUser(db.Model):
user = UserProperty(required=True)
...
Then when a user logs in just
...
user = users.get_current_user()
user_exists = AuthUser.gql('where user = :1', user) # or easy check db.GqlQuery("select __key__ from AuthUser where user = :1", user)
if user_exists:
# do user has been before stuff
else:
# do first time user stuff
...
Alternately a super easy way to do this is have a Model for your site that has a ListProperty(users.User) and then you can easily check the list to see if the user has been into your app before.
...
class SiteStuff(db.Model):
auth_users = ListProperty(users.User)
...
and when they log in: check if they are in the list; if not, you add them to the list, put() it and do whatever you need to do for first time users. If you find them in there then do the other stuff.