Bulk user import in Django - python

I like to bulk import users from xlsx or csv to my original User model. I don't use AbstractUser or AbstractBaseUser and I don't like to because my site is working and I don't want to abuse my schema.
I am using the original User model where I add the users (no user registration allowed) and I store the extra fields in my Profile model with a OneToOne relation.
I'm not so experienced so I tried to use code snippets that I found but I am still not able to achieve my goal. If I try to use import-export module in my admin panel it works with other models but not with the User model. Tablib or other solutions would be also interesting to me.
models.py
(I'm using the original User model that sends a signal to Profile model when a user is created)
class Profile(models.Model):
def __str__(self):
return str(self.user)
user = models.OneToOneField(User, null=True, on_delete=models.CASCADE)
date = models.DateField(auto_now_add=True, auto_now=False, blank=True)
projekt = models.ForeignKey(Projekt, on_delete=models.CASCADE, default=1)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
Profile.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
forms.py
class RegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'last_name', 'first_name', 'password1', 'password2']
admin.py
from django.contrib.auth.models import User
from import_export.admin import ImportExportModelAdmin
#admin.register(User)
class UserAdmin(ImportExportModelAdmin):
pass
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
I got this error message:
django.contrib.admin.sites.AlreadyRegistered: The model User is already registered with 'auth.UserAdmin'.
I understand that my User model is in use but what could I do?

Related

Queries related to Django Signals

To begin with, Here Profile and Seller model is created when a User model is created through Signals.What I want to do is When profile model is first created or updated,I want all the fields of Seller model to be same as all fields of Profile.Similarly when I first created Seller model,I also want all fields of Profile Model to be same as that of Seller model.But,I couldn't figure out how to do?
from typing import Tuple
from django.db import models
from django.contrib.auth.models import User
from django.urls import reverse
from django.db.models.fields import DecimalField
from django.dispatch import receiver
from django.db.models.signals import post_save
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, null=True, blank=True) #cascade is for deleting the customer
first_name = models.CharField(max_length=10, null=True)
second_name=models.CharField(max_length=10,null=True)
email = models.EmailField(max_length=70, null=True,blank=True)
#receiver(post_save, sender=User)
def create_profile(sender, instance,created,**kwargs):#Signal receivers must accept keyword arguments (**kwargs).
if created:
Profile.objects.create(user=instance)
...
#receiver(post_save, sender=Profile)
def create_seller(sender, instance,created,**kwargs):#Signal receivers must accept keyword arguments (**kwargs).
if created:
Seller.objects.create(user=instance)
class Seller(models.Model):
user = models.OneToOneField(Profile, on_delete=models.CASCADE, null=True, blank=True) #cascade is for deleting the customer
first_name = models.CharField(max_length=10, null=True)
second_name=models.CharField(max_length=10,null=True)
email = models.EmailField(max_length=70, null=True,blank=True)
...
If created=True it means a Profile object is created. otherwise if created=False it means that a Profile object has been updated.
When created=True you need to create a Seller object and when created=False you need to update a Seller object.
You can do this:
#receiver(post_save, sender=Profile)
def update_or_create_seller(sender, instance, created, **kwargs):
if created:
Seller.objects.create(
user=instance.user,
first_name=instance.first_name,
second_name=instance.second_name,
email=instance.email
)
else:
seller = instance.user.seller
seller.first_name = instance.first_name
seller.last_name = instance.second_name
seller.email = instance.email
seller.save()
Also notice that unless you define related_name in your OneToOneField, Django will use lowercased model name to access related object. So, instance.user.seller should work.

Django Admin Create Form Inline OneToOne

I have the following model:
from django.db import models
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
last_password_reset = models.DateTimeField(auto_now_add=True)
needs_password_reset = models.BooleanField(default=True)
image_url = models.URLField(max_length=500, default=None, null=True, blank=True)
I am trying to inline this into the admin. I have the following:
from django import forms
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm
class UserProfileInline(admin.StackedInline):
"""User profile inline."""
model = Profile
can_delete = False
verbose_name_plural = "Profile"
class CustomUserCreationForm(UserCreationForm):
"""Create user form."""
class Meta:
model = User
fields = ("username", "first_name", "last_name", "email")
class CustomUserAdmin(UserAdmin):
"""Custom user admin."""
add_form = CustomUserCreationForm
inlines = (UserProfileInline,)
admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)
This is working fine up to a point; when I go to create user, I can see the inlined profile information. However, when I try to submit the form I get the following error (on /admin/auth/user/add/):
psycopg2.errors.NotNullViolation: null value in column "user_id" violates not-null constraint
Why is the user_id field not getting populated in the inline form? How can I set this attribute to the id of the user created by the form?
Turns out I needed to remove some signals I had written for automatic profile creation:
# Create a profile for new users
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_user_profile(sender, instance=None, created=False, **kwargs):
if created:
Profile.objects.get_or_create(user=instance)
# Update profile on user change
#receiver(post_save, sender=User)
def save_user_profile(sender, instance=None, created=False, **kwargs):
instance.profile.save()

Django: authtools do create the user profile when the user is created

