Django switch database dynamically - django

I'd like to switch databases upon user login. I've created this login signal.. but it doesn't work
from django.dispatch import receiver
from django.contrib.auth.signals import user_logged_in
from django.db import connections
#receiver(user_logged_in)
def db_switch(sender, **kwargs):
user_db = 'userdb_%s' % kwargs['user'].username
cursor = connections[user_db].cursor()
The databases are defined in settings.py. Do I have to make this cursor global? Or is this all the way wrong way of doing it?
Thanks!

It's the wrong way of doing it.
Honestly I don't think there is a straightforward, stable way of doing this in Django. It's just not designed for it.
Instead, I'd set up a settings_username.py file for each user, which specifies a secondary database called personal or something. Then, after logging, have them redirect to a new domain, like username.example.com, which uses a unique .wsgi file that pulls in the settingsusername.py file.
Now, as far as the system is concerned, each website is totally separate and unique to that user. Just make sure to set the session cookie to example.com so that they're still logged in when they go to their user website.

Related

RelatedObjectDoesNotExist at /login/ while running the server locally

I using One To One field in Django to save some extra information about user but even afte migrating i got the issue which i mentioned in title
my models.py
the issue I got
issue while running server
please help if you can
The error you are getting:
User has no profile
Simply means what it says, meaning the particular User instance you are dealing with has no related Profile. Now you might be wondering why not, but that is because a User record can perfectly exist without a 'Profile' relation, the constraint only applies to your profiles, which cannot be created without a corresponding user record.
So if you have somehow tried linking the user to a certain profile, that means the code that is supposed to make that happen isn't doing so and from what I got from the images, you're using signals for that. But I wouldn't recommend doing so, not because signals are generally bad, but because in this case its sorta overkill, and it spreads your code too much.
What I'd suggest/recommend is to add the logic to create profile in the User creation form.
Your problem is probably because the user does not have an associated profile in the DB.
Even though there is an OneToOne relation there doesn't a guarantee. that a user will have a profile.
So you probably need to create a profile for that user.
Also if you want to extend the user model, Ill recommend that you check out this. It contains more ways to achieve what you are looking for
profile doesnt get created automatically ,you need either to add it manually or use signals so that every time a user is created a profile also is created,
if you have a profile model lets say you named it Profile
create a signals.py and add this to it:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
#receiver(post_save, sender=User)
def create_profile(sender, instance, created, *args, **kwargs):
if created:
Profile.objects.create(user=instance)
If you're adding blank=True, then why are you adding default=''
If you want profile picture to be mandatory, remove blank=True

How can I trigger a function when a user registers in django?

I took over a django web app and am still relatively new to django. I want to trigger a function whenever a new user registers on the website. But there is no code in the project to process the user registration. It all seems to happen under the hood. So I don't know where could put such a function call. The web app uses django.contrib.auth.
Additionally: How can I trigger a function when an account is activated?
You can use the signals to trigger an event when you save anything in your db, include the User from auth. You can see the django doc about this.
In your case, I think that the best way is like:
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import user
#receiver(post_save, sender=User)
def user_saved(sender, instance, **kwargs):
...
In the kwargs you can see, for example, if object is created or modified. The sender is the Class and the instance is the object.

How to execute code after authentication in Django?

I want to execute one or more functions after a user logs into my site. How is this possible? I looked into Middleware. Djangobook says that I'll need this to run a piece of code on each and every request that Django handles. However, I just need the code run when the authentication happens successfully.
Note: I am using Django Allauth for authentication and I don't have any view of my own to log in users.
You need to tap into Allauth's signals. Specifically the user logged in signal
allauth.account.signals.user_logged_in(request, user)
Sent when a user logs in.
So add code similar to the following in your project.
from django.dispatch.dispatcher import receiver
from allauth.account.signals import user_logged_in
#receiver(user_logged_in, dispatch_uid="unique")
def user_logged_in_(request, user, **kwargs):
print request.user
This code should be in a place that's likely to be read when django starts up. models.py and views.py are good candidates.
As per the official documentation, there is a signal allauth.account.signals.user_logged_in which gets triggered when a user logs in. This can serve your purpose.

Questions about extending any Django app

