2

I am creating a registration page for my website using django. The registration form contains the following fields: Username,E-mail,password,password confirmation, user_type. user_type can be either 'student' or 'organisation' which is of radio select type. Depending on the user_type, a user can perform only those specific tasks assigned for that type. So I need a way to store their user_type into the database and later check on it to let them do a specific task. How can I solve this problem?

Forms.py

from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm

USER_TYPE_CHOICES = (
('student', 'Student'),
('organization', 'Organization'),)

class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
user_type = forms.ChoiceField(required=True,widget=forms.RadioSelect, choices=USER_TYPE_CHOICES)

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

Views.py

from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm


def register(request):
    if request.method == 'POST':
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            form.save()
            username = form.cleaned_data.get('username')
            uType = form.cleaned_data.get('user_type')
            messages.success(request, 'Account created for {}, You may login now!'.format(username))
            return redirect('TakeTest-Home')
    else:
        form = UserRegisterForm()
    return render(request, 'users/register.html', {'form': form})

Models.py is empty for this app.

Kiran
  • 55
  • 1
  • 7

2 Answers2

1

Since, the choice of that Form field will be one chosen string value, then you can just store that as a charfield in your model:

So, user_type = models.CharField()

If your choices look as they are in your example:

USER_TYPE_CHOICES = (
('student', 'Student'),
('organization', 'Organization'),)

However, you can give integer values to the choices in you Form like:

choices=(
        (0,'Student'),
        (1,'Organization'),
)

Thus in your model you will save it as user_type = models.IntegerField()

Since only one value (one choice) will be saved at every user, then when you will get this field value back, you will just define tasks and permissions according to the values with if and else in your code later.

And if you would create this Form from Models then you can define the whole thing very similarly in your models, with list of choice' values and so on, but this is not the point of this question.

So your Model simply would look like this for example:

class User(models.Model):
    username = models.CharField(max_length=150)
    email = models.EmailField(max_length=254)
    password1 = models.CharField(max_length=50)
    password1 = models.CharField(max_length=50)
    user_type = models.CharField(max_length=20)
    creation_date = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.username

And if you would like to, then you can save the submitted Form values directly to the database like this too in your view:

from .forms import UserRegisterForm
from .models import User
# and so on imported

def register(request):
    if request.method == 'POST':

        username = request.POST.get('username')
        email = request.POST.get('email')
        password1 = request.POST.get('password1')
        password2 = request.POST.get('password2')
        user_type = request.POST.get('user_type')

        NewUser = User.objects.create(username = username, email = email, password1 = password1, password2 = password2, user_type = user_type)
        Try: 
            NewUser.full_clean(exclude=None, validate_unique=True)
            NewerUser.save()
            return HttpResponse('')
        except ValidationError as e:
            # Do something based on the errors contained in e.message_dict.
            # Display them to a user, or handle them programmatically.
            pass

        # you can send back messages here too    
        return HttpResponse('whatever')
    else:
        form = UserRegisterForm()
        return render(request, 'users/register.html', {'form': form})

Of course you can save that with the normal Form saving method as you did in your question, I just did not want to repeat your code from your question.

The point is on your question that you can either save the chosen user_type value as Charfield or you can also save the chosen value as IntegerField in your Model. In the database it will be only one value for every user. And then you can work with that value later.

And a bit clearer, the point is that you can redirect tasks based on the user_type value in any way you want after you have that value in User table at every of your registered users:

def Usertask_sorting(task1, task2, username):
    Task1 = task1
    Task2 = task2
    Username = username
    field_name = 'user_type'
    obj = User.objects.get(username=Username)
    user_type_value = getattr(obj, field_name)
    if user_type_value == 'Student':
        # let them do task1 or whatever
        return redirect('student_form')
    elif user_type_value == 'Organization':
        # let the user do task2 something else
        return redirect('organization_form')
    else :
        # the user has no valid user_type set
        return redirect('profile_form')

I hope this can give you some direction in the question.

UPDATE - JUST GIVING SOME USEFUL SUGGESTIONS ON CUSTOM USER MODEL

