I added a new UserProfile Model to my project today.
class UserProfile(models.Model):
user = models.OneToOneField(User)
...
def __unicode__(self):
return u'Profile of user: %s' % (self.user.username)
class Meta:
managed = True
def create_user_profile(sender, instance, created, **kwargs):
if created:
profile, created = UserProfile.objects.get_or_create(user=instance)
post_save.connect(create_user_profile, sender=User)
The above code will create a user profile for each new created user.
But how to create the user profile for each existing user automatically?
Thanks
You can loop through the existing users, and call get_or_create():
for user in User.objects.all():
UserProfile.objects.get_or_create(user=user)
You could put this in a data migration if you wish, or run the code in the shell.
For existing users, it checks whether such an instance already exists, and creates one if it doesn't.
def post_save_create_or_update_profile(sender,**kwargs):
from user_profiles.utils import create_profile_for_new_user
if sender==User and kwargs['instance'].is_authenticate():
profile=None
if not kwargs['created']:
try:
profile=kwargs['instance'].get_profile()
if len(sync_profile_field(kwargs['instance'],profile)):
profile.save()
execpt ObjectDoesNotExist:
pass
if not profile:
profile=created_profile_for_new_user(kwargs['instance'])
if not kwargs['created'] and sender==get_user_profile_model():
kwargs['instance'].user.save()
to connect signal use:
post_save.connect(post_save_create_or_update_profile)
In response to your code I'll say to put a get_or_create also in a post_init listener for User.
If this "all fields null is ok" profile is just a fast example I'd put a middleware redirecting all users with no profile to the settings page asking them to fill additional data. ( probably you want to do this anyway, no one in the real world will add new data to their existing profiles if not forced or gamified into it :) )
Related
Here i'm using django latest verion which is 3.1.4 and I just want to add condition in django admin side. I just wanted to return some text in terminal if i update my model from admin panel.
In my case
user submit kyc form
admin person approved that form
user will get notification on approval. (Right now I just want to print some message when admin update his kyc by updating his kyc form by updated approved boolean field.
In short Just wanted to show message when admin updates any model in django admin side.
admin.py
class KycAdmin(admin.ModelAdmin):
list_display = ['__str__','owner']
class Meta:
model = KycModel
def post(self,request):
response = "i'm updated"
print(vu)
return vu
admin.site.register(KycModel,KycAdmin)
If more detail is require then you can just tell me in a comments.
Have you tried overriding the save method in models.
Whenever you save an object, it will hit the save method. You can print whatever you want to over there
class SomeModel(models.Model):
... some fields for eg. name
def save(self, *args, **kwargs):
print(self.name)
super().save(*args, **kwargs)
This is the simplest way to achieve it. You can also override save in admin.
I'm a total Django newbie and apologize in advance if I'm not using the correct terminology.
I'm using django-registration to register user on my web-app. I've successfully adapted it work with my custom user model GeneralUser.
Conceptually, each GeneralUser has a Business, another model that I've defined. Whether this is the correct decision or not, I've decided that I never want to register a user without a related Business object.
I've read countless threads on customizing django form, and finally after a few days of unsuccessful attempts, came upon an answer that helped reach a solution. However, I am unsure that my code is correct/safe. This is my adaptation, followed by the linked-answer:
my adaptation:
class GeneralUserForm(UserCreationForm):
business_name = forms.CharField(required=True)
class Meta:
model = GeneralUser
fields = ['username', 'email', 'password1',
'password2', 'business_name']
def save(self, commit=True):
user = super(UserCreationForm, self).save(commit=True)
business = Business(name=user.business_name, owner=user)
# notice: no if-block
user.save()
business.save()
# notice: returning only a user-instance
return user
This code successfully creates a user and a business object, and creates the relationship. Looking at the original answer code though, I wonder if there isn't something critical I'm missing:
Answer I based my code on:
class UserCreateForm(UserCreationForm):
job_title = forms.CharField(max_length=100, required=True)
age = forms.IntegerField(required=True)
class Meta:
model = User
def save(self, commit=True):
if not commit:
raise NotImplementedError("Can't create User and UserProfile without database save")
user = super(UserCreateForm, self).save(commit=True)
user_profile = UserProfile(user=user, job_title=self.cleaned_data['job_title'],
age=self.cleaned_data['age'])
user_profile.save()
# notice: multiple returns
return user, user_profile
A few questions about the differences:
Why doesn't my code work if I end it like this:
.
if commit:
user.save()
business.save()
return user
I'm not using cleaned_data, is that okay?
What is the purpose of the if not commit block in the original code?
Most importantly, is this a "legitimate way" to handle user registration that requires an automatic object-relation on creation?
cleaned_data is the dictionary of data after all validation in every field in that form. Now you can decide whether to rely on it or not(preferably you should).So as a pseudocode we could say cleaned_data + errors will be all fields.
commit is used to decide whether it should commit to db(write). From the above code, to add a related model object like profile, the original object(User) has to be created first.Thats why it make force commit.
To add a related object on object creation, there are multiple ways like post_save signals, override model save, override form save etc.So you are using one of good approach, I would say.
Good day SO!
Recently I've started working on Django, got myself a situation which I can't find the right solution on the web to solve it. So I've got a little question about URL reversing on a success. Currently when an user successfully creates an account, the user gets reversed to a profile based on the user_id which just got created:
class Create(CreateView):
form_class = UserCreateForm # inherits from django's UserCreationForm
def get_success_url(self):
return reverse('users:profile', kwargs={'pk': self.object.pk})
This is working properly. Now I created a profile module with a OneToOneField
to the django.auth.models User model. When creating a new account, a signal is send to the create_profile_on_registration method.
#receiver(post_save, sender=User)
def create_profile_on_registration(sender, created, instance, **kwargs):
...
This is also working properly, a new profile is created on user account registration. Now I would like to reverse the user to the new created profile_id instead of the user_id. However, I cant figure out exactly how to get this properly to work. Can you give me a little push in the right direction on how to approach this issue? I can't match up the right google search words or find any examples which explains or shows how to achieve this properly.
Thanks in advance!
When you create a one to one field to your user model,
class Profile(models.Model):
user = models.OneToOneField(User)
you can access the user from the profile
profile.user
and you can also access the profile from the user
user.profile
In your view, self.object is the user, so self.object.profile.id will give you the profile id.
I am trying to create custom fields for users to enter on signup with django-allauth. I have referred to several posts about this, but I am not able to get my custom form to save to my database. I do get a combined form on my signup.html page with username, password1 and 2, email and my extra fields of city and school, but I am not able to save the extra fields to the database. I have run syncdb and can see my User Profile table in the admin area.
This advice is the closest I have come to the answer but I do not understand how to implement it: "You can't use UserProfileForm to the allauth.SIGNUP_FORM_CLASS. You need to extend it from SignUpForm and write a save method which will accept the newly created user as the only parameter," from this post:
Custom registration form for use with django-allauth
I have also attempted to integrate advice on this form these posts:
Django Allauth not saving custom form
How to customize user profile when using django-allauth
This is my code:
Models.py
from django.db import models
from django.contrib.auth.models import User
class UserProfile(models.Model):
# A required line - links a UserProfile to User.
user = models.OneToOneField(User)
# The additional attributes we wish to include.
school = models.CharField(max_length=128)
city = models.CharField(max_length=128)
def __unicode__(self):
return self.user.username
Forms.py
from django import forms
from django.contrib.auth.models import User
from myapp.models import UserProfile
from django.forms.widgets import HiddenInput
class UserProfileForm(forms.ModelForm):
class Meta:
model = UserProfile
fields = ('city', 'school')
def signup(self, request, user):
user=User.objects.get(email=request.email)
city=request.POST.get('city','')
school=request.POST.get('school','')
userprofile_obj = UserProfile(user=user,city=city,school=school)
userprofile_obj.save()
Settings.py
ACCOUNT_SIGNUP_FORM_CLASS = 'myapp.forms.UserProfileForm'
My template is the basic Signup.html from the django-allauth templates and I do not have a view made for this, although I attempted to make one from the tangowithdjango user authentication section register view, and this gave similar behavior (not saving to the database).
Thanks,
Kelly
Not sure if this is still an active question/issue for the original poster: if so, and for anyone else who comes across this, a few things to correct to at least move in the right direction:
I don't see an __init__() method that calls the superclass? E.g.:
def __init__(self, *args, **kwargs):
super(SignupForm, self).__init__(*args, **kwargs)
use the user parameter to the signup method. It should be populated; don't reload it.
Ensure the two objects are linking correctly (I didn't use Django to build my profile table so YMMV but I set user.profile = Profile(...); then execute user.profile.save() at the end of my signup() method.
get the values to place into the profile from the form cleaned_data (e.g. self.cleaned_data['city'] not the POST.
Then start debugging: is your signup() method firing? What does it get? What happens when you execute the profile.save() method?
I am trying to write custom get_profile() function which should create user profile for users who are registered thru admin or any other way where post_save was not called.
How can I start this?
I guess that you have a model to handle user profile like this:
class UserProfile(models.Model):
"""Contains user profile fields not provided by User model"""
user = models.OneToOneField(User)
# Defined User profile fields like picture, phone, etc
So adding following line (maybe in your models.py after UserProfile model):
User.profile = property(lambda u: UserProfile.objects.get_or_create(user=u)[0])
Allows access to the profile of a user (i.e. in templates: {% user.profile.phone %}) by creating it if not exists.
This is the way I solved in my site a problem like you describe.
Hope this helps
I am a bit confused. Are you trying to let users create account and sign in? Then use django-registration which is easy and works out of the box.