adding extra field to django-registration using signals - django

I want to add a locale selection to the default django-registration. I tried to follow this tutorial from dmitko. The form shows up correctly but the additional data (locale) is not saved.
I defined a custom model:
class AnymalsProfile(models.Model):
user = models.ForeignKey(User, unique=True)
locale = models.CharField(max_length=2)
def __unicode__(self):
return u'%s %s' % (self.user, self.locale)
and the form:
from models import AnymalsProfile
from registration.forms import RegistrationFormTermsOfService
class UserRegistrationForm(RegistrationFormTermsOfService):
locale = forms.CharField(max_length=3, widget=forms.Select(choices=LOCALE_CHOICES),label='Language:')
The fields show up correctly, but the locale data (profile) is not saved. I assume that the regbackend.py is my problem:
from anysite.models import AnymalsProfile
def user_created(sender, user, request, **kwargs):
form = UserRegistrationForm(request.POST)
data = AnymalsProfile(user=user)
data.locale = form.cleaned_data["locale"]
data.save()
from registration.signals import user_registered
user_registered.connect(user_created)
* EDIT *
I tried moving into production - just for a test - and it raised some errors. I altered the code, but still the profile is not saved. Here is what I tried:
from anysite.models import AnymalsProfile
from anysite.forms import UserRegistrationForm
def user_created(sender, user, request, **kwargs):
form = UserRegistrationForm(request.POST)
if form.is_valid():
ProfileData = form.cleaned_data
profile = AnymalsProfile(
user = user.id,
locale = ProfileData["locale"]
)
profile.save()
from registration.signals import user_registered
user_registered.connect(user_created)

Do you have somewhere in your code import regbackend. That should be done in order to the following strings being executed.
from registration.signals import user_registered
user_registered.connect(user_created)
I my example I have import regbackend in urls.py. Do you have this line as well?

I don't know why, but it didn't like cleaned_data. It now works using the following:
def user_created(sender, user, request, **kwargs):
form = UserRegistrationForm(request.POST)
data = AnymalsProfile(user=user)
data.locale = form.data["locale"]
data.save()
Thanks #dmitko for the code and the support. keep it up!

Related

Use signal function to create Profile object upon creation of User object

I am a following a tutorial on Django and have the following models.py
from django.db import models
from django.contrib.auth.models import User
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
image = models.ImageField(default = 'default.jpg', upload_to = 'profile_pics')
def __str__(self):
return f"{self.user.username} Profile"
I use the register view to create a User object:
def register(request):
if request.method == 'POST': # if form was submitted w data
form = UserRegisterForm(request.POST) #instantiate form w post data
if form.is_valid():
form.save() #save user to db
username = form.cleaned_data.get('username') #get this to print out success message
messages.success(request, f"Your account has been created. You are now able to log in.") #Formatted string literal for f-string
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form':form})
Upon creation of a User object I am trying to use signals to create a Profile object. I have created a signals.py file in my app directory:
from django.db.models.signals import post_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
#Run this function every time a User is created
#receiver(post_save, sender = User)
def create_profile(sender, instance, created, **kwargs):
if created: #if User was created
Profile.objects.create(user = instance)
#receiver(post_save, sender = User)
def save_profile(sender, instance, **kwargs):
instance.profile.save()
and have imported the signals within the ready method of apps.py:
from django.apps import AppConfig
class UsersConfig(AppConfig):
name = 'users'
# To make signals work you have to import your signals
# inside the ready method of our apps.py module
def ready(self):
import users.signals
However, upon the creation of a new User there is still no associated Profile object. Any idea why this is not working?
UsersConfig.ready() never runs and thus your signals are not seen by Django
Solutions
Add users.apps.UsersConfig to your INSTALLED_APPS
OR
Add default_app_config = 'users.apps.UsersConfig' in your __init__.py
OR
Just add your signals directly in your models.py
Checkout: https://docs.djangoproject.com/en/2.2/ref/applications/
Based on the information, I guess you have not defined default_app_config in the __init__.py file of the app.
Open the __init__.py which would be an empty file.
In that, add a line which specifies the value of default_app_config which equals to the path of UsersConfig class which you have defined in apps.py.
It should be following:
default_app_config = 'users.apps.UsersConfig'
Add this line and it should work.

Get the logged in user when there is request is not defined