Now the above is fine and answer the original question, however I promised to @Kiran that I'll give some additional useful suggestion to his custom user structure. Since in live environment it's not lucky to create a Model named User since Django already has a User Model and thus can cause conflict.

Instead what we do is creating our own User Model from AbstractModel class which is using all the benefits of Django User Model. It's better to try and practice the whole thing in a new Django project!

But before that, we create a userType Model since it's better to have user_types in a table and not hard-coded in our model or form, then later we can add or delete user_types easier. And since we want to use the values of this model for user_type choices in our custom User model:

from django.db import models

class userType(models.Model):

    name = models.CharField(max_length=50)

    def __str__(self):
        return self.name

Then we just run a migrate and then we continue with the next steps:

With creating our custom User model:

from django.db import models
from django.contrib.auth.base_user import AbstractBaseUser

class OurUser(AbstractUser):

    # we get the usertype choice values from the userType table and creating a list of that
    all_user_types = userType.objects.values()
    USER_TYPE_CHOICES = [(d['id'], d['name']) for d in all_user_types]

    chosen_user_type = models.PositiveSmallIntegerField(choices=USER_TYPE_CHOICES, null=True, verbose_name='User type')

And then we will create our Form from our User Model:

from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.forms import AuthenticationForm
from django import forms
from .models import OurUser

class UserRegistration(UserCreationForm):
    class Meta:
        model = OurUser
        fields = ['username', 'email','chosen_user_type',]

And then we create our view for Registration:

from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect, HttpResponse, HttpRequest
from django.urls import reverse
from django.views import View
from .models import OurUser
from django.template import loader
from django.contrib.auth import login, authenticate
# from django.contrib.auth.forms import UserCreationForm
from .forms import UserRegistration
from .models import OurUser

def signup(request):
    if request.method == 'POST':
        form = UserRegistration(request.POST)
        if form.is_valid():
            # form.save()
            username = form.cleaned_data.get('username')
            email = form.cleaned_data.get('email')
            raw_password = form.cleaned_data.get('password1')
            chosen_user_type = form.cleaned_data.get('chosen_user_type')
            newUser = OurUser.objects.create_user(username=username, email=email, password=raw_password, chosen_user_type=chosen_user_type)
            newUser.save()
            # user = authenticate(email=email, password=raw_password) # authenticate not needed here
            login(request, user)
            return HttpResponseRedirect(reverse('myappname:index'))
    else:
        form = UserRegistration()
    return render(request, 'myappname/signup.html', {'form': form})

And at the end we do not have to forget to register our models in admin.py

from django.contrib import admin
from .models import OurUser, userType

# Register your models here.
admin.site.register(OurUser)
admin.site.register(userType)

And also we do not have to forget to define our custom User Model authentication in settings.py

AUTH_USER_MODEL = 'myappname.OurUser'

In the urls.py we have to give a url path to our registration Form like:

from django.urls import path
from . import views

urlpatterns = [
    path('', views.index, name='index'),
    path('signup', views.signup, name='signup'),
]

And the signup.html in our templates folder:

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

{% block content %}
  <h2>Sign up</h2>
  <form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Sign up</button>
  </form>
{% endblock %}

And finally we just have to run migrate and we should go to our admin of our site and create some user type in our userType table which user types will be used in our custom registration Form as choices.

So I hope it's clearing this subject more. Then we have to figure out the permissions and so on connected to our user types too. Cheers. ;)

