Djitter - how to build a twitter clone using Django 2.0 - Part four

Djitter - how to build a twitter clone using Django 2.0 - Part four

Published 10. jun 2018 11:18 by Stein Ove Helset

In the fourth part of the series we're going make it possible to register and sign in to Djitter. So it's finally beginning to be a bit exciting!

We begin this part by setting up a form for registration and one for authorization. Create a file inside the djeeter folder.


$ touch djeeterprofile/forms.py

Open the forms.py file in your editor and write the following code.


# Import django forms and models

from django.contrib.auth.forms import AuthenticationForm, UserCreationForm
from django.contrib.auth.models import User
from django import forms
from django.utils.html import strip_tags

class SignupForm(UserCreationForm):
  email = forms.EmailField(required=True, widget=forms.widgets.TextInput(attrs={'placeholder': 'Email', 'class': 'form-control'}))
  first_name = forms.CharField(required=True, widget=forms.widgets.TextInput(attrs={'placeholder': 'First Name', 'class': 'form-control'}))
  last_name = forms.CharField(required=True, widget=forms.widgets.TextInput(attrs={'placeholder': 'Last Name', 'class': 'form-control'}))
  username = forms.CharField(widget=forms.widgets.TextInput(attrs={'placeholder': 'Username', 'class': 'form-control'}))
  password1 = forms.CharField(widget=forms.widgets.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}))
  password2 = forms.CharField(widget=forms.widgets.PasswordInput(attrs={'placeholder': 'Password Confirmation', 'class': 'form-control'}))

  class Meta:
    fields = ['email', 'username', 'first_name', 'last_name', 'password1', 'password2']
    model = User

class SigninForm(AuthenticationForm):
  username = forms.CharField(widget=forms.widgets.TextInput(attrs={'placeholder': 'Username', 'class': 'form-control'}))
  password = forms.CharField(widget=forms.widgets.PasswordInput(attrs={'placeholder': 'Password', 'class': 'form-control'}))

If we wanted we could just use the default forms (AuthenticationForm and UserCreationForm) from Django, but we extend and change them a little bit so it's easier to view errors and we can add placeholders.

Implement the forms

Now we're going to implement those to forms and make it possible to sign in and sign up. Open up djitter/urls.py in your editor and replace the content with the following code.


from django.urls import path

from djeeterprofile.views import frontpage, signout

urlpatterns = [
  path('', frontpage, name='frontpage'),
  path('signout/', signout, name='signout'),
]

It looks like the default urls.py but we have import the index view (not created yet) from the djeeterprofile app.

Open djeeterprofile/views.py in your editor and write the following code.


# Import django and models

from django.shortcuts import render, redirect
from django.contrib.auth import login, authenticate, logout
from django.contrib.auth.models import User
from djeeterprofile.forms import SignupForm, SigninForm

# Views

def frontpage(request):
  if request.user.is_authenticated:
    return render(request, 'profile.html')
  else:
    if request.method == 'POST':
      if 'signupform' in request.POST:
        signupform = SignupForm(data=request.POST)
        signinform = SigninForm()
        
        if signupform.is_valid():
          username = signupform.cleaned_data['username']
          password = signupform.cleaned_data['password1']
          signupform.save()
          user = authenticate(username=username, password=password)
          login(request, user)
          return redirect('/')
      else:
        signinform = SigninForm(data=request.POST)
        signupform = SignupForm()
        
        if signinform.is_valid():
          login(request, signinform.get_user())
          return redirect('/')
    else:
      signupform = SignupForm()
      signinform = SigninForm()
  
    return render(request, 'frontpage.html', {'signupform': signupform, 'signinform': signinform})

def signout(request):
  logout(request)
  return redirect('/')

The frontpage view is where we handle sign in and sign up. Since there are two different forms on the same page we need to make sure that we are receiving the correct data. Therefor we added a name attribute to the submit buttons. The first check here pulls the data from the SignupForm and set it as it's data. Django has a built in way to check if the form is valid based on the rules we have set in forms.py

Try it!

If you want you can test the site now by running this command.


$ python manage.py runserver

If you go to your browser now and open the url http://127.0.0.1:8000 you will see our front page with the sign in and sign up forms. Let us create one more template file.


$ touch templates/profile.html

Open the file in your editor and paste the following code.


{% extends 'templates/base.html' %}

{% block main %}
{% endblock %}

Summary

If you try to sign up now and everything is OK you will be redirected back to the frontpage but user.is_authenticated will now be true and a different template(profile.html) will be rendered. Right now it's just a white page, but in the next part we will change this :-)

