Extending User model in django - python

I am trying to register a user in django extending the auth module. I read from here and there and now I am all over the place and dont know what I am doing.
Initially what I wanted to do is register a user with information name, email, mobile and password. since mobile is not in the default django auth I tried to extend auth.
here is the code.
models.py
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class CustomerUserProfile(models.Model):
mobile = models.CharField(max_length = 20)
user = models.ForeignKey(User, unique=True)
def __str__(self):
return "%s's profile" % self.user
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = CustomerUserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
forms.py
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from neededform.models import CustomerUserProfile
class CustomerRegistrationForm(UserCreationForm):
email = forms.EmailField(required = True)
mobile = forms.CharField(max_length = 20)
class Meta:
model = User
fields = ('username','email','mobile','password1','password2')
views.py
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.template import RequestContext
from django.core.context_processors import csrf
from neededform.forms import CustomerRegistrationForm
from neededform.models import CustomerUserProfile
from django.contrib.auth.models import User
def register(request):
if request.method == 'POST':
form = CustomerRegistrationForm(request.POST)
if form.is_valid():
f = form.save()
return HttpResponseRedirect('/registered/')
else:
args = {}
args.update(csrf(request))
args['form'] = CustomerRegistrationForm()
return render_to_response('User_Registration.html', args ,context_instance = RequestContext(request))
This code upon execution makes an entry in auth_user table and an entry in CustomerUserProfile but the mobile coloumn is blank always.
what else am I suppose to add in the code ?
PS. please can some one explain me what is this code doing
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = CustomerUserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
as I copied it from somewhere I want to know how this works actually.
Thank you.

This is a 2-year old question but I am surprised that there was no correct answer.
The mobile field is not saved in your profile, simply because you create your CustomerUserProfile via the post_save signal, and the mobile field is not forwarded by the post_save signal.
I would suggest to simply update your CustomerUserProfile when you handle form.is_valid() in your register function.

Related

How to select a OnetoOne field from a QuerySet in a view?

