{"componentChunkName":"component---src-templates-blog-post-js","path":"/hands-on-assignment-custom-user-model-and-login-via-facebook-f6358a50ac3348cd90f8b7b32a8bcd51/","result":{"data":{"site":{"siteMetadata":{"title":"CommonLounge Archive"}},"markdownRemark":{"id":"e636a0e4-1309-5504-99f6-41385361a996","excerpt":"Welcome to your first project with Django. One of the most common things you’ll do as you begin to design your own web applications is to manage user…","html":"<p>Welcome to your first project with Django. One of the most common things you’ll do as you begin to design your own web applications is to manage user authentication. We covered the generic user creation process earlier that Django provides, but now we’ll delve a little deeper by creating our own custom user model to replace the default one that Django provides. We’ll also integrate social login so that you can login via Facebook into your application!</p>\n<h1><a href=\"#project-goals\"></a>Project Goals</h1>\n<ul>\n<li>Create a custom, more <strong>comprehensive User model</strong>. This can store additional information about the user such as their birth date, their profile photo, etc.</li>\n<li>Learn about several built in Django features such as <strong>custom authentication backends</strong> and the <strong><code class=\"language-text\">sites</code></strong> <strong>framework</strong>.</li>\n<li>Allow users to <strong>log in via social platforms</strong> such as Facebook.</li>\n<li><strong>Integrate 3rd party Django packages</strong> into your application</li>\n</ul>\n<h1><a href=\"#1-set-up-packages\"></a>1. Set up Packages</h1>\n<p>We will start off from where the last tutorial left off but without any of the database or migrations (since we will be modifying some of the models). You can find the starter code <a href=\"https://www.dropbox.com/s/ljhy1gun28o80qy/proj1-starter-v2.zip?dl=0\">here</a>. (If you’re using Django 1.11, use the starter code <a href=\"https://www.dropbox.com/s/jistu3c5ovgwnx5/proj1-starter.zip?dl=0\">here</a>). Alternatively if you want to use your own code from the previous tutorials, just delete all the files in the <code class=\"language-text\">myblog/blog/migrations</code> folder and delete the <code class=\"language-text\">db.sqlite3</code> file at <code class=\"language-text\">myblog/db.sqlite3</code>.</p>\n<h2><a href=\"#python-packages-requirements-file\"></a>Python Packages Requirements File</h2>\n<p>We need to make sure we install all the python packages we need. Remember that earlier we manually installed Django by running <code class=\"language-text\">pip install django~=1.11.0</code> in the command prompt inside our virtual environment. When we have a lot of packages to manage, we create a <code class=\"language-text\">requirements.txt</code> file that just lists the name and versions of all the packages.</p>\n<p>Create this file at the root of your folder, i.e. at <code class=\"language-text\">proj1-starter/requirements.txt</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">django==2.0.6\ndjango-allauth==0.35.0</code></pre></div>\n<hr>\n<p>If you’re using Django 1.11, you should use the following instead:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">django==1.11.0\ndjango-allauth==0.35.0</code></pre></div>\n<hr>\n<p><code class=\"language-text\">[django-allauth](https://django-allauth.readthedocs.io/en/latest/index.html)</code> (<code class=\"language-text\">allauth</code> for short) is the package we are doing to use to help us integrate Login via Facebook into our application. There is a <a href=\"https://djangopackages.org/\">huge ecosystem</a> of packages available that you can simply plug into your Django application. When you find a package that matches your needs, it’s often a better idea to use it rather than re-invent the wheel every time.</p>\n<p>Let’s go ahead and install these packages. Remember that you may have to use a different command to start the virtual environment depending on whether you’re on Windows, OSX, or Linux, as we did <a href=\"https://www.commonlounge.com/discussion/6f97ace2ce954da68f12fed259c34d98#virtual-environment\">here</a>.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">python3 -m venv myvenv\nsource myvenv/bin/activate</code></pre></div>\n<p>Install the packages. <code class=\"language-text\">-r</code> simply denotes the path to the file that has all the package information.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">pip install -r requirements.txt</code></pre></div>\n<p>Perfect, on to step 2!</p>\n<h1><a href=\"#2-create-custom-user-model-usermanager\"></a>2. Create Custom User Model &#x26; UserManager</h1>\n<p>We will begin by creating a custom user model that will add some fields and remove others from Django’s <a href=\"https://docs.djangoproject.com/en/1.11/ref/contrib/auth/#user-model\">default user model</a>. We’d like to</p>\n<ul>\n<li>Get rid of the requirement to have a username and replace it with a default email field.</li>\n<li>Add a <code class=\"language-text\">profile_img_url</code> field so that we can store the user’s profile image</li>\n</ul>\n<p>To override the default user model, we need to create our own user class that subclasses both <code class=\"language-text\">AbstractBaseUser</code> and <code class=\"language-text\">PermissionsMixin</code>.</p>\n<blockquote>\n<p><code class=\"language-text\">[AbstractBaseUser](https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#django.contrib.auth.models.AbstractBaseUser)</code> provides the core implementation of a user model, including hashed passwords and tokenized password resets.</p>\n</blockquote>\n<blockquote>\n<p>To make it easy to include Django’s permission framework into your own user class, Django provides <code class=\"language-text\">[PermissionsMixin](https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#django.contrib.auth.models.PermissionsMixin)</code>. This is an abstract model you can include in the class hierarchy for your user model, giving you all the methods and database fields necessary to support Django’s permission model.</p>\n</blockquote>\n<p>Let’s go ahead and create a new app that will hold our user model.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">python manage.py startapp custom_auth</code></pre></div>\n<h2><a href=\"#cluser-model\"></a>CLUser Model</h2>\n<p>Now to define our new user model. Go to <code class=\"language-text\">custom_auth/models.py</code> and create a class called <code class=\"language-text\">CLUser</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">from django.db import models\nfrom django.contrib.auth.models import PermissionsMixin\nfrom django.contrib.auth.base_user import AbstractBaseUser\nfrom .managers import CLUserManager\nclass CLUser(AbstractBaseUser, PermissionsMixin):\n    email = models.EmailField(unique=True)\n    first_name = models.CharField(max_length=40, blank=True)\n    last_name = models.CharField(max_length=40, blank=True)\n    profile_image_url = models.URLField(null=True, blank=True)\n    is_staff = models.BooleanField(default=False)\n    is_active = models.BooleanField(default=True)\n    date_joined = models.DateTimeField(auto_now_add=True)\n    objects = CLUserManager()\n    USERNAME_FIELD = 'email'\n    REQUIRED_FIELDS = []\n    def get_full_name(self):\n        '''\n        Returns the first_name plus the last_name, with a space in between.\n        '''\n        full_name = '%s %s' % (self.first_name, self.last_name)\n        return full_name.strip()\n    def get_short_name(self):\n        '''\n        Returns the short name for the user.\n        '''\n        return self.first_name</code></pre></div>\n<p>A few important things to note here:</p>\n<ul>\n<li>We’ve gotten rid of the <code class=\"language-text\">username</code> field and set the <a href=\"https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#django.contrib.auth.models.CustomUser.USERNAME_FIELD\">USERNAME_FIELD</a> (line 17) to instead be the <code class=\"language-text\">email</code> field. Any field we choose as the <code class=\"language-text\">USERNAME_FIELD</code> must have <code class=\"language-text\">unique=True</code> set on it since it needs to uniquely identify the user.</li>\n<li>We’ve added a <code class=\"language-text\">profile_image_url</code> field which is a <a href=\"https://docs.djangoproject.com/en/1.11/ref/models/fields/#urlfield\">URLField</a> on line 10.</li>\n<li>We’ve kept around some of the default user attributes such as <code class=\"language-text\">first_name</code>, <code class=\"language-text\">last_name</code>, <code class=\"language-text\">is_staff</code>, <code class=\"language-text\">is_active</code>, and <code class=\"language-text\">date_joined</code>. As an aside, <code class=\"language-text\">is_staff</code> is <code class=\"language-text\">True</code> if the user has access to the admin site, and <code class=\"language-text\">is_active</code> is <code class=\"language-text\">True</code> if the user account is currently active.</li>\n<li>We added a few helper methods to print out the user’s full and short name. These are generally included by default on Django’s User model so we added them here as well. These should be pretty self explanatory.</li>\n<li>Finally we need to write our own <a href=\"https://docs.djangoproject.com/en/1.11/ref/contrib/auth/#django.contrib.auth.models.UserManager\">UserManager</a> . You can see on line 15 that we’ve added <code class=\"language-text\">objects = CLUserManager()</code>. The <code class=\"language-text\">UserManager</code> defines helper methods like <code class=\"language-text\">create_user</code>and <code class=\"language-text\">create_superuser.</code> Since we created our own user object, we need to write our own <code class=\"language-text\">UserManager</code> and provide implementations for both these methods.mana</li>\n</ul>\n<h2><a href=\"#clusermanager\"></a>CLUserManager</h2>\n<p>Let’s create a file called <code class=\"language-text\">managers.py</code> inside the <code class=\"language-text\">custom_auth</code> app and put in the code for our custom <code class=\"language-text\">CLUserManager</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\"># custom_auth/managers.py\nfrom django.contrib.auth.models import BaseUserManager\nclass CLUserManager(BaseUserManager):\n    def _create_user(self, email, password,\n                     is_staff, is_superuser, **extra_fields):\n        \"\"\"\n        Creates and saves a User with the given email and password.\n        \"\"\"\n        if not email: raise ValueError('The given email must be set')\n        email = self.normalize_email(email)\n        user = self.model(email=email,\n                          is_staff=is_staff, is_active=True,\n                          is_superuser=is_superuser,\n                          **extra_fields)\n        user.set_password(password)\n        user.save(using=self._db)\n        return user\n    def create_user(self, email, password=None, **extra_fields):\n        return self._create_user(email, password, False, False,\n                                **extra_fields)\n    def create_superuser(self, email, password, **extra_fields):\n        return self._create_user(email, password, True, True,\n                                **extra_fields)</code></pre></div>\n<p>Here, we provide implementations for <code class=\"language-text\">create_user</code> and <code class=\"language-text\">create_superuser</code> both of which use a <code class=\"language-text\">_create_user</code> helper method.</p>\n<p>Our <code class=\"language-text\">_create_user</code> helper method takes in <code class=\"language-text\">email</code>, <code class=\"language-text\">password</code>, <code class=\"language-text\">is_staff</code>, and <code class=\"language-text\">is_superuser</code>, as well as a dictionary of extra_fields.</p>\n<blockquote>\n<p><code class=\"language-text\">**var_name</code> is simply a shorthand in Python for passing keyword arguments in python. <code class=\"language-text\">var_name</code> in this case refers to a dictionary of key-value pairs. So for example, calling <code class=\"language-text\">_create_user(email, password, is_staff, is_superuser,{'profile_image_url' : 'http://www.example.com'})</code> would pass <code class=\"language-text\">profile_image_url</code> to <em>`create</em>user<code class=\"language-text\">and give it a value of</code>’<a href=\"http://www.example.com&#x27;%60\">http://www.example.com’`</a>. Read more <a href=\"http://book.pythontips.com/en/latest/args_and_kwargs.html#usage-of-kwargs\">here</a>.</p>\n</blockquote>\n<p>You can see that <code class=\"language-text\">create_user</code> sets both <code class=\"language-text\">is_staff</code> to <code class=\"language-text\">False</code> and <code class=\"language-text\">is_superuser</code> to <code class=\"language-text\">False</code>. <code class=\"language-text\">create_superuser</code> sets <code class=\"language-text\">is_staff</code> to <code class=\"language-text\">True</code> and <code class=\"language-text\">is_superuser</code> to <code class=\"language-text\">True</code>.</p>\n<p>Let’s talk about the <code class=\"language-text\">_create_user</code> method in a little more detail. We first make sure that an <code class=\"language-text\">email</code> is passed in. Remember that we’re trying to get rid of the <code class=\"language-text\">username</code> and make the <code class=\"language-text\">email</code> the default! Next we normalize the email by calling the BaseUserManager’s <code class=\"language-text\">normalize_email</code> method which just lowercases the domain portion of the email address (i.e. <code class=\"language-text\">GOOGLE.com</code> would normalize to <code class=\"language-text\">google.com</code>.</p>\n<p>We then go ahead and create the user with self.model → this is just a reference to our <code class=\"language-text\">CLUser</code> model. Finally, we set the password using <code class=\"language-text\">set_password</code>, save the user, and return it.</p>\n<p>Whew! That was a lot to digest. Take a moment before continuing on :).</p>\n<h2><a href=\"#add-the-new-user-to-the-admin\"></a>Add the new User to the admin</h2>\n<p>We now register the <code class=\"language-text\">CLUser</code> with the admin. Copy the following into <code class=\"language-text\">custom_auth/admin.py</code>:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\"># custom_auth/admin.py\nfrom django.contrib import admin\nfrom .models import CLUser\n# Register your models here.\nadmin.site.register(CLUser) </code></pre></div>\n<h2><a href=\"#update-settings\"></a>Update settings</h2>\n<p>In our <code class=\"language-text\">settings.py</code>file located inside the <code class=\"language-text\">mysite</code> folder, we need to add the <code class=\"language-text\">custom_auth</code> app after the <code class=\"language-text\">blog</code> app in the <code class=\"language-text\">INSTALLED_APPS</code> variable. We also set the <code class=\"language-text\">AUTH_USER_MODEL</code> to the <code class=\"language-text\">CLUser</code> model we just created.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">INSTALLED_APPS = [\n    ...\n    'blog',\n    'custom_auth'\n]\nAUTH_USER_MODEL = 'custom_auth.CLUser'</code></pre></div>\n<h2><a href=\"#update-the-blog-app-to-point-to-our-new-user\"></a>Update the Blog App to point to our new user</h2>\n<p>Change the author field inside of the <code class=\"language-text\">Post</code> class in <code class=\"language-text\">blog/models.py</code> to point to our new user model. It’s considered good practice to refer to the model by using the <code class=\"language-text\">AUTH_USER_MODEL</code> settings variable we just defined above instead of referring to the User class directly using <code class=\"language-text\">custom_auth.CLUser</code>. Import settings by writing <code class=\"language-text\">from django.conf import settings</code> (line 3), and then use it to modify line 6 as shown below.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">from django.db import models\nfrom django.utils import timezone\nfrom django.conf import settings\nclass Post(models.Model):\n    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)\n    ...</code></pre></div>\n<h2><a href=\"#migrate\"></a>Migrate</h2>\n<p>Let’s finally run our migrations. Go to the command prompt and type in the following:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">python manage.py makemigrations\npython manage.py migrate</code></pre></div>\n<p>Go ahead and create a superuser as well. Don’t forget the email and password!</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">python manage.py createsuperuser</code></pre></div>\n<p>Check that everything is running by starting our server: <code class=\"language-text\">python manage.py runserver</code>.</p>\n<h1><a href=\"#3-serve-your-local-site-to-the-world-using-ngrok\"></a>3. Serve your local site to the world using Ngrok</h1>\n<p>When you try to integrate Facebook login into your app, you will see that Facebook requires your site to be served over https. When we’re running everything locally, our website is being served over normal http.</p>\n<p>Ngrok is a free service allows you to expose your website from your localhost to a url that is generated for you. This means that you can now give a link to your local website to your friend and they can see it!</p>\n<h2><a href=\"#install-ngrok\"></a>Install Ngrok</h2>\n<p>Go to <a href=\"https://ngrok.com/download\">Ngrok</a> and download their software. You will have to create an account to get your auth_token to be able to use the software. Follow the instructions to unzip and set up your auth token. Once that is done, start ngrok by running:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">./ngrok http 8000</code></pre></div>\n<blockquote>\n<p><code class=\"language-text\">./</code> just says to run the <code class=\"language-text\">ngrok</code> program in the directory you’re in. So make sure you’re in the directory wherever you downloaded ngrok! (Remember you can use <code class=\"language-text\">cd</code>to change your directory).</p>\n</blockquote>\n<p>After running the above, you should see the following output (with different account name and urls of course):</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">Session Status                online\nAccount                       James M (Plan: Free)\nVersion                       2.2.8\nRegion                        United States (us)\nWeb Interface                 http://127.0.0.1:4040\nForwarding                    http://db4da85e.ngrok.io -> localhost:8000\nForwarding                    https://db4da85e.ngrok.io -> localhost:8000</code></pre></div>\n<h2><a href=\"#modify-settingspy\"></a>Modify <code class=\"language-text\">settings.py</code></h2>\n<p>Add the https forwarding url (<code class=\"language-text\">https://db4da85e.ngrok.io</code>) to your <code class=\"language-text\">ALLOWED_HOSTS</code> in <code class=\"language-text\">settings.py</code> so that Django doesn’t complain about it.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">ALLOWED_HOSTS = ['127.0.0.1', 'localhost', '.pythonanywhere.com', 'db4da85e.ngrok.io']</code></pre></div>\n<p>Note that anytime you stop the above ngrok process (by closing your command prompt, killing the process with ctrl+c, etc.), your urls will change when you restart it (unless you’ve paid ngrok). So we advise that while you’re testing this and getting it all set up, keep this process running (maybe in a new command prompt or tab).</p>\n<h1><a href=\"#4-setting-up-allauth\"></a>4. Setting up allauth</h1>\n<p>Finally! We’re getting to the part where we will start integrating Facebook Login into our application :).</p>\n<p>We will make several changes to your <code class=\"language-text\">settings.py</code> file located at <code class=\"language-text\">proj1-starter/settings.py</code>.</p>\n<h2><a href=\"#add-authentication-backends\"></a>Add Authentication Backends</h2>\n<p>We need to let Django know to use the the authentication backend provided by <code class=\"language-text\">django-allauth</code>. An <a href=\"https://docs.djangoproject.com/en/1.11/topics/auth/customizing/#writing-an-authentication-backend\">authentication backend</a> just implements two required methods. These include <code class=\"language-text\">get_user(user_id)</code> and <code class=\"language-text\">authenticate(request,**credentials)</code>. Add this to your <code class=\"language-text\">settings.py</code> file.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">AUTHENTICATION_BACKENDS = (\n    # Needed to login by username in Django admin, regardless of `allauth`\n    'django.contrib.auth.backends.ModelBackend',\n    # `allauth` specific authentication methods, such as login by e-mail\n    'allauth.account.auth_backends.AuthenticationBackend',\n)</code></pre></div>\n<h2><a href=\"#add-allauth-related-settings\"></a>Add <code class=\"language-text\">allauth</code> related settings</h2>\n<p>Next, we add some more apps to <code class=\"language-text\">INSTALLED_APPS</code>. We need to add several apps from <code class=\"language-text\">allauth</code> as well as <code class=\"language-text\">django.contrib.sites</code>.</p>\n<p>The <code class=\"language-text\">sites</code> app is a built in Django feature that allows your Django installation to power more than one site — it is useful if you need to differentiate between those sites in some way. <code class=\"language-text\">allauth</code> uses the <code class=\"language-text\">sites</code> framework so that it is easy to switch between development and production setups and to support multi-domain projects. We won’t be delving deeper into this but you’re welcome to check out the documentation if you’d like to know more <a href=\"https://django-allauth.readthedocs.io/en/latest/index.html\">here</a>.</p>\n<p>The <code class=\"language-text\">allauth</code> apps we’re adding include management for <code class=\"language-text\">SocialAccount</code> (i.e. the actual user social accounts for different providers) as well as the <code class=\"language-text\">SocialApplication</code> (contains configuration information like api keys for different providers such as Facebook or Twitter). Add the following to your <code class=\"language-text\">INSTALLED_APPS</code> list in your <code class=\"language-text\">settings.py</code> file. We’ve denoted the additions with <code class=\"language-text\">######</code>.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">INSTALLED_APPS = [\n    'django.contrib.admin',\n    'django.contrib.auth',\n    'django.contrib.contenttypes',\n    'django.contrib.sessions',\n    'django.contrib.messages',\n    'django.contrib.staticfiles',    \n    ####################\n    'django.contrib.sites',\n    'allauth',\n    'allauth.account',\n    'allauth.socialaccount',\n    'allauth.socialaccount.providers.facebook',\n    #####################\n    'blog',\n    'custom_auth'\n]</code></pre></div>\n<p>We need to also add configuration settings for <code class=\"language-text\">allauth</code>. The explanations for each variable are below. Add these to your <code class=\"language-text\">settings.py</code> file as well.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">## Allauth\n# No username field exists\nACCOUNT_USER_MODEL_USERNAME_FIELD = None\n# No username field required\nACCOUNT_USERNAME_REQUIRED = False\n# We require email\nACCOUNT_EMAIL_REQUIRED = True\n# We authenticate via email\nACCOUNT_AUTHENTICATION_METHOD = 'email'\n# Do all auth over https (necessary for facebook login)\nACCOUNT_DEFAULT_HTTP_PROTOCOL = 'https'\n# No need to verify email for now\nACCOUNT_EMAIL_VERIFICATION = \"none\"\n# This is just the default site that will be created when you\n# run migrate below (because we included it in INSTALLED_APPS).\nSITE_ID = 1</code></pre></div>\n<p>You can now run migrations. Go to the command prompt and type in the following. You may have to quit the server if it’s already running with Ctrl + C.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">python manage.py makemigrations\npython manage.py migrate</code></pre></div>\n<h2><a href=\"#modify-the-urlspy\"></a>Modify the urls.py</h2>\n<p>We need to makes sure the authentication urls for logging in, out, and connecting to social providers like Facebook are properly set up. Open up <code class=\"language-text\">mysite/urls.py</code>, and delete the old <code class=\"language-text\">accounts/login</code> and <code class=\"language-text\">accounts/logout</code> url configurations. We’ve commented them out below so you can see what was there. Instead we replace it with <code class=\"language-text\">allauth.urls</code> like below.</p>\n<p><strong>If you’re using Django 2.0 and above, use the following:</strong></p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">#mysite/urls.py\n...\nurlpatterns = [\n    path('admin/', admin.site.urls),\n    # path('accounts/login/', views.login, name='login'),\n    # path('accounts/logout/', views.logout, name='logout', kwargs={'next_page': '/'}),\n    path('accounts/', include('allauth.urls')),\n    path('', include('blog.urls')),\n]</code></pre></div>\n<hr>\n<p><strong>If you’r using Django 1.11, use the following:</strong></p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">#mysite/urls.py\n...\nurlpatterns = [\n    url(r'^admin/', admin.site.urls),\n    # url(r'^accounts/login/$', views.login, name='login'),\n    # url(r'^accounts/logout/$', views.logout, name='logout', kwargs={'next_page': '/'}),\n    url(r'^accounts/', include('allauth.urls')),\n    url(r'', include('blog.urls')),\n]</code></pre></div>\n<h1><a href=\"#5-setting-up-our-facebook-app\"></a>5. Setting up our Facebook App</h1>\n<h2><a href=\"#create-the-facebook-app\"></a>Create the Facebook App</h2>\n<ol>\n<li>Go to <a href=\"https://developers.facebook.com/\">Facebook Developers</a> and log in using your Facebook account.</li>\n<li>Go to <em>My Apps</em>, and click <em>Add New App</em>.</li>\n<li>Choose any <em>Display Name</em> you’d like and enter your <em>Contact Email</em>.</li>\n<li>On the <em>Add a Product</em> page, select <em>Facebook Login</em>, by clicking on <em>Set Up</em>.</li>\n<li>Ignore the Quickstart menu and go directly to <em>Facebook Login</em> → <em>Settings</em> from the left hand menu.</li>\n<li>Add the following <em>Valid OAuth Redirect URIs</em>:</li>\n<li><code class=\"language-text\">https://db4da85e.ngrok.io/</code></li>\n<li><code class=\"language-text\">https://db4da85e.ngrok.io/accounts/facebook/</code></li>\n<li><code class=\"language-text\">https://db4da85e.ngrok.io/accounts/facebook/login/callback/</code></li>\n</ol>\n<p>Replace <a href=\"https://db4da85e.ngrok.io/\">https://db4da85e.ngrok.io/</a> with whatever your url was from ngrok output above.</p>\n<p>Hit <em>Save Changes</em> at the bottom.</p>\n<ol start=\"7\">\n<li>Go to the overall app <em>Settings</em> → <em>Basic</em> on the left-hand menu.</li>\n</ol>\n<p><img src=\"https://static.commonlounge.com/fp/original/o6zoC6K916JCgP41wEqus90iC1524807607_kc\"></p>\n<p>You should see your <em>App Id</em> and <em>App Secret</em> at the very top. We are now going to configure <code class=\"language-text\">allauth</code> to use these two values.</p>\n<h2><a href=\"#create-the-social-account-in-our-admin\"></a>Create the Social Account in our Admin</h2>\n<p>Go to <a href=\"http://localhost:8000/admin/\">http://localhost:8000/admin/</a>. Sign in using the superuser email and password from earlier. Under the <em>SOCIAL ACCOUNTS</em> heading click on the <em>+ Add</em> next to the <em>Social applications</em> row. You should see something that looks like this:</p>\n<p><img src=\"https://static.commonlounge.com/fp/600w/NmZG8qYw5twerGnOMoXCtIEc01524807608_kc\"></p>\n<p>Select:</p>\n<ul>\n<li>Facebook for the provider</li>\n<li>Choose any <em>Name</em> that you like</li>\n<li>For the <em>Client id</em>, use the <em>App Id</em> from the facebook settings page above.</li>\n<li>For the <em>Secret key</em>, use the <em>App Secret</em> from the facebook settings page above.</li>\n<li>Double click the default <em>example.com</em> site from the Sites so that it becomes a <em>Chosen site</em>.</li>\n</ul>\n<p>Now hit save.</p>\n<h1><a href=\"#6-integrating\"></a>6. Integrating</h1>\n<h2><a href=\"#requesting-the-appropriate-information-from-facebook\"></a>Requesting the appropriate information from Facebook</h2>\n<p>Now we need a way to tell facebook exactly what information we want to request from the user. Some permissions don’t require the user’s explicit approval such as their public profile information (name, profile picture, etc.)</p>\n<p>Fortunately <code class=\"language-text\">allauth</code> allows us to specify exactly what we need, so add the <code class=\"language-text\">SOCIALACCOUNT_PROVIDERS</code> configuration to your <code class=\"language-text\">settings.py</code> file (full <a href=\"https://django-allauth.readthedocs.io/en/latest/providers.html#facebook\">documentation</a>). Comments are below.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">SOCIALACCOUNT_PROVIDERS = {\n    'facebook': {\n         # requesting the user's email and public profile\n         'SCOPE': ['email', 'public_profile'],\n         # The fields to fetch from Facebook's Graph API. We won't\n         # use all of these but just wanted to show you a sample\n         'FIELDS': [\n            'id',\n            'email',\n            'name',\n            'first_name',\n            'last_name',\n            'verified',\n            'locale',\n            'timezone',\n            'link',\n            'gender',\n            'updated_time',\n            'picture'\n        ],\n    }\n}</code></pre></div>\n<h2><a href=\"#modifying-the-default-allauth-flow\"></a>Modifying the default <code class=\"language-text\">allauth</code> flow</h2>\n<p>Now when the user goes through the facebook flow, <code class=\"language-text\">allauth</code>will automatically store all this information and create our <code class=\"language-text\">CLUser</code> object for us. We do however want to explicitly add the users <code class=\"language-text\">profile_image_url</code> so we <strong>need a way to tell</strong> <code class=\"language-text\">allauth</code> <strong>exactly how to modify the user object before it’s saved.</strong></p>\n<p>Because of <code class=\"language-text\">allauth</code>’s great architecture, this is easy to do! It has <a href=\"https://django-allauth.readthedocs.io/en/latest/advanced.html#creating-and-populating-user-instances\">adapters</a> that we can override for any operation. One in particular is the <code class=\"language-text\">populate_user(self, request, sociallogin, data)</code> function. It is a hook that can be used to further populate the user instance (available via <code class=\"language-text\">sociallogin.account.user</code>). Here, <code class=\"language-text\">data</code> is a dictionary of common user properties (<code class=\"language-text\">first_name</code>, <code class=\"language-text\">last_name</code>, <code class=\"language-text\">email</code>, <code class=\"language-text\">name</code>) that the provider already extracted for you.</p>\n<p>Let’s create an <code class=\"language-text\">adapter.py</code> file at <code class=\"language-text\">custom_auth/adapter.py</code>. This will be pretty simple. We will extend the <code class=\"language-text\">DefaultSocialAccountAdapter</code> class that <code class=\"language-text\">allauth</code> provides and override the <code class=\"language-text\">populate_user</code> method from above.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">from django.conf import settings\nfrom allauth.socialaccount.adapter import DefaultSocialAccountAdapter\nclass CustomSocialAccountAdapter(DefaultSocialAccountAdapter):\n    def populate_user(self, request, sociallogin, data):\n      user = super(CustomSocialAccountAdapter, self).populate_user(request, sociallogin, data)\n      url = sociallogin.account.extra_data.get('picture', {}).get('data', {}).get('url')\n      if url: user.profile_image_url = url\n      return user</code></pre></div>\n<p>On line 7, we first let the default method do its modifications to the user object. In Python, we can easily do this by invoking the same function in the parent class by calling <code class=\"language-text\">super</code>. Now that we have the modified <code class=\"language-text\">user</code> object, we just have to add a <code class=\"language-text\">profile_image_url</code> to it.</p>\n<p>The passed in <code class=\"language-text\">sociallogin</code> object will contain <code class=\"language-text\">extra_data</code> available via <code class=\"language-text\">sociallogin.account.extra_data</code>. <code class=\"language-text\">extra_data</code> will be a dictionary that will look something like:</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{\n  \"id\": \"1703333330834\",\n  \"email\": \"test@test.com\",\n  \"name\": \"James Mat\",\n  \"first_name\": \"James\",\n  \"last_name\": \"Mat\",\n  \"verified\": True,\n  \"locale\": \"en_US\",\n  \"timezone\": -7,\n  \"link\": \"https://www.facebook.com/app_scoped_user_id/1703333330834/\",\n  \"gender\": \"male\",\n  \"updated_time\": \"2018-04-18T17:12:54+0000\",\n  \"picture\": {\"data\": {\"height\": 50, \"is_silhouette\": False, \"url\": \"https://lookaside.facebook.com/platform/profilepic/?asid=17027334asdf333&amp;height=50&amp;width=50&amp;ext=15233ad329&amp;hash=A33ag31ar4bD35uJ\", \"width\": 50}}\n}</code></pre></div>\n<p>On line 8, we simply extract the url, and if it exists, on line 9, we set it on the user object.</p>\n<p>Great! We’ve now added the users profile picture to the <code class=\"language-text\">CLUser</code> model.</p>\n<p>The final step before we get to integrating all this new stuff into our templates is to let <code class=\"language-text\">allauth</code> know where to find this adapter class we wrote.</p>\n<p>Just go to <code class=\"language-text\">settings.py</code> and add the <code class=\"language-text\">SOCIALACCOUNT_ADAPTER</code> variable.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">SOCIALACCOUNT_ADAPTER = 'custom_auth.adapter.CustomSocialAccountAdapter'</code></pre></div>\n<h2><a href=\"#modifying-templates\"></a>Modifying Templates</h2>\n<p>Now let’s actually integrate everything into the template. We need to show the right urls in our template, add the user’s first name, and show their profile picture.</p>\n<p>Open up <code class=\"language-text\">base.html</code> in <code class=\"language-text\">blog/templates/blog/base.html</code>. We’re going to load the <code class=\"language-text\">allauth</code> static files right after the <code class=\"language-text\">{% load staticfiles %}</code> like below.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{% load staticfiles %}\n{% load socialaccount %}\n{% load account %}</code></pre></div>\n<p>Next we’re going to change the login and logout urls to point to the ones <code class=\"language-text\">allauth</code>generates.</p>\n<p>So we’ll make the following changes:</p>\n<ul>\n<li>Replace <code class=\"language-text\">{% url 'logout' %}</code> → <code class=\"language-text\">{% url 'account_logout' %}</code></li>\n<li>Replace <code class=\"language-text\">{% url 'login' %}</code> → <code class=\"language-text\">{% provider_login_url \"facebook\" method=\"oauth2\" %}</code></li>\n<li>Replace <code class=\"language-text\">Hello {{ user.username }}</code> with <code class=\"language-text\">Hello {{ user.first_name }}</code></li>\n<li>Add the user’s profile image right next to the edit icon, by creating an image tag → <code class=\"language-text\">&lt;img class=\"top-menu\" src=\"{{user.profile_image_url}}\">&lt;/img></code></li>\n</ul>\n<p>Your final file should look like the one below.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">{% load staticfiles %}\n{% load socialaccount %}\n{% load account %}\n&lt;html>\n    &lt;head>\n        &lt;title>My Blog&lt;/title>\n        &lt;link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css\">\n        &lt;link rel=\"stylesheet\" href=\"//maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css\">\n        &lt;link href='//fonts.googleapis.com/css?family=Lobster&amp;subset=latin,latin-ext' rel='stylesheet' type='text/css'>\n        &lt;link rel=\"stylesheet\" href=\"{% static 'css/blog.css' %}\">\n    &lt;/head>\n    &lt;body>\n        &lt;div class=\"page-header\">\n            {% if user.is_authenticated %}\n                &lt;a href=\"{% url 'post_new' %}\" class=\"top-menu\">&lt;span class=\"glyphicon glyphicon-plus\">&lt;/span>&lt;/a>\n                &lt;a href=\"{% url 'post_draft_list' %}\" class=\"top-menu\">&lt;span class=\"glyphicon glyphicon-edit\">&lt;/span>&lt;/a>\n                &lt;img class=\"top-menu\" src=\"{{user.profile_image_url}}\">&lt;/img>\n                &lt;p class=\"top-menu\">Hello {{ user.username }} &lt;small>(&lt;a href=\"{% url 'account_logout' %}\">Log out&lt;/a>)&lt;/small>&lt;/p>\n            {% else %}\n            &lt;a href=\"{% provider_login_url \"facebook\" method=\"oauth2\" %}\" class=\"top-menu\">&lt;span class=\"glyphicon glyphicon-lock\">&lt;/span>&lt;/a>\n            {% endif %}\n            &lt;h1>&lt;a href=\"/\">My Blog&lt;/a>&lt;/h1>\n        &lt;/div>\n        &lt;div class=\"content container\">\n            &lt;div class=\"row\">\n                &lt;div class=\"col-md-8\">\n                {% block content %}\n                {% endblock %}\n                &lt;/div>\n            &lt;/div>\n        &lt;/div>\n    &lt;/body>\n&lt;/html></code></pre></div>\n<h1><a href=\"#7-testing\"></a>7. Testing</h1>\n<p>To test, we need to load the site using our <strong>https</strong> ngrok link. For example, you may navigate to something like <a href=\"https://db4da85e.ngrok.io/\">https://dbxee81e.ngrok.io</a>. Now click the lock icon, to be redirected to facebook, where you’ll see a page like the one below.</p>\n<p><img src=\"https://static.commonlounge.com/fp/original/C7IskJtuxCT8bxkfNfUsxKVYJ1524807616_kc\"></p>\n<p>Click the big blue “Continue” button and you should be all logged in! You should see both your first name and profile picture displayed in the top bar.</p>\n<hr>\n<p>Congratulations 🎉 🎉 !</p>\n<p>The final code is also available <a href=\"https://www.dropbox.com/s/6o2y5k1xqysdic4/proj1-final-v2.zip?dl=0\">here</a> for your reference. If you’re using Django 1.11, use the final code <a href=\"https://www.dropbox.com/s/z1yzwqzzkk731pb/proj1-final.zip?dl=0\">here</a>.</p>\n<p>Note that, you’ll have to run the following commands after downloading the above project.</p>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">python3 -m venv myvenv\nsource myvenv/bin/activate\npip install -r requirements.txt\npython manage.py makemigrations\npython manage.py migrate\npython manage.py createsuperuser</code></pre></div>\n<p><strong>You’ll also have to create the social account in the admin again!</strong></p>","frontmatter":{"title":"Hands-on Assignment: Custom User Model & Login via Facebook","date":"May 17, 2018","description":""}}},"pageContext":{"slug":"/hands-on-assignment-custom-user-model-and-login-via-facebook-f6358a50ac3348cd90f8b7b32a8bcd51/","previous":{"fields":{"slug":"/your-first-django-project-0d5679ddef8e4d3ba072fa7fc50eb196/"},"frontmatter":{"title":"Your First Django Project!"}},"next":{"fields":{"slug":"/introduction-to-the-command-line-interface-65a8a4ba99124bc1ba2c79931a3e4fff/"},"frontmatter":{"title":"Introduction to the Command-line Interface"}}}},"staticQueryHashes":["2841359383","2969095810"]}