I am using the authtools plugin to manage the user and its profile in django, but when I create the user, it does not create its profile, I have to go to the admin part of the site and create it manually.
I separated the applications into account and profile.
This is the profiles model:
class Profile(models.Model):
user = models.OneToOneField(settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
primary_key=True)
slug = models.UUIDField(default=uuid.uuid4, blank=True, editable=False)
email_verified = models.BooleanField("Email verified", default=True)
This is the signal.py, that is inside of the profiles application:
#receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_profile_handler(sender, instance, created, **kwargs):
if not created:
return
profile = models.Profile(user=instance)
profile.save()
logger.info('New user profile for {} created'.format(instance))
This is the admin.py of the account app:
class UserProfileInline(admin.StackedInline):
model = Profile
class NewUserAdmin(NamedUserAdmin):
inlines = [UserProfileInline]
list_display = ('is_active', 'email', 'name', 'permalink',
'is_superuser', 'is_staff',)
# 'View on site' didn't work since the original User model needs to
# have get_absolute_url defined. So showing on the list display
# was a workaround.
def permalink(self, obj):
url = reverse("profiles:show",
kwargs={"slug": obj.profile.slug})
# Unicode hex b6 is the Pilcrow sign
return format_html('{}'.format(url, '\xb6'))
admin.site.unregister(User)
admin.site.register(User, NewUserAdmin)
admin.site.register(Profile)
When I signup a user, both the user and the profile objects are created, only they are not linked. Why is that?
Thank you
Use this below your profile model in models.py. I hope you are generating slug by another slugify signal.
def user_created_receiver(sender, instance, created, *args, **kwargs):
if created:
Profile.objects.get_or_create(user = instance)
post_save.connect(user_created_receiver, sender = User)

Django model extending Default User model (one-to-one field), how to create reg form for all combined model fields

I am using Django 1.10.*. This is my user profile model:
class student(models.Model):
user = models.OneToOneField(User, primary_key=True, on_delete=models.CASCADE)
state = models.CharField(max_length=21, null=True, blank=True, choices=in_states.STATE_CHOICES)
city = models.CharField(max_length=21, null=True, blank=True)
date_joined = models.DateTimeField(default=timezone.now)
educational_role = models.CharField(max_length=39, choices=EDUCATIONAL_ROLE)
institute = models.ForeignKey(educational_institute, null=True, blank=True)
language = models.CharField(max_length=8, choices=LANGUAGES)
#receiver(post_save, sender=User)
def create_user_profile(sender, instance, created, **kwargs):
if created:
student.objects.create(user=instance)
#receiver(post_save, sender=User)
def save_user_profile(sender, instance, **kwargs):
instance.profile.save()
When I created form class for student and use that to create a View class extending FormView class in my Views passing the form context to HTML template like this:
forms.py :
class RegistrationForm(forms.ModelForm):
class Meta:
model = student
fields = ['user', 'state', 'city', 'educational_role', 'institute', 'language']
views.py :
class Register(FormView):
template_name = 'searcher/register.html'
form_class = RegistrationForm
def get_context_data(self, **kwargs):
context = super(Register, self).get_context_data(**kwargs)
context['applink'] = applink
context['forumlink'] = forumlink
return context
So how do I need to modify this so that the registration form asks for username, firstname, email of User model and also the fields added by student model and having option for creating a new educational_institute if it doesn't exist already?
You could use multi-table inheritance django.contrib.auth.models.User. Would look like this:
from django.contrib.auth.models import User
class Student(User):
state = models.CharField(...)
...
This way all Django features like ModelForm or UpdateView should function without any additional fiddling. In behind, Django will just create exactly the same OneToOneField for you.
And if all of your users are students you could also replace the auth user model entirely.
If you don't want to do any of those, you will need to add additional fields into your form, specify them if you form Meta, take care of setting their default values (in __init__ in example), cleaning these fields and saving the model behind OneToOneField all by yourself.

UserProfile missing the User object

I'm using a custom sign up form with django-allauth.
settings.py
ACCOUNT_SIGNUP_FORM_CLASS = 'project.userprofile.form.UserSignupForm'
form.py
from django import forms
from models import UserProfile
class UserSignupForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('mobile_number',)
models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.ForeignKey(User, unique=True)
mobile_number = models.CharField(max_length=30, blank=True, null=True)
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
The User and the UserProfile objects are created, however the UserProfile isn't associated with any User object. It's late and I'm probably missing something silly, right?
UPDATE: As Kevin pointed out, the solution was to add the save method in the form.py. This is how it looks now:
from django import forms
from django.contrib.auth.models import User
from models import UserProfile
class UserSignupForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('mobile_number',)
def save(self, user):
profile = UserProfile(user=user)
profile.mobile_number = self.cleaned_data['mobile_number']
profile.save()
The documentation says:
[ACCOUNT_SIGNUP_FORM_CLASS] should implement a ‘save’ method, accepting the newly signed up user as its only parameter.
It looks like you haven't provided such a method, so the user never gets connected to the profile. And I think you're not seeing an error because ModelForm has a save(commit=True) method that happens to match this signature, even though it doesn't do what you want.

Categories

Resources