django-remember me-'long' object has no attribute 'set_expiry' - django

I am making my first app in django . I am writing a function for remember me , I am not using login(request,user) neither authentication thing . If user select remember me check box , I am setting cookie expire time after a week . But the problem is , in every sample implementation of remember in django , I saw this request.session.set_expiry() function . My doubt is , If I use this function it will set the expiry time for every member of request.session(for example request.session[1],request.session[2] where these two are session variables for two different users ) I want to set_expiry only for the current logged in user if he hits the remember me check box. So I am doing request.session[userid].set_expiry() instead off request.session.set_expiry() , but it is throwing this error --- 'long' object has no attribute 'set_expiry'
Here is my function in views.py
username=request.POST['Username']
password=request.POST['Password']
m=mytable.objects.get(Username=username)
if m.Password==password:
request.session[m.id]=m.id
if request.POST.get('remember_me', None):
request.session[m.id].set_expiry(604800)
else:
request.session[m.id].set_expiry(0)
else:
#do something
Please guide me through this

You should do request.session.set_expiry() instead of on member of request.session[m.id].
The request.session identified only current session along with user for the current request not all users logged in.
Hope you are gone through django sessions doc.

Related

How do I check if a user has entered the URL from another website in Django?

I want an effect to be applied when a user is entering my website. So therefore I want to check for when a user is coming from outside my website so the effect isnt getting applied when the user is surfing through different urls inside the website, but only when the user is coming from outside my website
You can't really check for where a user has come from specifically. You can check if the user has just arrived on your site by setting a session variable when they load one of your pages. You can check for it before you set it, and if they don't have it, then they have just arrived and you can apply your effect. There's some good examples of how sessions work here: https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Sessions
There's a couple of ways to handle this. If you are using function based views, you can just create a separate util function and include it at the top of every page, eg,
utils.py
def first_visit(request):
"""returns the answer to the question 'first visit for session?'
make sure SESSION_EXPIRE_AT_BROWSER_CLOSE set to False in settings for persistance"""
if request.session['first_visit']:
#this is not the first session because the session variable is used.
return False
else:
#This is the first visit
...#do something
#set the session variable so you only do the above once
request.session[first_visit'] = True
return True
views.py
from utils.py import first_visit
def show_page(request):
first_visit = first_visit(request)
This approach gives you some control. For example, you may not want to run it on pages that require login, because you will already have run it on the login page.
Otherwise, the best approach depends on what will happen on the first visit. If you want just to update a template (eg, perhaps to show a message or run a script on th epage) you can use a context processor which gives you extra context for your templates. If you want to interrupt the request, perhaps to redirect it to a separate page, you can create a simple piece of middleware.
docs for middleware
docs for context processors
You may also be able to handle this entirely by javascript. This uses localStorage to store whether or not this is the user's first visit to the site and displays the loading area for 5 seconds if there is nothing in localStorage. You can include this in your base template so it runs on every page.
function showMain() {
document.getElementByID("loading").style.display = "none";
document.getElementByID("main").style.display = "block";
}
const secondVisit = localStorage.getItem("secondVisit");
if (!secondVisit) {
//show loading screen
document.getElementByID("loading").style.display = "block";
document.getElementByID("main").style.display = "none";
setTimeout(5000, showMain)
localStorage.setItem("secondVisit", "true" );
} else {
showMain()
}

Django function execution

In views, I have a function defined which is executed when the user submits the form online. After the form submission there are some database transactions that I perform and then based on the existing data in the database API's are triggered:
triggerapi():
execute API to send Email to the user and the administrator about
the submitted form
def databasetransactions():
check the data in the submitted form with the data in DB
if the last data submitted by the user is before 10 mins or more:
triggerapi()
def formsubmitted(request):
save the user input in variables
Databasetransactions()
save the data from the submitted form in the DB
In the above case, the user clicks on submit button 2 times in less than 5 milliseond duration. So 2 parallel data starts to process and both trigger Email which is not the desired behavior.
Is there a way to avoid this ? So that for a user session, the application should only accept the data once all the older data processing is completed ?
Since we are talking in pseudo-code, one way could be to use a singleton pattern for triggerapi() and return Not Allowed in case it is already istantiated.
There are multiple ways to solve this issue.
One of them would be to create a new session variable
request.session['activetransaction'] = True
This would however require you to pass request, unless it is already passed and we got a changed code portion. You can also add an instance/ class flag for it in the same way and check with it.
Another way, which might work if you need those submissions handled after the previous one, you can always add a while request.session['activetransaction']: and do the handling afterwards.
def formsubmitted(request):
if 'activetransaction' not in request.session or not request.session['activetransaction']:
request.session['activetransaction'] = True
# save the user input in variables
Databasetransactions()
# save the data from the submitted form in the DB
request.session['activetransaction'] = False
...

django-channels: differentiate between different `AnonymousUser`s

Unfortunately I'm using django-channels channels 1.1.8, as I missed all the
updates to channels 2.0. Upgrading now is unrealistic as we've just
launched and this will take some time to figure out correctly.
Here's my problem:
I'm using the *message.user.id *to differentiate between authenticated
users that I need to send messages to. However, there are cases where I'll
need to send messages to un-authenticated users as well - and that message
depends on an external API call. I have done this in ws_connect():
#channel_session_user_from_http
def ws_connect(message):
# create group for user
if str(message.user) == "AnonymousUser":
user_group = "AnonymousUser" + str(uuid.uuid4())
else:
user_group = str(message.user.id)
print(f"user group is {user_group}")
Group(user_group).add(message.reply_channel)
Group(user_group).send({"accept": True})
message.channel_session['get_user'] = user_group
This is only the first part of the issue, basically I'm appending a random
string to each AnonymousUser instance. But I can't find a way to access
this string from the request object in a view, in order to determine who
I am sending the message to.
Is this even achievable? Right now I'm not able to access anything set in
the ws_connect in my view.
EDIT: Following kagronick's advice, I tried this:
#channel_session_user_from_http
def ws_connect(message):
# create group for user
if str(message.user) == "AnonymousUser":
user_group = "AnonymousUser" + str(uuid.uuid4())
else:
user_group = str(message.user.id)
Group(user_group).add(message.reply_channel)
Group(user_group).send({"accept": True})
message.channel_session['get_user'] = user_group
message.http_session['get_user'] = user_group
print(message.http_session['get_user'])
message.http_session.save()
However, http_session is None when user is AnonymousUser. Other decorators didn't help.
Yes you can save to the session and access it in the view. But you need to use the http_session and not the channel session. Use the #http_session decorator or #channel_and_http_session. You may need to call message.http_session.save() (I don't remember, I'm on Channels 2 now.). But after that you will be able to see the user's group in the view.
Also, using a group for this is kind of overkill. If the group will only ever have 1 user, put the reply_channel in the session and do something like Channel(request.session['reply_channel']).send() in the view. That way it doesn't need to look up the one user that is in the group and can send directly to the user.
If this solves your problem please mark it as accepted.
EDIT: unfortunately this only works locally but not in production. when AnonymousUser, message.http_sesssion doesn't exist.
user kagronick got me on the right track, where he pointed that message has an http_session attribute. However, it seems http_session is always None in ws_connect when user is AnonymousUser, which defeats our purpose.
I've solved it by checking if the user is Anonymous in the view, and if he is, which means he doesn't have a session (or at least channels can't see it), initialize one, and assign the key get_user the value "AnonymousUser" + str(uuid.uuid4()) (this way previously done in the consumer).
After I did this, every time ws_connect is called message will have an http_session attribute: Either the user ID when one is logged in, or AnonymousUser-uuid.uuid4().

Django "request" object

I just started learning Django and Python a few weeks ago and have been tasked with a project to manage form processing using a Django/Python/MySQL combination. My background is in C++, so if there are any C++ analogies in Python/Django syntax please feel free to reference them.
So far I understand what the HTTPRequest objects do, but can't understand this snippet of code:
#login_required(login_url="/some_directory/")
def xyz(request):
item1 = request.GET['item1']
user = request.user
page = Page.objects.get(title = item1)
item1info = {}
perm_all = get_perms(user,page)
item1info["industry"] = page.industry.split(',')
For the first line what does "#" do? Is "#login_required" a Django command or was was it defined by the coder already?
I know "def xyz(request)" defines a function, but is the parameter "request" something that's been pre-defined in another file (urls.py)?
What does request.GET['item1'] do? Is it retrieving the value of the element "item1" from the query string?
"#" is a Decorator. Login required is a decorator provided by Django that requires the current user (in request.user) to be logged in to visit this view.
The "request" parameter is passed to the View function when its called, by Django itself. Any valid view function must receive the request as a paramete
Request.GET is a python dictionary that contains all the parameters passed in the request by GET method (as part of the URL querystring).

Set a "global pre-request variable" in Django in Middleware

I'm trying to combine Google App Engine with RPX Now user authentication and a per-user limited access pattern.
The per user access-limiting pattern relies upon GAE's global User.get_current_user(), like-so:
from google.appengine.api import users
class CurrentUserProperty(db.UserProperty):
def checkCurrentUser(self, value):
if value != users.get_current_user():
raise db.BadValueError(
'Property %s must be the current user' % self.name)
return value
def __init__(self, verbose_name=None, name=None):
super(CurrentUserProperty, self).__init__(
verbose_name, name, required=True,
validator=self.checkCurrentUser)
However, with GAE Utilities' sessions storing RPX's user identifier, there is no global User.
The most obvious solution to me is to create some global User variable (somehow localized to the current request/thread) in the middleware. However, I wouldn't do this unless I was confident there were no race conditions.
Is there any way to get the identity of the current user (as stored in the request session variable) to the CurrentUserProperty when CurrentUserProperty is constructed?
Thank you for reading.
EDIT:
Reading GAE's google/appengine/tools/dev_appserver.py:578 which does a:
579 env['USER_ID'] = user_id
and google/appengine/api/users.py:92ff which reads:
92 if _user_id is None and 'USER_ID' in os.environ:
93 _user_id = os.environ['USER_ID']
seems to suggest that you can safely set the environment in a single Google App Engine request (but I may be wrong!).
Presumably, then, I can set an environment variable in middleware. It smells of trouble, so I'd like to know if anyone else has (similarly) tackled this.
App Engine instances (and indeed, CGI in general) are guaranteed to be single-threaded, so setting an environment variable per request is indeed safe - in fact, all the information about the current request is passed in through the current environment! Just make sure that you _un_set the environment variable if the user is not logged in, so you can't have an unauthenticated request get the authentication of the previous request to hit the same instance.