How can I create a django url specific to a user? - django

I am interested in making my urls customised for each user, something like
username.mysite.com/home but I am not sure how to do this with django.
I am also curious if this might work in development (so as to have username.localhost:8000/home) or not.
Thank you.

There is another way as well. What you can do is have Middleware that gets the url, parses the subdomain and then renders a user profile page.
This is assuming you are using a custom profile page and not the default profile page.
#in yourapp.middleware
from django.contrib.auth.models import User
import logging
import yourapp.views as yourappviews
logger = logging.getLogger(__name__)
class AccountMiddleware(object):
def process_request(self, request):
path = request.META['PATH_INFO']
domain = request.META['HTTP_HOST']
pieces = domain.split('.')
username = pieces[0]
try:
user = User.objects.get(username=username)
if path in ["/home","/home/"]:
return yourappviews.user_profile(request, user.id)
#In yourapp.views.py
def user_profile(request,id):
user = User.objects.get(id=id)
return render(request, "user_profile.html", {"user": user})
#In settings.py
MIDDLEWARE_CLASSES = (
#... other imports here
'yourapp.middleware.AccountMiddleware'
)

Related

django-The page isn’t redirecting properly

I have a middleware that check user profile. If auth user doesn't have a profile, then redirect to user profile. My browser displays the error The page isn’t redirecting properly.
class Check(MiddlewareMixin):
def process_request(self, request):
if request.user.is_authenticated():
user = request.user
try:
profile = Profile.objects.get(user_id = user)
if profile:
pass
except ObjectDoesNotExist:
return HttpResponseRedirect('/accounts/profile/')
I'm use django-allauth.
It sounds like you might have an infinite redirect loop. Check the request path, and do not redirect if the user is trying to access /accounts/profile/.
class Check(MiddlewareMixin):
def process_request(self, request):
if request.user.is_authenticated() and request.path != '/accounts/profile/':
...
Make sure you are using The Right view, in my case i was using:
view
class Blog_View(View):
model = Blog
template_name = 'blog.html'
instead of
Listview
class Blog_View(ListView):
model = Blog
template_name = 'blog.html'
Check your secret key in setting.py I solved this problem with to remove get_random_secret_key().
Before
SECRET_KEY = env.str("SECRET_KEY", get_random_secret_key())
After
SECRET_KEY = env.str("SECRET_KEY")
Now Im using unique SECRET_KEY and it works fine in prod service.

How to secure Flask-Admin if my only user is going to be the Admin?

I have seen plenty of solutions online, however all of them addressed more complex apps which allow external users to create accounts. In my case the only user will be the admin. How do I secure the /admin routes created by Flask-Admin in an efficient way?
You can use Flask-Login for that. I usually add a route to the AdminIndexView class that handles the login if the user isn't logged in, yet. Otherwise the default admin page will be shown.
from flask import Flask
from flask_login import LoginManager
from flask_admin import Admin
app = Flask(__name__)
login_manager = LoginManager(app)
login_manager.session_protection = 'strong'
login_manager.login_view = 'admin.login'
admin = Admin(app, index_view=MyIndexView())
The definition of MyAdminView can look like this:
from flask_admin import AdminIndexView, expose, helpers
class FlaskyAdminIndexView(AdminIndexView):
#expose('/')
def index(self):
if not login.current_user.is_authenticated:
return redirect(url_for('.login'))
return super(MyAdminIndexView, self).index()
#expose('/login', methods=['GET', 'POST'])
def login(self):
form = LoginForm(request.form)
if helpers.validate_form_on_submit(form):
user = form.get_user()
if user is not None and user.verify_password(form.password.data):
login.login_user(user)
else:
flash('Invalid username or password.')
if login.current_user.is_authenticated:
return redirect(url_for('.index'))
self._template_args['form'] = form
return super(MyAdminIndexView, self).index()
#expose('/logout')
#login_required
def logout(self):
login.logout_user()
return redirect(url_for('.login'))
This integrates Flask-Login unobtrusively in the Flask-Admin interface. You will still need to implement the user and password verification like described in the Flask-Login documentation.
EDIT
To prevent unauthorized access to your admin routes create a ModelView class for each view and add a function is_accessible() with the following code:
def is_accessible(self):
if (not login.current_user.is_active or not
login.current_user.is_authenticated):
return False
return True

Django - how to implement an example.com/username url system

