Django: issues migrating to custom user model - django

I've been writing a Django webapp without much concern for my User model- the provided model has been good, but I've realized that I'd like to be able to customize it somehow.
Starting from scratch with a custom user model looks pretty straightforward, but migrating to one while keeping existing users is a bit trickier, and has been giving me a lot of issues. I found this guide that uses a special package and has step-by-step instructions for my exact situation (Django 1.8, Python 3.4).
One of the prep steps is
You must have ensured that everywhere in your project (including 3rd party libraries) you are using AUTH_USER_MODEL and django.contrib.auth.get_user_model() rather than "auth.User" and django.contrib.auth.models.User.
My project isn't super complex- the only references to the User model are in ForeignKeys as well as a couple lines that get User objects.
Where should I use django.contrib.auth.get_user_model()? My impression is that ForeignKeys need to use settings.AUTH_USER_MODEL and any runtime operation (e.g. obj = User.objects.get(<criteria>) would set User with get_user_model(). Is that correct?
I currently have my AUTH_USER_MODEL setting like:
AUTH_USER_MODEL = User
as an intermediate step, with an import of django.contrib.auth.models.User at the top of settings.py.
I tried to switch my models to use the setting:
class League(models.Model):
name = models.CharField(max_length=100)
users = models.ManyToManyField(settings.AUTH_USER_MODEL)
However when I start the server, I keep getting an error about settings.py
raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
django.core.exceptions.ImproperlyConfigured: The SECRET_KEY setting must not be empty.
What am I doing wrong here? The SECRET_KEY setting isn't empty, so I'm thinking there's a different error in the settings.

A little unclear where you're at right now in the switch from the default to your custom user, but like the docs say here, your AUTH_USER_MODEL should be set like:
AUTH_USER_MODEL = 'auth.User'
As a string, not importing the model directly. 'auth.User' is the default setting, so if you want to use the default user in your code just set it like that, and when you're ready to switch it over change it to whatever app name and model so: 'my_app.CustomUser'
You're getting the SECRET_KEY error because you're trying to import django.contrib.auth.models.User at the top of settings.py., and so it's importing other parts of the django library before the settings file, but the settings file is supposed to be loaded first.

Related

About change AUTH_USER_MODEL and customize the built-in User model

The doc says" If you intend to set AUTH_USER_MODEL, you should set it before creating any migrations or running manage.py migrate for the first time.".
So i want to double check about this, and is it possible to change the built-in User model the DB setup?
You can create your own user model rather than changing the built-in one. That's what AUTH_USER_MODEL does. It tells django to use your user model as the default, rather than the default django.contrib.auth.models.User.
You should do this once in the beginning of the project and then stick with whatever you have setup; as this setting has effects for many other areas of the framework. That is why there is a warning in the documentation.

django google calendar API and south freeze issue

I'm trying to use the Google API django client lib. In order to store the credentials for each user of my web app, a Credentials model is set up:
from oauth2client.django_orm import CredentialsField
class CredentialsModel(models.Model):
id = models.ForeignKey(User, primary_key=True)
credential = CredentialsField()
However upon trying to add this model with a South migration, I get:
Cannot freeze field 'google.credentialsmodel.credential'
(this field has class oauth2client.django_orm.CredentialsField)
South cannot introspect some fields; this is probably because they are custom
fields. If they worked in 0.6 or below, this is because we have removed the
models parser (it often broke things).
To fix this, read http://south.aeracode.org/wiki/MyFieldsDontWork
I read the linked document, but I'm not much clearer on how to fix this. How do I write introspection rules? or how do I fix this to simply add the model with this funky field?
You need to add these lines before your model declaration:
from south.modelsinspector import add_introspection_rules
add_introspection_rules([], ["^oauth2client\.django_orm\.CredentialsField"])
That will allow South to know about the oauth2client.django_orm.CredentialField and to use the introspection rules defined by its parent class.

One Django Project, Multiple Settings.py

Recently I am to develop a CRM system with an e-commerce module. Since customers only log into the e-commerce website (log in with Email), staff only log into CRM,
I want to separate these two authentication model. Is it a good idea to have two sets of settings.py, one using staff as AUTH_USER_MODEL, the other one using customer as AUTH_USER_MODEL? (Maybe separate urls.py as well)
I'm going to run two different settings of app under two sub path or two domain, is this going to cause any issue? (Like concurrency issue ?)
you dont need to set two AUTH_USER_MODEL = 'myapp.MyUser' 's or two settings for this purpose which probabyly would work but this is not the level this logic belongs to. (settings is already in deployment level e.g. running multiple websites on the same codebase and same databse etc etc...)
what I would recommend is something simple:
# settings.py
AUTH_USER_MODEL = 'yourapp.CustomUser'
# yourapp's models.lpy
from django.contrib.auth.models import User
class CustomUser(models.Model):
user = models.OneToOneField(User, related_name="customuser")
crm_staff = models.Boolean(default=False)
# ...
and depending on crm_staff, the user is either crm-user or just an external user. I set the default value of crm_staff to False, so that you have to give it explicitly everytime a new user comes in, but only if user is a crm staff, then you need to set the field to True
keep it as simple as possible, you say thanks to yourself for this later..

Django - Removing username from user model

In order to create a new user model in Django 1.5.x, there are two approaches:
Inherit AbstractUser class which is the default user model you get, this way you can extend it with any attributes you want. However, if you want to remove any field, it's technically possible but not recommended; even if it can be done, it is against OOP principles, I believe. So if you would like to alter the current user model, there is the second approach.
Inherit AbstractBaseUser, which by looking at the code provides very basic functionality. You will miss all the goodness of permissions, profile retrieval and absolute url construction, unless you copy it from the default Django user model.
The above is my understanding of the situation. Correct me if I'm wrong, but doesn't this mean that if I want to simply remove the username field out of the model since I won't need it at all, I have to copy paste the model code provided in the framework and inherit from AbstractBaseUser and PermissionsMixin? For such a simple thing, this approach doesn't look very pretty to me, and it looks a bit odd since I'm quite certain the custom user model was introduced largely because of the popular use case of email field as the user identifier instead of username.
Your thoughts (and corrections) please.
If You look at the source code of the django.contrib.auth.models file then you will see that definition of the AbstractUser class is rather short and starts like this:
class AbstractUser(AbstractBaseUser, PermissionsMixin):
...
It inherits from the AbstractBaseUser and PermissionMixin. You could define your custom model and also inherit it from the mentioned classes to get permissions support. If you want all other model fields then yes, you will need to copy them, but it's also an opportunity to customize things to match your needs.
Rather than using mixins and other applications which solve the problem,
The best way to tackle the problem of not wanting a username is to replace the username with the email address entered by the user.
What u need to do is,
go to the django source code which is usually situated in the python path.
usually in the site-packeges of the python folder,
go to django folder, and into contrib folder, and into auth folder, open the models.py file which contains the definition of the User model.
On Virtualenv -> <virtualenv_name>/lib/python2.7/site-packages/django
In the models.py of auth app
Go to -> AbstractUser class
replace the regex in "validators.RegexValidator" with this:
r"^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+#[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$"
replace only the regex part inside the "validators.RegexValidator"
and in the same class, alter the username field's max_length to 254
I didnt have the reputation to post image of the code, if anybody wants a screenshot of how it looks after altering the code, ping me.
Thats it!
now go back to your app and then you can replace the username field with the email of any type in this world.
The final step :
Go to your application where you are using the User model, meaning anywhere
python manage.py syncdb
python manage.py makemigrations
python manage.py migrate
if you don't see the auth model migrating then do,
python manage.py migrate auth
Now all you need to do is just replace the username with the email, during registration you can do somewhat like:
user = User.objects.create_user('email here', 'again email here', 'password here')
The best part about this is you dont have to change your authentication backend, as the email is itself the username and you can just label the username field as email.

Adding fields to user's personal info in Django admin page

I just started a Django project (there are no apps in it). I activated the admin in settings file and can access the Django administration page. There is a column in Django page to add users; while adding users I get only three fields under personnal info, but I need to store some more information about users. I Googled around and found that I can use user profiles to accomplish this. I tried, but I am having problems.
My aim is to add three more fields to the user table:
role
contact number
other
I need details like: which function I need to write and where to do this.
I found this, but I do not know where I need to write these steps. I would greatly appreciate a more clear explanation of this.
Django User Profiles is what you need. The blog you linked to has clear steps on how to do it. You can check out the Django documentation. http://www.turnkeylinux.org/blog/django-profile also provides a good explanation.
Basically you need to create a new model with User as ForeignKey and define the model in the settings.py as AUTH_PROFILE_MODULE = "django_app.your_profile_modelname". Create the profile and save it just like any other model, and access it using user.get_profile()
Adding a couple of things in response to your questions below:
First, do not create apps as a directory. Use startapp <appname> [destination] as described here. That will create the app directory.
Second, you have to add the app to INSTALLED_APPS in the project's settings file, do a syncdb. Basically, follow the steps in Django tutorial on writing your first app.
Third, UserProfile is a separate model. It is not an extension of User. It is associated with the User just because you added User as the ForeignKey.
Fourth, to be able to see the user profile model in admin, you do exactly what you would do to add any other model to admin page. Create a file names admin.py under your app with:
from django.contrib import admin
from myproject.app.models import UserProfile
admin.site.register(UserProfile)
There are three key concepts to understand:
There is no built in "profile" system in Django, beyond the limited auth app which is really geared just to user login. You are expected to roll your own.
There is nothing magical about a profile record in itslef, it is just like any other record that takes User as a foreign key (or, more properly, a one-to-one field as per the docs). You create it by creating a custom django app (traditionally called profiles) and a model for that app (traditionally called UserProfile, since Profile is not allowed as a model name).
The only thing that sets UserProfile aparts as a model is that you specify it as the AUTH_PROFILE_MODULE which means that it is accessible when called .get_profile() on a User record. That's it. If you set up the UserProfile like so:
def UserProfile(models.Model):
user = models.OneToOneField(User, related_name='profile')
other fields
then you can also access the profile as user.profile rather than user.get_profile() which some people prefer.
Again, nothing magical about the profile model -- it is just a model record like any other model record.
If you want to be able to edit additional fields within the user form that's more complicated; easiest way is probable unregister User and then register it again using your custom ModelAdmin and form class but judging by your question you're probably not at that level yet.