If you've got any questions your are more than welcome to leave a comment and I'll answer as soon as possible.

Next part

Buy me a coffee

Buy me a coffeeBuy me a coffee

Share this post

Comments

Ruben

10. jun 2018 12:20

Good, keep 'em coming :D

Pt

10. jun 2018 19:54

Wow. Ty so much for these articles. Please keep it up.

Stein Ove Helset

10. jun 2018 21:18

@Ruben and @Pt
Thanks, part five is coming tomorrow :-) Be sure to sign up for the newsletter and you'll get a digest of what's new once a week!

martin

25. sep 2018 08:00

There's a tiny typo in the first import line of the forms.py codeblock: a sneaky angular bracket stuck itself to the end of the line:

from django.contrib.auth.forms import AuthenticationForm, UserCreationForm>

Thanks for your great tutorial : )

Stein Ove Helset

26. sep 2018 05:40

Thank you, Martin! I have remove the "<" now :-)

Robby

19. mar 2019 18:52

Hi.

I have had everything setup correctly so far, but it will not run the server. Here is the output log:

Performing system checks...

Unhandled exception in thread started by <function check_errors.<locals>.wrapper
at 0x7f30f7cbc6a8>
Traceback (most recent call last):
File "/root/djitter_env/lib/python3.6/site-packages/django/utils/autoreload.py"
, line 225, in wrapper
fn(*args, **kwargs)
File "/root/djitter_env/lib/python3.6/site-packages/django/core/management/comm
ands/runserver.py", line 117, in inner_run
self.check(display_num_errors=True)
File "/root/djitter_env/lib/python3.6/site-packages/django/core/management/base
.py", line 379, in check
include_deployment_checks=include_deployment_checks,
File "/root/djitter_env/lib/python3.6/site-packages/django/core/management/base
.py", line 366, in _run_checks
return checks.run_checks(**kwargs)
File "/root/djitter_env/lib/python3.6/site-packages/django/core/checks/registry
.py", line 71, in run_checks
new_errors = check(app_configs=app_configs)
File "/root/djitter_env/lib/python3.6/site-packages/django/core/checks/urls.py"
, line 40, in check_url_namespaces_unique
all_namespaces = _load_all_namespaces(resolver)
File "/root/djitter_env/lib/python3.6/site-packages/django/core/checks/urls.py"
, line 57, in _load_all_namespaces
url_patterns = getattr(resolver, 'url_patterns', [])
File "/root/djitter_env/lib/python3.6/site-packages/django/utils/functional.py"
, line 37, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/root/djitter_env/lib/python3.6/site-packages/django/urls/resolvers.py",
line 533, in url_patterns
patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module)
File "/root/djitter_env/lib/python3.6/site-packages/django/utils/functional.py"
, line 37, in __get__
res = instance.__dict__[self.name] = self.func(instance)
File "/root/djitter_env/lib/python3.6/site-packages/django/urls/resolvers.py",
line 526, in urlconf_module
return import_module(self.urlconf_name)
File "/root/djitter_env/lib/python3.6/importlib/__init__.py", line 126, in impo
rt_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 994, in _gcd_import
File "<frozen importlib._bootstrap>", line 971, in _find_and_load
File "<frozen importlib._bootstrap>", line 955, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 665, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 674, in exec_module
File "<frozen importlib._bootstrap_external>", line 781, in get_code
File "<frozen importlib._bootstrap_external>", line 741, in source_to_code
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "/root/djitter/djitter/urls.py", line 7
path('signout/', signout name='signout'),
^
SyntaxError: invalid syntax

Stein Ove Helset

24. mar 2019 16:56

Hi Robby! Thanks for commenting :-)
You're missing a comma.
path('signout/', signout name='signout'), should be path('signout/', signout, name='signout').
There should be a comma behind the "signout" function.

googles

29. mar 2019 05:44

hello this pst very interesting

just_some_person

15. jul 2019 22:14

How to go about testing the post part of the frontpage view?
It includes two forms, so self.client.post('url', data) isn't going to work.

Coding

09. oct 2019 16:05

I don't see the template code for the frontpage.html. The page is empty at this point Did I miss something in a previous tutorial?

Stein Ove Helset

10. oct 2019 12:07

Hi!
The code for the frontpage template is in the second part:
https://ahackersday.com/blog/djitter-how-to-build-a-twitter-clone-using-django-2-0-part-two/

It's the fourth code block if I'm counting correct.

Add comment