See all users (that don't have search_hidden enabled) view
#login_required
def users(request):
"""List all users page"""
t_users = User.objects.all()
users = t_users.usersettings.filter(search_hidden=False).select_related('user')
context = {'users': users}
return render(request, 'users/users.html', context)
UserSettings model
from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class UserSettings(models.Model):
"""Stores the user's settings."""
user = models.OneToOneField(User, related_name='usersettings', on_delete=models.CASCADE)
public_profile = models.BooleanField(default=True)
search_hidden = models.BooleanField(default=False)
class Meta:
verbose_name_plural = 'usersettings'
def __str__(self):
return f"{self.user}'s settings"
#receiver(post_save, sender=User)
def create_user_usersettings(sender, instance, created, **kwargs):
if created:
UserSettings.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_usersettings(sender, instance, **kwargs):
instance.usersettings.save()
All users have a UserSettings model tied to them when their accounts are created. In my view, I want to select all users that have search_hidden disabled, however what I've tried doesn't work.The error 'QuerySet' object has no attribute 'usersettings' is displayed whenever the page is requested. I probably need to select each user and retrieve the settings, but I don't know how to do that in an efficient manner.
iliya commented that filtering using t_users.objects.filter(search_hidden=False) would return users where search_hidden is not true in their settings object.

django-admin: How to redirect to URL after one Object save?

I am using Django Signals to Trigger Code once the user is created i am saving additional data on another model class, it's getting triggered but it's not redirecting to additional data object page.
Here is my models.py
from django.db import models
from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.db.models.signals import post_save
class Customers(models.Model):
user = models.OneToOneField(User)
business_name = models.CharField(max_length=250)
address = models.CharField(max_length=500)
area = models.CharField(max_length=250)
city = models.CharField(max_length=250)
state = models.CharField(max_length=250)
pincode = models.IntegerField(default='0')
phone = models.IntegerField(default='0')
mobile = models.IntegerField(default='0')
def create_customer(sender, **kwargs):
if kwargs['created']:
customer_profile = Customers.objects.create(user=kwargs['instance'])
post_save.connect(create_customer, sender=User)
and here is my admin.py
from django.contrib import admin
from .models import Customers
from django.shortcuts import redirect
admin.site.register(Customers)
class Customers(admin.ModelAdmin):
def response_add(self, request, obj, post_url_continue=None):
return redirect('/admin/app/customers/add/')
def response_change(request, obj):
return redirect('/admin/app/customers/add/')
Tired looking for the answer but nothing works, please correct me here.
It doesn't look like you are registering your admin configuration. Refer to Django docs on the register decorator for more information. The syntax is to decorate your function with #admin.register(<model>) or if you want to manually register the model admin configuration then admin.site.register(<model>, <model admin>).
I would recommend changing class Customers(admin.ModelAdmin): to class CustomersAdmin(admin.ModelAdmin): or something similar to stop the namespace clash.
See example below:
from django.contrib import admin
from .models import Customers
from django.shortcuts import redirect
#admin.register(Customers)
class CustomersAdmin(admin.ModelAdmin):
def response_add(self, request, obj, post_url_continue=None):
return redirect('/admin/app/customers/add/')
def response_change(request, obj):
return redirect('/admin/app/customers/add/')

models.py and views.py may be conflicting

Below are the output of the models.py
from django.db import models
from django.core.urlresolvers import reverse
#from django.core.urlresolvers import reverse
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
class Registration(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
username = models.CharField(max_length = 250)
password = models.CharField(max_length = 250)
email = models.CharField(max_length = 250)
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Registration.objects.create(username=instance)
instance.registration.save()
Below is the output of the views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import UserCreationForm
from .forms import SignUpForm
from django.views import generic
class IndexView(generic.View):
templet_name = 'user_info/index.html'
def signupview(request):
if request.method == 'POST':
form = SignUpForm(request.POST)
if form.is_valid():
form.save()
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password')
user = authenticate(username=username, password=raw_password)
login(request, user)
return redirect('registration_form.html')
else:
form = SignUpForm()
return render(request,'user_info/registration_form.html', {'form': form})
I have two questions:
1) In my models.py I have 4 fields, 'user','username','password','email'. In my first field "user", I guess, I shouldn't be using "models.OneToOneField(User, on_delete=models.CASCADE)", because, as per my understanding, it's used when we have a primary key and foreign key in working. Please correct me if I am wrong.
2) in my views.py, the function "signupview", I am saving the form in the database through form.save(), and then cleaned the data. have I done the right thing, as my models.py has 4 fields, but in view.py , I am giving only two fields
username = form.cleaned_data.get('username')
raw_password = form.cleaned_data.get('password')
I hope I am making sense here. I am getting an error while creating a superuser through
python manage.py createsupseruser
Below is the error
django.db.utils.IntegrityError: NOT NULL constraint failed: user_info_registration.user_id
That is why I am asking these questions.
forms.py
from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm
from django import forms
#from django.forms import ModelForm
class SignUpForm(UserCreationForm):
#first_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
#last_name = forms.CharField(max_length=30, required=False, help_text='Optional.')
email = forms.EmailField(max_length=254, help_text='Required. Inform a valid email address.')
class Meta:
model = User
fields = ('username','password1','email')
Latest look of models.py:
from django.db import models
from django.contrib.auth.models import User
class Registration(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
The reason you get the error is that the User post save signal tries to create a Registration instance, but you don't supply values for all the required fields.
#receiver(post_save, sender=User)
def update_user_profile(sender, instance, created, **kwargs):
if created:
Registration.objects.create(username=instance)
instance.registration.save()
You either have to remove this signal handler or you have to provide valid arguments to Registration.objects.create().

Creating a custom login for user changed the login for my Admin. How to prevent that?

I am creating a web application where users have to register themselves and create profiles. I am using the "AbstractBaseUser" class provided by Django, as I wanted to add some other fields. Now, when a user logs in, I want the login credentials to be the Mobile number and the password. I created a custom authentication function for this and registered it in my settings.py. The problem is this changed the login to my admin sit, which I want to remain the same.
I followed the tutorial for add custom fields to User from this link
My models.py:
from django.db import models
from django.contrib.auth.models import AbstractBaseUser
from django.contrib.auth.models import UserManager
class userInfo(AbstractBaseUser):
email = models.EmailField('Email address', unique=True,)
Mobile = models.CharField(max_length=15, unique=True,)
Address = models.CharField(max_length=500)
Landmark = models.CharField(max_length=50)
Status = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
USERNAME_FIELD = 'Mobile'
def __unicode__(self):
return self.get_username()
views.py for login page:
import datetime
from .forms import userInfoForm, LoginForm
from django.shortcuts import render, render_to_response
from .models import userInfo, orderHistory
from django.http import HttpResponseRedirect, HttpResponse
from django.template import RequestContext, loader
from django.contrib.auth import login as django_login, authenticate, logout as django_logoutdef Login(request):
"""
Log in view
"""
if request.method == 'POST':
form = LoginForm(data=request.POST)
print ("Step 1")
if form.is_valid():
print ("Step 2")
user = authenticate(Mobile=request.POST['username'], password=request.POST['password'])
print ("Step 3")
if user is None:
print("No valid user")
if user is not None:
print ("Step 3.10")
if user.is_active:
print ("Step 4")
django_login(request, user)
print ("Step 5")
return redirect('/i/Home')
else:
form = LoginForm()
return render_to_response('loginpage.html', {
'form': form,
}, context_instance=RequestContext(request))`
forms.py:
from django import forms
from .models import userInfo, orderHistory
from django.forms import ModelForm
class LoginForm(forms.Form):
"""
Login form
"""
Mobile = forms.CharField(widget=forms.TextInput)
password = forms.CharField(widget=forms.PasswordInput())
class Meta:
fields = ['Mobile', 'password'] `
The backend I created:
from django.conf import settings
from django.contrib.auth.models import check_passwor
from .models import userInfo
class EmailAuthBackend(object):
"""
A custom authentication backend. Allows users to log in using their email address.
"""
def authenticate(self, Mobile=None, password=None):
"""
Authentication method
"""
try:
user = userInfo.objects.get(Mobile=Mobile)
if user.check_password(password):
return user
except userInfo.DoesNotExist:
return None
def get_user(self, user_id):
try:
user = userInfo.objects.get(pk=user_id)
if user.is_active:
return user
return None
except userInfo.DoesNotExist:
return None
And finally the changes I made to settings.py:
AUTH_USER_MODEL = 'Registration.userInfo'
AUTHENTICATION_BACKENDS = ['Registration.authBackend.EmailAuthBackend', ]
The default backend for Django is ('django.contrib.auth.backends.ModelBackend',), which is what the Django admin is using. When you insert the line:
AUTHENTICATION_BACKENDS = ['Registration.authBackend.EmailAuthBackend', ]
you're overwriting the default backend, rather than adding a second backend option. Change that line to:
AUTHENTICATION_BACKENDS = (
'Registration.authBackend.EmailAuthBackend',
'django.contrib.auth.backends.ModelBackend',
)
and your application should pick up the second backend. You may need to trigger the second backend based on logic for whether the first succeeds, see responses to questions like Django Multiple Authentication Backend for one project, HOW? or the docs here.

Can´t save images on Django Model after extending it

I´m having a really hard time with this. I have extended the Django user model. I created a separate app call "userprofile" (i have 2 apps: 'userprofile' and 'Administration') with new models.py:
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
profile_image = models.ImageField(upload_to="/perfil/", blank=True, null=True)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user = u)[0])
the urls.py:
urlpatterns = patterns('',
url(r'^perfil/$', 'apps.userprofile.views.user_profile', name= 'perfil'),
)
and a views.py:
# Create your views here.
from django.shortcuts import render_to_response
from django.http import HttpResponseRedirect
from django.core.context_processors import csrf
from forms import UserProfileForm
from django.contrib.auth.decorators import login_required
#login_required
def user_profile(request):
if request.method == 'POST':
form = UserProfileForm(request.POST, request.FILES)
if form.is_valid():
form.save()
return HttpResponseRedirect('../index')
else:
user = request.user
profile = user.profile
form = UserProfileForm(instance = profile)
args = {}
args.update(csrf(request))
args['form'] = form
return render_to_response('profile.html', args)
and of course a forms.py:
from django import forms
from models import UserProfile
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Submit, Layout
from crispy_forms.bootstrap import (FormActions, )
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
helper = FormHelper()
helper.form_method = 'POST'
helper.layout = Layout(
'profile_image',
FormActions(Submit('Editar', 'Editar', css_class= 'btn-primary'))
)
def save(self, commit=True):
fact = super(UserProfileForm, self).save(commit=False)
if commit:
fact.save()
return fact
So, what i´m trying to do is to let the user upload an image an let it use it as a profile image. I set the:
AUTH_PROFILE_MODULE = 'apps.userprofile.UserProfile' (the app is inside a folder call 'apps' that´s why the first 'apps' before userprofile)
in the settings.py, and i added the urls of 'userprofile' to the main project. Now I have the template where i can upload an image, the problem is that the image is never saved in the database so I can´t call a function to display the image in a template, let´s say the User Profile page.
Does anyone looking at the code knows what I am doing wrong?
According to the Django 1.7 docs, ModelForm classes must explicitly specify which fields should be updated when the save() method is called. Try adding fields = __all__ to your UserProfileForm class meta.
Relevant section of ModelForm documentation
Notice the first line of the Note in that link:
Any fields not included in a form by the above logic will not be set
by the form’s save() method.
I am still learning Django myself but that's what I would try first. :)

Categories

Resources