How to create user profile with django-registration? - django

In django 1.7 I use django-registration to handle user registration and I'd like to automatically create a UserProfile instance for each newly registered user.
So in models I have:
class UserProfile(models.Model):
username = models.OneToOneField(User)
name = models.CharField(max_length=30)
occupation = models.CharField(max_length=50)
city = models.CharField(max_length=30)
#models.permalink
def get_absolute_url(self):
return ('view_pirate', None, {'username': self.account.user})
def __unicode__(self):
return unicode(self.username)
#**this line is supposed to create user profile****
User.profile = property(lambda u:UserProfile.objects.get_or_create(username=u)[0])
But when I check the database no new row in userprofile_userprofile is created after a new user registration. What is wrong here?
If the line is in wrong place, where should it be?

Related

How do I best restrict by user and by data model using Django?

I'm using django-guardian and I encountered some issues with the default mixins. And I want to know if there's a better way to do this.
GitHub Link: https://github.com/iaggocapitanio1/django_homepage
Problem:
If I want to limit access at both the model and object levels, using these two mixins (PermissionRequiredMixin, PermissionListMixin) is not a very easy task. Because the permissions_required attribute is overridden. To get around this I had to create a new attribute "object_permission" and do the following:
Model Looks like:
# Create your models here.
from django.db import models
from localflavor.br import models as localModels
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
class Customer(models.Model):
user: User = models.OneToOneField(User, on_delete=models.CASCADE)
def __str__(self):
return f'{self.user.first_name} {self.user.last_name}'
class Company(models.Model):
user: User = models.OneToOneField(User, on_delete=models.CASCADE)
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='comapnies')
def __str__(self):
return f'{self.user.first_name} {self.user.last_name}'
class Project(models.Model):
name = models.CharField(max_length=100)
owner = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name='projects')
class Meta:
permissions = (('read_project', 'Read Project'),)
def __str__(self):
return self.name
class House(models.Model):
rooms = models.IntegerField()
postal_code = localModels.BRPostalCodeField()
project = models.ForeignKey(Project, on_delete=models.CASCADE)
Here I needed to create a new attribute ("object_permission") to limit object-level access
in the View:
class ProjectsListView(PermissionRequiredMixin, PermissionListMixin, ListView):
template_name = 'home/projects.html'
model = models.Project
permission_required = ["homepage.view_project"]
object_permission = ["read_project"]
redirect_field_name = 'next'
login_url = 'login/'
get_objects_for_user_extra_kwargs = {}
def get_object_permission(self, request: HttpRequest = None) -> List[str]:
if isinstance(self.object_permission, str):
perms = [self.object_permission]
elif isinstance(self.object_permission, Iterable):
perms = [p for p in self.object_permission]
else:
raise ImproperlyConfigured("'PermissionRequiredMixin' requires "
"'permission_required' attribute to be set to "
"'<app_label>.<permission codename>' but is set to '%s' instead"
% self.permission_required)
return perms
def get_get_objects_for_user_kwargs(self, queryset):
return dict(user=self.request.user,
perms=self.get_object_permission(self.request),
klass=queryset,
**self.get_objects_for_user_extra_kwargs)
#receiver(post_save, sender=models.Project)
def project_post_save(sender, **kwargs):
"""
Create a Profile instance for all newly created User instances. We only
run on user creation to avoid having to check for existence on each call
to User.save.
"""
project: models.Project = kwargs["instance"]
created: bool = kwargs["created"]
if created:
user = models.User.objects.get(pk=project.owner.user.id)
assign_perm("read_project", user, project)
Am I using the right approach to filter data relative to each user? How do I combine both the page access limitation and the relative data of each user in a class model view?

django add object with the current user

I'm trying to create a todoapp with google login to create personal todolist for each users.
here's views.py
from django.contrib.auth.decorators import login_required
#login_required
def todoView(request):
all_todo_items = Todoitem.objects.filter(userid=request.user.id)
return render(request, 'todoapp/home.html', {'all_items': all_todo_items})
def addTodo(request):
add_new_item = Todoitem(content=request.POST['content'])
add_new_item.save()
return HttpResponseRedirect('/home/')
this is my code before without users but when there's currently login user it's throwing this error
null value in column "id" violates not-null constraint / DETAIL: Failing row contains (null, sampletodo,null). I believe the third column which is null is the userid and first column null is auto increment id since I set it to id SERIAL primary key in todoitem table
I'm 100% sure i need to add something #addTodo views.py, I just dont know how to add todolist with the current user
EDIT here's my models.py
class Todoitem(models.Model):
content = models.CharField(max_length=100)
userid = models.ForeignKey(AuthUser, models.DO_NOTHING,
db_column='userid')
class Meta:
managed = False
db_table = 'todoitem'
class AuthUser(models.Model):
password = models.CharField(max_length=128)
last_login = models.DateTimeField(blank=True, null=True)
is_superuser = models.BooleanField()
username = models.CharField(unique=True, max_length=150)
soon...
class Meta:
managed = False
db_table = 'auth_user'
Just pass the current user the same way you did in todoView. The request object has a reference to the current user through request.user. But you need to specify the user object, not user.id
#login_required
def todoView(request):
all_todo_items = Todoitem.objects.filter(userid=request.user) # changed to request.user
return render(request, 'todoapp/home.html', {'all_items': all_todo_items})
def addTodo(request):
add_new_item = Todoitem(content=request.POST['content'], userid=request.user)
add_new_item.save()
return HttpResponseRedirect('/home/')
You should use a good user model to be able to use request.user.
Try a model like this:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
password = models.CharField(max_length=128)
last_login = models.DateTimeField(blank=True, null=True)
is_superuser = models.BooleanField()
username = models.CharField(unique=True, max_length=150)
then in your views you can do this
def addTodo(request):
add_new_item = Todoitem(content=request.POST['content'], userid=request.user)
def todoView(request):
all_todo_items = Todoitem.objects.filter(userid=request.user) # changed to request.user
return render(request, 'todoapp/home.html', {'all_items': all_todo_items})