Zollie
  • 1,171
  • 7
  • 14
  • Thank you so much for taking your time in explaining it! I've understood it now and I'm sure it'll help me a lot! :) – Kiran Jan 26 '19 at 09:46
  • If I delete a user from django's admin page it's not reflected in the database table. how do I fix it? – Kiran Jan 26 '19 at 13:03
  • @Kiran - the item should be deleted actually from the db. if you delete that via admin. Is there any more info you can provide about this problem? – Zollie Jan 26 '19 at 14:29
  • @Kiran - I read again your question and understand it a bit better. The problem I can imagine here is that you defined your Model as User, which is not lucky name for your custom Model since Django already has User table and User Model in default, so there can be a little conflict here. Please check this in your situation and give me some feedback on this. – Zollie Jan 26 '19 at 15:46
  • @Kiran - in my answer the Model is just an example, I would not use that this way with that name. If you need I can extend my answer with some additional useful things and real life examples on User managment and how to add different groups to users. – Zollie Jan 26 '19 at 18:09
  • Yes I realised that, I renamed my custom model to 'createUser'. The feature I'm looking for is: say a user (of type 'Organisation') is registered and once they login, only they can create a quiz which user's of type 'Student' can take. How do I place that check? I hope I was clear. – Kiran Jan 26 '19 at 18:11
  • also I noticed I can access username/email of the current user in the templates like: {{ user.username }} but it doesn't work for user type when I do {{ user.user_type }}. Also if you don't mind is there another way we can have this conversation on? – Kiran Jan 26 '19 at 18:27
  • Here is the link to my github repository for this project: [ https://github.com/sai8kiran99/taketestproject-working ] – Kiran Jan 26 '19 at 18:33
  • @Kiran - I can help you in these only tomorrow afternoon. I’ll check your project. – Zollie Jan 26 '19 at 18:36
  • @Kiran - I'm sorry, today was full for me, so tomorrow afternoon. I already looked at your project. I'll clear that a bit for you. – Zollie Jan 27 '19 at 18:02
  • @Kiran - I did not forget on you, I just did not have enough time in the last days, but now I updated my answer with some useful suggestion on how to create custom user model and user types. I hope it will help you further. Take care! – Zollie Feb 02 '19 at 07:39
  • I noticed I can access username/email of the current user logged in in the templates like: {{ user.username }} but it doesn't work for user type when I do {{ user.user_type }}. How do I fix that? – Kiran Feb 08 '19 at 05:40
  • @Kiran - in your case, I also checked your github users folder and in your template you have to call the user type like `{{ user.userType }}` since in your createUser Model that is the name of the field. – Zollie Feb 08 '19 at 11:35
  • I've tried {{ user.userType }} but it still doesn't work. – Kiran Feb 08 '19 at 17:19
  • @Kiran - the problem could be coming from a conflict as you did not created your user model from AbstractUser model. And your system this way cannot manage users well. I updated my answer 5 days ago. You should rebuild your app according to those new steps in second part of my answer. Or you should just create a new project and create a new app and try the way of user creation how I did in my update. – Zollie Feb 08 '19 at 17:40
  • @Kiran - and since your users' type at the moment actually not in django User table but in createUser table in your database, user type cannot be reached in your template by using `user.userType` nor with `user.user_type` – Zollie Feb 08 '19 at 17:59
  • @Kiran - But since you use now UserProfile Model too in your app then in your template {{ user.usertype }} actually should work now without defining it in the view. – Zollie Feb 08 '19 at 18:15
  • You reformulated your app well actually now, as you deleted the createUser model. Now your Django uses the normal User model. So as it is in your github repo, now it must work without problem in your template. – Zollie Feb 08 '19 at 18:52
  • can you please help me with this problem? link: [ https://stackoverflow.com/questions/54869681/how-do-i-store-the-uploaded-file-inside-a-folder-having-the-name-from-the-model ] – Kiran Feb 25 '19 at 15:37
0

First you need to know that choices are just Many to Many field in the django.

So you need to declare it in models.py.It should be like below:

class Choices(models.Model):
  description = models.CharField(max_length=100)

class UserProfile(models.Model):
  user = models.ForeignKey(User, blank=True, unique=True, verbose_name='profile_user')
  choices = models.ManyToManyField(Choices)
  def __unicode__(self):
    return self.name

Now you can change your form.py according to it.

In the views.py save the form data like below:

from django.shortcuts import render, redirect
from django.contrib import messages
from .forms import UserRegisterForm


def register(request):
    if request.method == 'POST':
        form = UserRegisterForm(request.POST)
        if form.is_valid():
            form.save()
            messages.success(request, 'Account created for {}, You may login now!'.format(username))
            return redirect('TakeTest-Home')
    else:
        form = UserRegisterForm()
    return render(request, 'users/register.html', {'form': form})

I hope it will help.

vikasvmads
  • 542
  • 1
  • 7
  • 12