My old worker installed Pinax through PIP and it's installed in site-packages. All the apps lives there. Our own apps are within our Django project structure.
I want to modify Pinax's account app, by switching the create_user's is_active flag to False. Currently, the app makes it True. I also want to add additional functionality to create_user or whatever function I want to do.
from pinax.account import forms
class MyCustomizeForm(forms.SignupForm):
def create_user(....):
super(....)
// additional...
Maybe this?
But doesn't that require me to do at least two commit transactions talking to DB?
Is that preferable? Also, does doing this require me to change anything else in my Django project (how users signup, what views it uses... what forms it uses)?
Currently, I've an app living in my Django project supposes to deal with the extension / customization of account app. I can't commit site-packages to VCS.... I mean.. I am not supposed to make any changes there.
Thanks.
Pinax account/models.py
class Account(models.Model):
...
def its_own_method(...)
# this is in the same indentation level as class Account
def create_account(sender, instance=None, **kwargs):
if instance is None:
return
account, created = Account.objects.get_or_create(user=instance)
post_save.connect(create_account, sender=User)
You can use the django signals for exactly this situation. Signals are meant for apps that need to be distributed generally and won't always know how they will be integrated into a project.
The signal of interest to you here is the pre_save. You can connect a pre_save to the pinax.account model and be notified when a save is about to happen. This will give you a chance to make changes to that model instance. Signals are synchronous, meaning you are making your change serially, right before the pinax.accounts will finish committing the save

How to get unique users across multiple Django sites powered by the "sites" framework?

I am building a Django site framework which will power several independent sites, all using the same apps but with their own templates. I plan to accomplish this by using multiple settings-files and setting a unique SITE_ID for them, like suggested in the Django docs for the django.contrib.sites framework
However, I don't want a user from site A to be able to login on site B. After inspecting the user table created by syncdb, I can see no column which might restrict a user to a specific site. I have also tried to create a user, 'bob', on one site and then using the shell command to list all users on the other side and sure enough, bob shows up there.
How can I ensure all users are restricted to their respective sites?
The most compatible way to do this would be to create a user Profile model that includes a foreign key to the Site model, then write a custom auth backend that checks the current site against the value of that FK. Some sample code:
Define your profile model, let's say in app/models.py:
from django.db import models
from django.contrib.sites.models import Site
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
site = models.ForeignKey(Site)
Write your custom auth backend, inheriting from the default one, let's say in app/auth_backend.py:
from django.contrib.auth.backends import ModelBackend
from django.contrib.sites.models import Site
class SiteBackend(ModelBackend):
def authenticate(self, **credentials):
user_or_none = super(SiteBackend, self).authenticate(**credentials)
if user_or_none and user_or_none.userprofile.site != Site.objects.get_current():
user_or_none = None
return user_or_none
def get_user(self, user_id):
try:
return User.objects.get(
pk=user_id, userprofile__site=Site.objects.get_current())
except User.DoesNotExist:
return None
This auth backend assumes all users have a profile; you'd need to make sure that your user creation/registration process always creates one.
The overridden authenticate method ensures that a user can only login on the correct site. The get_user method is called on every request to fetch the user from the database based on the stored authentication information in the user's session; our override ensures that a user can't login on site A and then use that same session cookie to gain unauthorized access to site B. (Thanks to Jan Wrobel for pointing out the need to handle the latter case.)
You can plug your own authorization and authentication backends that take the site id into consideration.
See other authentication sources on the django documentation and the authentication backends references
Besides that, if your django source is too old, you can always modify the authenticate() or login() code yourself. After all... Isn't that one of the wonders of open source. Be aware that by doing so you may affect your compatibility with other modules.
Hope this helps.
You have to know, that many people complain for Django default authorization system and privileges - it has simply rules for objects, for instances of the objects - what it means, that without writing any code it woudn't be possible.
However, there are some authorization hooks which can helps you to achieve this goal, for example:
Take a look there:
http://code.djangoproject.com/browser/django/trunk/django/contrib/auth/models.py
and for class Permission.
You can add your own permission and define rules for them (there is a ForeignKey for User and for ContentType).
However2, without monkeypatching/change some methods it could be difficult.