Create a separate user type

I am working on an intranet web application which needs two types of users. Normal users that can be setup from django admin and specific type of users -
Employees.
I have the following model for Employee type user.
class Employee(models.Model):
emp_name = models.CharField(max_length=500)
slug = models.SlugField(unique=True, default='')
location = models.CharField(max_length=200)
email = models.EmailField()
experience = models.TextField(blank=True)
primary_skill = models.ManyToManyField(PrimarySkill)
secondary_skill = models.ManyToManyField(SecondarySkill)
I tried having a OneToOneField like this as per the official doc and
this article:
user = models.OneToOneField(User, blank=True, null=True, on_delete=models.CASCADE)
#receiver(post_save, sender=User)
def create_employee(sender, instance, created, **kwargs):
if created:
Employee.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_employee(sender, instance, **kwargs):
instance.employee.save()
I realized that this is the opposite of what I want. Every time a User
is created from the admin, there was an entry created in the
app_employee table.
What I want is this:
Every time an Employee is created, I need a User created.
An Employee can be created using a separate signup form, say emp_signup
How do I approach this scenario?
I have achieved this using a custom user based on AbstractUser inspired by this article.
class CustomUser(AbstractUser):
pass
class Employee(CustomUser):
user = models.OneToOneField(settings.AUTH_USER_MODEL)
# other fields
In settings.py, I then add the following key:
AUTH_USER_MODEL = 'myapp.CustomUser'
And wherever I need to refer the User class, I use get_user_model(), which will substitute our custom user, in views and forms as follows:
views.py
from django.contrib.auth import get_user_model
def user_profile(request):
User = get_user_model()
user = get_object_or_404(User, username=request.user.username)
return render(request, 'user/user_profile.html', {
'site_user': user
})
forms.py
class SignUpForm(UserCreationForm):
class Meta:
model = get_user_model()
fields = ('username', 'email', 'password1', 'password2',)

Django 1.5 Custom User Model unknown column

I am using Django 1.5s Custom User Model. I want to let a user type their username in - and be logged in. NO PASSWORD (for testing anyway). My User Model doesnt have a password. But when i try to login to admin I get the following error:
OperationalError(1054, "Unknown column 'hrms.password' in 'field list'"
It seems to be trying to execute this query in the authenticate() method.
SELECT `myusers`.`password`, `myusers`.`last_login`, `myusers`.`id`, `myusers`.`user`, `myusers`.`name`, `myusers`.`firstname`, `myusers`.`lastname`, `myusers`.`organisation`, `myusers`.`unit`, `myusers`.`grade`, `myusers`.`email`, `myusers`.`position`, `myusers`.`manager` FROM `myusers` WHERE `myusers`.`user` = 'warrenm' "
I do not have the fields password, last_login - I dont know why its trying to get them.
Below is my code.
My Backend (auth.py)
from epmds.application.models import AuthUser
class MyBackend(object):
def get_user(self, user_id):
# get a user from the user_id
try:
return AuthUser.objects.get(pk=user_id)
except AuthUser.DoesNotExist:
return None
def authenticate(self, username=None, password=None):
# check the username/password and return a user
user = AuthUser.objects.get(user=username)
return user
MY Model
class AuthUser(AbstractBaseUser):
id = models.CharField(primary_key=True, max_length=15)
user = models.CharField('username', max_length=20, unique=True)
name = models.CharField(max_length=100)
firstname = models.CharField(max_length=100)
lastname = models.CharField(max_length=100)
organisation = models.CharField(max_length=100)
email = models.CharField(max_length=50, blank=True, null=True)
USERNAME_FIELD = 'user'
def get_full_name(self):
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
return self.first_name
class Meta:
ordering = ('lastname', 'firstname')
managed = False
db_table = 'myusers'
password is part of AbstractBaseUser so it should be added in your AuthUser model as well in table.
As you have managed=False for this model, you need to add that explicitly.

How to bind UserProfile to User and another model?

I have created a Company model and a profile model.
Every User belongs to one company and a company can belong to many users.
Which of the two is the correct way of modelling it?
class Company(models.Model):
company_name = models.CharField(max_length=50)
company_code = models.CharField(max_length=40)
company_email = models.EmailField()
def save(self, *args, **kwargs):
if not self.company_code:
self.company_code = uuid.uuid1()
super(Company, self).save(*args, **kwargs)
Now the UserProfile is defined like this:
class UserProfile(models.Model):
# This field is required.
user = models.OneToOneField(User)
# Other fields here
company = models.ManyToManyField(Company)
# !!!! OR !!!!
company = models.ForeignKey(Company)
Update:
class UserProfile(models.Model):
user = models.OneToOneField(User)
company = models.ForeignKey(Company)
def create_user_profile(self, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
I have now added this bit to UserProfile class also added AUTH_PROFILE_MODULE = 'MyApp.UserProfile' to the settings.
When I do syncdb I get an error message:
>> company = models.ForeignKey(Company)
NameError: name 'Company' is not defined
A ManyToManyField would allow a User to belong to multiple Companys. Based on your spec a ForeignKey would be appropriate.