I am having trouble to find a way to make it work;
I need to get the queryset with a list of the team created by the current logged in user.
My form look the following :
from django import forms
from django.contrib.auth.models import User
from registration.models import MyUser
from .models import Project, Team
from django.contrib.auth import get_user_model
User = get_user_model()
class EditSelectTeam(forms.Form):
team_choice = forms.ModelChoiceField(widget=forms.RadioSelect, queryset=Team.objects.all().filter(team_hr_admin=request.User))
#team_id = forms.ChoiceField(queryset = Team.objects.filter(team_hr_admin= MyUser))
def team_select(self):
data = self.cleaned_data['team_choice']
return data
views.py:
def TeamSelect(request):
if request.method == "POST":
select_form = EditSelectTeam(request.POST)
print('sucess')
else:
select_form = EditSelectTeam(request)
return render(request,'link_project.html',
{'select_form':select_form })
I get the error that request is not define
you can pass the request using init method like:
class EditSelectTeam(forms.Form):
team_choice = forms.ModelChoiceField(widget=forms.RadioSelect, queryset=None)
def __init__(self, request, *args, **kwargs):
super(EditSelecTeam, self).__init__(*args, **kwargs)
self.fields['team_choice'].queryset = Team.objects.all().filter(team_hr_admin=request.User))
def team_select(self):
data = self.cleaned_data['team_choice']
return data
Remember pass in your form the request like:
form = your_form(request)

View with multiple forms not saving (missing 1 positional argument on form)

I have setup an override for Django-Registration-Redux to save on an additional model UserProfile below:
class UserProfile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
tel_number = models.CharField(max_length=20, null = True)
This is setup with the following form:
class UserProfileRegistrationForm(RegistrationFormUniqueEmail):
tel_number = forms.CharField()
And regbackend.py:
from registration.backends.default.views import RegistrationView
from .forms import UserProfileRegistrationForm
from .models import UserProfile
class MyRegistrationView(RegistrationView):
form_class = UserProfileRegistrationForm
def register(self, request, form_class):
new_user = super(MyRegistrationView, self).register(request, form_class)
user_profile = UserProfile()
user_profile.user = new_user
user_profile.tel_number = form_class.cleaned_data['tel_number']
user_profile.save()
return user_profile
However, even though the view loads correctly and I can fill it out, I get the following error each time I save:
register() missing 1 required positional argument: 'form_class'
I assume this is something passing incorrectly?
I checked the code quickly here:
https://github.com/macropin/django-registration/blob/master/registration/backends/default/views.py
That Django-Registration-Redux seems to implement in RegistrationView, the register method like so:
def register(self, form):
#code
Try to remove request and it should work, sth like this.
def register(self, form_class):
new_user = super(MyRegistrationView, self).register(form_class)
#code

django populate db with some data when new user is created