I am trying to implement on my website a simple and friendly address system.
What i'm thinking about is when the user logged in, his username will be displayed in the address bar.
www.example.com/username1 (for home page profile)
www.example.com/username1/about/
www.example.com/username1/gallery/
www.example.com/username2 (for home page profile)
www.example.com/username2/about/
www.example.com/username2/gallery/
And additionally if anyone enter the address www.example.com/username1, will be shown the profile of user1.
I already implemented a register/Login system using Django-Allauth
mySite/urls.py
url(r'^accounts/', include('allauth.urls')),
home/urls.py
url(r'^$', views.index),
home/views.py
def index(request):
return render_to_response('home/index.html', context_instance=RequestContext(request))
I tried to follow some examples like Facing problem with user profile url scheme like example.com/username in django
But i dont have this thing working yet. I dont understand what to do :(
Please, give some advise.
Add the following url as the last item of the mySite/urls.py:
urlpatterns = patterns('',
...
url(r'^(?P<username>\w+)/', include('userapp.urls')),
)
Then the username parameter will be passed to the views of your userapp:
userapp/urls.py:
from userapp import views
urlpatterns = patterns('',
url(r'^$', views.profile, name='user_profile'),
url(r'^about/$', views.about, name='user_about'),
url(r'^gallery/$', views.gallery, name='user_gallery'),
)
userapp/views.py:
def profile(request, username):
user = get_object_or_404(User, username=username)
return render(request, 'userapp/profile.html', {'profile_user': user})
def about(request, username):
...
def gallery(request, username):
...
It's almost perfect, but i have a bug. Let me explain. When i login (my login system is: django-allauth) on the http://127.0.0.1:8000/accounts/login/ i return to http://127.0.0.1:8000 with an error 404.
I am not getting the http://127.0.0.1:8000/username/ with the template, when the login botton is clicked.
The instalation of django-allauth require adding to the settings.py
LOGIN_REDIRECT_URL = '/'
How can i redirect to http://127.0.0.1:8000/username/ and show the correct template?
1. Regarding
How can i redirect to
Based on the answer from https://stackoverflow.com/a/20143515/4992248
# settings.py:
ACCOUNT_ADAPTER = 'project.your_app.allauth.AccountAdapter'
# project/your_app/allauth.py:
from allauth.account.adapter import DefaultAccountAdapter
class AccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
return 'request.user.username' # probably also needs to add slash(s)
Would be better to use get_absolute_url, ie return 'request.user.get_absolute_url'. In this case you need to do:
# 1. Add `namespace` to `yoursite/urls.py`
urlpatterns = patterns('',
...
url(r'^(?P<username>\w+)/', include('userapp.urls', namespace='profiles_username')),
)
# 2. Add the code below to the Users class in models.py
def get_absolute_url(self):
# 'user_profile' is from the code shown by catavaran above
return reverse('profiles_username:user_profile', args=[self.username])
2. Regarding
show the correct template
catavaran wrote correct urls which leads to views.profile, so in view.py you need to write:
from django.shortcuts import render
from .models import UserProfile # import model, where username field exists
from .forms import UserProfileForm # import Users form
def profiles(request, username):
user = get_object_or_404(UserProfile, username=username)
return render(request, 'home/profiles.html', {'user_profile_form': user})
In template (i.e. profiles.html) you can show user's data via {{user_profile_form.as_p}}

Redirect User to another url with django-allauth log in signal

I am using Django-allauth for my login/signup related stuff, so when a user signs up(first time) into my site, I am redirecting him to /thanks/ page by defining below setting in settings.py file
LOGIN_REDIRECT_URL = '/thanks/'
But when the user tried to log in for the next time(if already registered) I should redirect him to '/dashboard/' URL
So tried to alter that with Django-allauth signals like below which is not working at all
#receiver(allauth.account.signals.user_logged_in)
def registered_user_login(sender, **kwargs):
instance = User.objects.get_by_natural_key(kwargs['user'])
print instance.last_login==instance.date_joined,"??????????????????????????????"
if not instance.last_login==instance.date_joined:
return HttpResponseRedirect(reverse('dashboard'))
So can anyone please let me know how to redirect a user to /dashboard/ for the normal login, am I doing anything wrong in the above signal code?
Edit
After some modification according to the below answer by pennersr, my AccountAdapter class looks like below
from allauth.account.adapter import DefaultAccountAdapter
# from django.contrib.auth.models import User
class AccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
if request.user.last_login == request.user.date_joined:
return '/registration/success/'
else:
return '/dashboard/'
But still, it is redirecting the user to /dashboard/, my logic in determining the first time user is wrong?
In general, you should not try to put such logic in a signal handler. What if there are multiple handlers that want to steer in different directions?
Instead, do this:
# settings.py:
ACCOUNT_ADAPTER = 'project.users.allauth.AccountAdapter'
# project/users/allauth.py:
class AccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
return '/some/url/'
The two datetimes last_login and date_joined will always be different, although it might only be a few milliseconds. This snippet works:
# settings.py:
ACCOUNT_ADAPTER = 'yourapp.adapter.AccountAdapter'
# yourapp/adapter.py:
from allauth.account.adapter import DefaultAccountAdapter
from django.conf import settings
from django.shortcuts import resolve_url
from datetime import datetime, timedelta
class AccountAdapter(DefaultAccountAdapter):
def get_login_redirect_url(self, request):
threshold = 90 #seconds
assert request.user.is_authenticated()
if (request.user.last_login - request.user.date_joined).seconds < threshold:
url = '/registration/success'
else:
url = settings.LOGIN_REDIRECT_URL
return resolve_url(url)
One important remark to pennersr answer: AVOID using files named allauth.py as it will confuse Django and lead to import errors.
the answer here is very simple, you do not need any signals or overriding the DefaultAccountAdapter
in settings.py just add a signup redirect_url
ACCOUNT_SIGNUP_REDIRECT_URL = "/thanks/"
LOGIN_REDIRECT_URL = "/dashboard/"
You can simply define those two other signals using user_logged_in signal as base. A good place to put it is on a signals.py inside a accounts app, in case you have one, or in you core app. Just remember to import signals.py in you __init__.py.
from django.dispatch import receiver, Signal
pre_user_first_login = Signal(providing_args=['request', 'user'])
post_user_first_login = Signal(providing_args=['request', 'user'])
#receiver(user_logged_in)
def handle_user_login(sender, user, request, **kwargs):
first_login = user.last_login is None
if first_login:
pre_user_first_login.send(sender, user=user, request=request)
print 'user_logged_in'
if first_login:
post_user_first_login.send(sender, user=user, request=request)
#receiver(pre_user_first_login)
def handle_pre_user_first_login(sender, user, request, **kwargs):
print 'pre_user_first_login'
#receiver(post_user_first_login)
def handle_post_user_first_login(sender, user, request, **kwargs):
print 'post_user_first_login'

mongoengine and django auth, login

I am trying to implement login functionality using mongoengine and django.
I have included 'mongoengine.django.mongo_auth' in INSTALLED_APPS
Following are my settings.py from mongoengine site.
MONGOENGINE_USER_DOCUMENT = 'mongoengine.django.auth.User'
AUTH_USER_MODEL = 'mongo_auth.MongoUser'
SESSION_ENGINE = 'mongoengine.django.sessions'
AUTHENTICATION_BACKENDS = (
'mongoengine.django.auth.MongoEngineBackend',
)
This is from models.py
class UserInfo(User,DynamicDocument):
address = EmbeddedDocumentField(Address)
dob = DateTimeField(required = True)
sex = StringField(max_length = 1, choices = SEX)
primary_number = LongField(required = True)
And following is from views.py
def LoginOrCreateUser(request):
formAuth = AuthenticationForm(data=(request.POST or None))
if(request.method=='POST'):
if(formAuth.is_valid()):
if(formAuth.clean_email()):
if(formAuth.clean_password()):
formAuth.save(True)
user=authenticate(username=formAuth.cleaned_data['username'],password = formAuth.cleaned_data['password1'])
login(request,user)
return HttpResponse('New User Success')
This code gives me error <obj_id "user"> is NOT JSON serializable.
The error is raised for login, so I guess here login API is provided by django but the user we are providing to it is the value got from authenticate which is mongoengine's provided api.
I looked into the auth.py of django and mongoengine. So, we don't have login API in mongoengine. And the authenticate of django returns the user instance, while authenticate of mongoengine returns a string i.e. username.
Any suggestions here or mistakes I am making in the implementation here.
André I just tried you're example but it gives me
NameError at /game/
global name 'jsonResponse' is not defined
If I import jsonResponse like
from django.http import HttpResponse,JsonResponse
then gives me
ImportError at /game/ cannot import name JsonResponse
I just only want to manage simple user auth with my mongoengine backend.
Thanks.
1st question, are you trying to customize the User object? Or you want to use default Django User model? I ask because you should set MONGOENGINE_USER_DOCUMENT and AUTH_USER_MODEL if you do want to make a custom model.
I will show you how I'm authenticating using mongoengine x Django:
On settings.py
connect('localhost')
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.dummy',
}
}
AUTHENTICATION_BACKENDS = (
'mongoengine.django.auth.MongoEngineBackend'
)
SESSION_ENGINE = 'mongoengine.django.sessions'
On views.py
from django.contrib.auth import authenticate, login, logout
from django.http import HttpResponse
def jsonResponse(responseDict):
return HttpResponse(simplejson.dumps(responseDict), mimetype='application/json')
def createSession(request):
if not request.is_ajax():
return jsonResponse({'error':True})
if not request.session.exists(request.session.session_key):
request.session.create()
data = extractDataFromPost(request)
email = data["email"]
password = data["password"]
try:
user = User.objects.get(username=email)
if user.check_password(password):
user.backend = 'mongoengine.django.auth.MongoEngineBackend'
user = authenticate(username=email, password=password)
login(request, user)
request.session.set_expiry(3600000) # 1 hour timeout
return jsonResponse(serializeUser(user))
else:
result = {'error':True, 'message':'Invalid credentials'}
return jsonResponse(result)
except User.DoesNotExist:
result = {'error':True, 'message':'Invalid credentials'}
return jsonResponse(result)
def serializeUser(user):
return simplejson.dumps({'email': user.email, 'username': user.username, 'id': str(user.id), 'firstName': user.first_name, 'lastName': user.last_name})
After reading lots of stuff I could make it work this way following MongoEngine User authentication (django).
I'm not setting anything on models.py since I use the default Django user model.
Regards