How can I populate the following tables with some default / initial data, every-time new user is created ? I know about this https://docs.djangoproject.com/en/dev/howto/initial-data/, but this works only when I create models. Here I want to insert some default entries when new user is created.
Additionally, when I create a new user how can I add him to a given group with a static group id automatically ?
models.py
from django.db import models
from django.contrib.auth.models import User
class Category(models.Model):
name = models.CharField(max_length=50)
user = models.ForeignKey(User)
class Feed(models.Model):
url = models.URLField()
name = models.CharField(max_length=50)
created = models.DateTimeField(auto_now_add=True)
description = models.TextField(blank=True)
category = models.ForeignKey(Category)
user = models.ForeignKey(User)
views.py
def signup(request):
if request.method == 'POST':
form = UserCreationForm1(request.POST)
if form.is_valid():
form.save()
return HttpResponseRedirect("/accounts/login")
else:
form = UserCreationForm1()
return render(request, "registration/signup.html", {
'form': form,
})
forms.py
class UserCreationForm1(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username', 'email')
Many thanks!
What you're looking for is Django's signals framework.
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User, Group
from my_app import Category, Feed
#receiver(post_save, sender=User)
def init_new_user(instance, created, raw, **kwargs):
# raw is set when model is created from loaddata.
if created and not raw:
instance.groups.add(
Group.objects.get(name='new-user-group'))
Category.objects.create(
name="Default", user=instance)
Feed.objects.create(
user = instance,
name = "%s's Feed" % instance.first_name,
....
)
REF: https://docs.djangoproject.com/en/1.5/topics/signals/
There are at least two ways you can handle populating additional models with data when creating a new user. This first one that comes to mind is a post_save signal:
from django.db.models.signals import post_save
from django.dispatch import receiver
from your_app.models import Category, Feed
#receiver([post_save, post_delete], sender=Coupon)
def add_user_data(sender, **kwargs):
user = kwargs.get('instance')
try:
category, category_created = Category.objects.get_or_create(user=user,
defaults={'name': 'Some Value', 'user': user})
try:
feed, feed_Created = Feed.objects.get_or_create(user=user,
category=category, defaults={'url': 'some-url',
'name': 'some-name', 'description': 'some-desc',
'category': category, 'user': user})
except MultipleObjectsReturned:
pass
except MultipleObjectsReturned:
pass
This code would execute any time an instance of User is saved, but only create the additional records if they don't already exist for that user.
Another way would be to override the save() method on a form for the User. If you also need this functionality in Django admin, you would need to un-register the built-in UserAdmin and register your own UserAdmin class to leverage the custom form.

django profile creation, set User profile while using multiple profile types

I am stuck at user registration, I actually intends to have different profile types. While registration I am unable to set UserProfile while creating a user. I am using UserCreationForm. code in my files are as following.
from django.contrib.auth.forms import UserCreationForm
from registration.forms import RegistrationForm
from django import forms
from django.contrib.auth.models import User
from accounts.models import UserProfile
from django.utils.translation import ugettext_lazy as _
from person.models import Person
from pprint import pprint
class UserRegistrationForm(UserCreationForm):
#email = forms.EmailField(label = "Email")
fullname = forms.CharField(label = "Full name")
class Meta:
model = User
fields = ("email","fullname","password1","password2" )
def __init__(self, *args, **kwargs):
super(UserRegistrationForm, self).__init__(*args, **kwargs)
del self.fields['username']
def clean_email(self):
"""
Validate that the supplied email address is unique for the
site.
"""
if User.objects.filter(email__iexact=self.cleaned_data['email']):
raise forms.ValidationError(_("This email address is already in use. Please supply a different email address."))
return self.cleaned_data['email']
def save(self, commit=True):
user = super(UserRegistrationForm, self).save(commit=False)
#user_profile=user.set_profile(profile_type="Person")
UserProfile.profile.person.full_name = self.cleaned_data["fullname"]
user.email = self.cleaned_data["email"]
if commit:
user.save()
return user
class CompanyRegistrationForm(UserCreationForm):
email=forms.EmailField(label="Email")
class UserProfileForm(forms.ModelForm):
class Meta:
model=UserProfile
exclude=('user',)
accounts/models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user=models.OneToOneField(User)
meta_keywords=models.CharField("Meta Keywords",max_length=255,
help_text="Comma delimited set of keywords of meta tag")
meta_description=models.CharField("Meta Description",max_length=255,
help_text='Content for description meta tag')
def __unicode__(self):
return "User Profile for: "+self.username
class Meta:
ordering=['-id']
views.py
from django.contrib.auth.forms import UserCreationForm
from django.template import RequestContext
from django.shortcuts import render_to_response,get_object_or_404
from django.core import urlresolvers
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from accounts.forms import UserRegistrationForm, UserProfileForm
#from accounts.forms import UserProfile
def register(request,template_name="account/register.html"):
if request.method=='POST':
postdata=request.POST.copy()
form=UserRegistrationForm(postdata)
user_profile=UserProfileForm(postdata)
if form.is_valid():
form.save()
un=postdata.get('username','')
pw=postdata.get('password','')
from django.contrib.auth import login,authenticate
new_user=authenticate(username=un,password=pw)
if new_user and new_user.is_active:
login(request,new_user)
url=urlresolvers.reverse('dashboard')
return HttpResponseRedirect(url)
else:
form=UserRegistrationForm()
page_title="User Registration"
return render_to_response(template_name,locals(),context_instance=RequestContext(request))
#login_required
def dashboard(request):
pass
#login_required
def settings(request):
pass
As I am using multiple profiles so following is code of one of those profiles' models.py:
from django.db import models
from django.contrib.auth.models import User
from accounts.models import UserProfile
class Person(UserProfile):
skills=models.CharField(max_length=100)
fullname=models.CharField(max_length=50)
short_description=models.CharField(max_length=255)
is_online=models.BooleanField(default=False)
tags=models.CharField(max_length=50)
profile_pic=models.ImageField(upload_to="person_profile_images/")
profile_url=models.URLField()
date_of_birth=models.DateField()
is_student=models.BooleanField(default=False)
current_designation=models.CharField(max_length=50)
is_active_jobseeker=models.BooleanField(default=True)
current_education=models.BooleanField(default=True)
class Meta:
db_table='person'
My profile auth in settings.py
AUTH_PROFILE_MODULE='accounts.UserProfile'
Here is a file that also I used after looking at some other place, profile.py:
from accounts.models import UserProfile
from accounts.forms import UserProfileForm
from person.models import Person
from company.models import Company
def retrieve(request,profile_type):
try:
profile=request.user.get_profile()
except UserProfile.DoesNotExist:
if profile_type=='Person':
profile=Person.objects.create(user=request.user)
else:
profile=Company.objects.create(user=request.user)
profile.save()
return profile
def set(request,profile_type):
profile=retrieve(request,profile_type)
profile_form=UserProfileForm(request.POST,instance=profile)
profile_form.save()
I am new and confuse, have seen documentation also. Also saw other solutions at stackoverflow.com but didn't find any solution of my problem. So please tell if you find anything helpful for me. It doesn't seems to be a big problem but as I am new to it so it is a problem for me.
Multiple profile types won't work with the OneToOne relation that is required by Django profile mechanism. I suggest you keep a single profile class containing data common to all profile types and you store type-specific data in a separate set of classes that you link to your profile class using a generic relation.
EDIT:
Thanks for the clarification. Looking at your code again today it seems that you might indeed be able to accomplish what your trying to do with model inheritance. I think the problem is in the save() method of UserRegistrationForm. Try something like this:
def save(self, commit=True):
user = super(UserRegistrationForm, self).save(commit=False)
user.email = self.cleaned_data["email"]
if commit:
user.save()
person = Person(user=user)
person.full_name = self.cleaned_data["fullname"]
person.save()
return user