I have a simple question. This is my profile:
class Profile(models.Model):
user = models.ForeignKey(User, unique=True)
born = models.DateTimeField('born to')
photo = models.ImageField(upload_to='profile_photo')
I want to create a registration form with these fields (from User and Profile models):
username
first_name
last_name
born
photo
These fields are required.
How do I do that?
How does get_profile() work in a template for this issue?
Thank you :)
Setup
Are you using the django-profiles and django-registration projects? If not, you should—much of this code has already been written for you.
Profile
Your user profile code is:
class Profile(models.Model):
user = models.ForeignKey(User, unique=True)
born = models.DateTimeField('born to')
photo = models.ImageField(upload_to='profile_photo')
Have you correctly setup this profile in your Django settings? You should add this if not, substituting yourapp for your app's name:
AUTH_PROFILE_MODULE = "yourapp.Profile"
Registration Form
django-registration comes with some default registration forms but you specified you wanted to create your own. Each Django form field defaults to required so you should not need to change that. The important part is just making sure to handle the existing registration form fields and adding in the profile creation. Something like this should work:
from django import forms
from registration.forms import RegistrationForm
from yourapp.models import Profile
from registration.models import RegistrationProfile
class YourRegistrationForm(RegistrationForm):
born = forms.DateTimeField()
photo = forms.ImageField()
def save(self, profile_callback=None):
new_user = RegistrationProfile.objects.create_inactive_user(username=self.cleaned_data['username'],
password=self.cleaned_data['password1'],
email = self.cleaned_data['email'])
new_profile = Profile(user=new_user, born=self.cleaned_data['born'], photo=self.cleaned_data['photo'])
new_profile.save()
return new_user
Bringing it together
You can use the default django-registration templates and views, but will want to pass them your form in urls.py:
from registration.backends.default import DefaultBackend
from registration.views import activate
from registration.views import register
# ... the rest of your urls until you find somewhere you want to add ...
url(r'^register/$', register,
{'form_class' : YourRegistrationForm, 'backend': DefaultBackend},
name='registration_register'),
Related
I am trying to save user form data to database. I tried in these way but its not save anything i'm getting None value.
views.py
from django.shortcuts import render, redirect
from .forms import Signup
from .models import Signup
def Sign_up(request):
username = request.POST.get('username')
mobile_number = request.POST.get('mobile_number')
email = request.POST.get('email')
password = request.POST.get('password')
address = request.POST.get('address')
print("Hello form is submitted")
print(username)
print(mobile_number)
print(email)
print(password)
print(address)
post = Signup(username= username, mobile_number=mobile_number,email=email,
password=password, address=address)
post.save()
return render(request, 'sign_up/sign_up.html',{})
models.py
from django.db import models
class Signup(models.Model):
username = models.CharField(max_length=300, default='SOME STRING',
blank=True, null=True)
mobile_number = models.CharField(max_length=12, blank=True, null=True)
email = models.EmailField(max_length=50, blank=True, null=True)
password = models.CharField(max_length=50, blank=True, null=True)
address = models. CharField(max_length=100, blank=True, null=True)
print("Hi")
def __str__(self):
return self.username or ''
def __str__(self):
return self.mobile_number or ''
def __str__(self):
return self.email or ''
def __str__(self):
return self.password or ''
def __str__(self):
return self.address or ''
forms.py
from django import forms
from .models import Signup
class SignupForm(forms.Form):
username = forms.CharField(max_length=30, required=True)
mobile_number = forms.CharField(max_length=12)
email = forms.EmailField(max_length=50, required=True)
password = forms.CharField(max_length=50, required=True)
address = forms.CharField(max_length=100)
I'm getting like this
Django version 2.2, using settings 'project.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CTRL-BREAK.
Hello form is submitted
None
None
None
None
None
[01/May/2019 22:39:18] "GET /signup/? HTTP/1.1" 200 3360
You are creating a Signup object in a wrong manner, create it like this:
you can create model form instead like this:
class SignupForm(forms.ModelForm):
class Meta:
model = Signup
fields = ('username', )#pass fields here
and in your view you get the values entered by user like this:
formToSave = SignupForm(request.POST,request.FILES)
if formToSave.is_valid():
product = formToSave.save()
but if you don't want to use the model form you can create the object Signup and then save it as you are doing but make sure before creating the object you are getting all the form values in your views by printing them(as you are already doing)
post = Signup.objects.create(username= username, mobile_number=mobile_number,email=email,
password=password, address=address)
then save it
post.save()
If you are using this model in production be careful.
Storing non hashed password is a really bad practice.
I think you are trying to reinvent the wheel here.
There is several ways to manage the User model in django.
If you decide to create your own User system, please read this first:
https://docs.djangoproject.com/en/2.2/topics/auth/customizing/
Extending the existing User model
There are two ways to extend the default User model without substituting your own model. If the changes you need are purely behavioral, and don’t require any change to what is stored in the database, you can create a proxy model based on User. This allows for any of the features offered by proxy models including default ordering, custom managers, or custom model methods.
If you wish to store information related to User, you can use a OneToOneField to a model containing the fields for additional information. This one-to-one model is often called a profile model, as it might store non-auth related information about a site user. For example you might create an Employee model:
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
department = models.CharField(max_length=100)
Using a custom user model when starting a project
If you’re starting a new project, it’s highly recommended to set up a custom user model, even if the default User model is sufficient for you. This model behaves identically to the default user model, but you’ll be able to customize it in the future if the need arises:
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
Don’t forget to point AUTH_USER_MODEL to it. Do this before creating any migrations or running manage.py migrate for the first time.
Also, register the model in the app’s admin.py
Further in the Doc
Specifying a custom user model
When you start your project with a custom user model, stop to consider
if this is the right choice for your project.
Keeping all user related information in one model removes the need for
additional or more complex database queries to retrieve related
models. On the other hand, it may be more suitable to store
app-specific user information in a model that has a relation with your
custom user model. That allows each app to specify its own user data
requirements without potentially conflicting or breaking assumptions
by other apps. It also means that you would keep your user model as
simple as possible, focused on authentication, and following the
minimum requirements Django expects custom user models to meet.
If you use the default authentication backend, then your model must
have a single unique field that can be used for identification
purposes. This can be a username, an email address, or any other
unique attribute. A non-unique username field is allowed if you use a
custom authentication backend that can support it.
The easiest way to construct a compliant custom user model is to
inherit from AbstractBaseUser. AbstractBaseUser provides the core
implementation of a user model, including hashed passwords and
tokenized password resets. You must then provide some key
implementation details
As a reference here is the doc page about user authentication: https://docs.djangoproject.com/en/2.2/topics/auth/
If you want to choose the default django User system: https://docs.djangoproject.com/en/2.2/topics/auth/default/ and more info about the default user api : https://docs.djangoproject.com/en/2.2/ref/contrib/auth/
I know, this question has been already asked many times in SO, but most of the answers I read were either outdated (advising the now deprecated AUTH__PROFILE_MODULE method), or were lacking of a concrete example.
So, I read the Django documentation [1,2], but I lack a real example on how to use it properly.
In fact, my problem comes when a new user is created (or updated) through a form. The user is obviously created but, the fields from the extension are all unset. I know that the Django documentation is stating that:
These profile models are not special in any way - they are just Django models that happen to have a one-to-one link with a User model. As such, they do not get auto created when a user is created, but a django.db.models.signals.post_save could be used to create or update related models as appropriate.
But, I don't know how to do it in practice (should I add a a receiver and if 'yes', which one).
For now, I have the following (taken from the documentation for the sake of brevity):
File models.py
from django.contrib.auth.models import User
class Employee(models.Model):
user = models.OneToOneField(User)
department = models.CharField(max_length=100)
File admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import Employee
# Define an inline admin descriptor for Employee model
class EmployeeInline(admin.StackedInline):
model = Employee
can_delete = False
verbose_name_plural = 'employee'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (EmployeeInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
File forms.py
class SignupForm(account.forms.SignupForm):
department = forms.CharField(label="Department", max_length=100)
class SettingsForm(account.forms.SignupForm):
department = forms.CharField(label="Department", max_length=100)
Then, in my code, I use it like this:
u = User.objects.get(username='fsmith')
freds_department = u.employee.department
But, Signup and Settings forms do not operates as expected and new values for the departement is not recorded.
Any hint is welcome !
I have looked at all the answers but none does really hold the solution for my problem (though some of you gave me quite good hints for looking in the right direction). I will summarize here the solution I have found to solve my problem.
First of all, I have to admit I didn't tell everything about my problem. I wanted to insert extra fields in the User model and use other apps such as the default authentication scheme of Django. So, extending the default User by inheritance and setting AUTH_USER_MODEL was a problem because the other Django applications were stopping to work properly (I believe they didn't use user = models.OneToOneField(settings.AUTH_USER_MODEL) but user = models.OneToOneField(User)).
As, it would have been too long to rewrite properly the other applications I am using, I decided to add this extra field through a One-to-One field. But, the documentation miss several points that I would like to fill in the following.
So, here is a complete example of adding an extra field to the User model with other applications using the same model.
First, write the description of the model gathering the extra fields that you want to add to your models.py file:
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
extra_field = models.CharField(max_length=100)
Then, we need to trigger the addition of an object UserProfile each time a User is created. This is done through attaching this code to the proper signal in the receiver.py file:
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver
from my_user_profile_app.models import UserProfile
#receiver(post_save, sender=User)
def handle_user_save(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
Now, if you want to be able to modify it through the administration interface, just stack it with the usual UserAdmin form in the admin.py file.
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User
from my_user_profile_app.models import UserProfile
# Define an inline admin descriptor for UserProfile model
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (UserProfileInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Then, it is time now to try to mix this extra field with the default Django authentication application. For this, we need to add an extra field to fill in the SignupForm and the SettingsForm through inheritance in the forms.py file:
import account.forms
from django import forms
class SignupForm(account.forms.SignupForm):
extra_field = forms.CharField(label="Extra Field", max_length=100)
class SettingsForm(account.forms.SignupForm):
extra_field = forms.CharField(label="Extra Field", max_length=100)
And, we also need to add some code to display and get properly the data that you have been added to the original User model. This is done through inheritance onto the SignupView and the SettingsView views in the views.py file:
import account.views
from my_user_profile_app.forms import Settings, SignupForm
from my_user_profile_app.models import UserProfile
class SettingsView(account.views.SettingsView):
form_class = SettingsForm
def get_initial(self):
initial = super(SettingsView, self).get_initial()
initial["extra_field"] = self.request.user.extra_field
return initial
def update_settings(self, form):
super(SettingsView, self).update_settings(form)
profile = self.request.user.userprofile
profile.extra_field = form_cleaned_data['extra_field']
profile.save()
class SignupView(account.views.SignupView):
form_class = SignupForm
def after_signup(self, form):
profile = self.created_user.userprofile
profile.extra_field = form_cleaned_data['extra_field']
profile.save()
super(SignupView, self).after_signup(form)
Once everything is in place, it should work nicely (hopefully).
I struggled with this topic for about a year off and on until I finally found a solution I was happy with, and I know exactly what you mean by "there is a lot out there, but it doesn't work". I had tried extending the User model in different ways, I had tried the UserProfile method, and some other 1-off solutions as well.
I finally figured out how to simply extend the AbstractUser class to create my custom user model which has been a great solution for many of my projects.
So, let me clarify one of your comments above, you really shouldn't be creating a link between 2 models, the generally accepted "best" solution is to have one model which is inherited from AbstractUser or AbstractBaseUser depending on your needs.
One tricky thing that got me was that "Extending the User Model" did not get me where I wanted and I needed to Substitute the User Model, which I'm sure you've seen/read multiple times, but possibly not absorbed it (at least I know I didn't).
Once you get the hang of it, there's really not that much code and it's not too complicated either.
# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
'''
Here is your User class which is fully customizable and
based off of the AbstractUser from auth.models
'''
my_custom_field = models.CharField(max_length=20)
def my_custom_model_method(self):
# do stuff
return True
There are a couple things to look out for after this, some of which came up in django 1.7.
First of all, if you want the admin page to look like it did before, you have to use the UserAdmin
# admin.py
from django.contrib import admin
from django.contrib.auth import get_user_model
from django.contrib.auth.admin import UserAdmin
# Register your models here.
admin.site.register(get_user_model(), UserAdmin)
The other thing is that if you're wanting to import the User class in a models file, you have to import it from the settings and not with get_user_model(). If you run into this, it's easy to fix, so I just wanted to give you a heads up.
You can check out my seed project I use to start projects to get a full but simple project that uses a Custom User Model. The User stuff is in the main app.
From there all the Registration and Login stuff works the same way as with a normal Django User, so I won't go into detail on that topic. I hope this helps you as much as it has helped me!
I try to avoid to extend the user model as explained in the django docs.
I use this:
class UserExtension(models.Model):
user=models.OneToOneField(User, primary_key=True)
... your extra model fields come here
Docs of OneToOneField: https://docs.djangoproject.com/en/1.7/topics/db/examples/one_to_one/
I see these benefits:
the same pattern works for other models (e.g. Group)
If you have N apps, every app can extend the model on his own.
Creating the UserExtension should be possible without giving parameters. All fields must have sane defaults.
Then you can create a signal handler which creates UserExtension instances if a user gets created.
I prefer extend the User model. For example:
class UserProfile(User):
def __unicode__(self):
return self.last_name + self.first_name
department = models.CharField(max_length=100)
class SignupForm(forms.Form):
username = forms.CharField(max_length=30)
first_name = forms.CharField(max_length=30)
last_name = forms.CharField(max_length=30)
department = forms.CharField(label="Department", max_length=100)
To save the data
form = UserRegistrationForm(request.POST)
if form.is_valid():
client = UserProfile()
client.username = username
client.set_password(password)
client.first_name = first_name
client.department = department
client.save()
check how are you saving the data after validate the form
This question is a follow-up to the solution explained by Muki here:
Problem in adding custom fields to django-registration
I have installed and have been successfully using the Django-registration package. By default, when you create an account using this package, it asks for your username, email address and password. I want it to also ask for (optional) first name + last name. Muki's answer at the link above explains how to do so.
However, Muki left out what should go into the file that he creates in the custom/forms.py. I need to know what the name of the class I should create in here is and what the field definitions should look like.
Can someone please post a sample forms.py that I can use to accomplish what I'm trying to do?
If your custom backend is in the custom folder, then custom/forms.py could be something like this:
from django import forms
from registration.forms import RegistrationForm
class RegistrationFormWithName(RegistrationForm):
first_name = forms.CharField(required=False)
last_name = forms.CharField(required=False)
This adds your two optional fields to the default registration form. To tell your custom backend to use this new form instead of the default you need to change the get_form_class method in custom/__init__.py Muki's answer explains how to do that.
Of course, you'll also need to handle saving the data from the first_name and last_name fields.
Edit:
Your custom/__init__.py needs to look something like this:
from registration.backends.default import DefaultBackend
from registration.backends.custom.forms import RegistrationFormWithName
class CustomBackend(DefaultBackend):
def get_form_class(self, request):
return RegistrationFormWithName
And custom/urls.py needs a line like this:
url(r'^register/$', register, {'backend': 'registration.backends.custom.CustomBackend'}, name='registration_register'),
Change the name of the CustomBackend class in both files to whatever you're calling your new backend.
Have a look at the default backend source to get an idea of the other methods you can override. Hope that helps.
This link explains the process well and works with django-registration 1.0
here are a few extra pointers in addition to the above code.
To update the first name change this in the models.py
def user_registered_callback(sender, user, request, **kwargs):
profile = ExUserProfile(user = user)
profile.is_human = bool(request.POST["is_human"])
user.first_name = request.POST["firstname"]
user.save()
profile.save()
user_registered.connect(user_registered_callback)
and in the forms.py file
class ExRegistrationForm(RegistrationForm):
is_human = forms.BooleanField(label = "Are you human?:")
firstname = forms.CharField(max_length=30)
lastname = forms.CharField(max_length=30)
finally to see the changes on the form create an appropriate template. The profile can be seen in the admin by creating a file called admin.py in your app and write the following code
from django.contrib import admin
from django.contrib.auth.models import User
from django.contrib.auth.admin import UserAdmin
from prof.models import ExUserProfile
admin.site.unregister(User)
class UserProfileInline(admin.StackedInline):
model = ExUserProfile
class UserProfileAdmin(UserAdmin):
inlines = [ UserProfileInline, ]
admin.site.register(User, UserProfileAdmin)
I have a Django application with some fairly common models in it: UserProfile and Organization. A UserProfile or an Organization can both have 0 to n emails, so I have an Email model that has a GenericForeignKey. UserProfile and Organization Models both have a GenericRelation called emails that points back to the Email model (summary code provided below).
The question: what is the best way to provide an Organization form that allows a user to enter organization details including 0 to n email addresses?
My Organization create view is a Django class-based view. I'm leaning towards creating a dynamic form and an enabling it with Javascript to allow the user to add as many email addresses as necessary. I will render the form with django-crispy-forms and django-floppyforms for display on a site using Twitter Bootstrap.
I've thought about doing this with a BaseGenericInlineFormset embedded within the form, but this seems like overkill for email addresses. Embedding a formset in a form delivered by a class-based view is cumbersome too.
Note that the same issue occurs with the Organization fields phone_numbers and locations.
Code
emails.py:
from django.db import models
from parent_mixins import Parent_Mixin
class Email(Parent_Mixin,models.Model):
email_type = models.CharField(blank=True,max_length=100,null=True,default=None,verbose_name='Email Type')
email = models.EmailField()
class Meta:
app_label = 'core'
organizations.py:
from emails import Email
from locations import Location
from phone_numbers import Phone_Number
from django.contrib.contenttypes import generic
from django.db import models
class Organization(models.Model):
active = models.BooleanField()
duns_number = models.CharField(blank=True,default=None,null=True,max_length=9) # need to validate this
emails = generic.GenericRelation(Email,content_type_field='parent_type',object_id_field='parent_id')
legal_name = models.CharField(blank=True,default=None,null=True,max_length=200)
locations = generic.GenericRelation(Location,content_type_field='parent_type',object_id_field='parent_id')
name = models.CharField(blank=True,default=None,null=True,max_length=200)
organization_group = models.CharField(blank=True,default=None,null=True,max_length=200)
organization_type = models.CharField(blank=True,default=None,null=True,max_length=200)
phone_numbers = generic.GenericRelation(Phone_Number,content_type_field='parent_type',object_id_field='parent_id')
taxpayer_id_number = models.CharField(blank=True,default=None,null=True,max_length=9) # need to validate this
class Meta:
app_label = 'core'
parent_mixins.py
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes import generic
from django.db import models
class Parent_Mixin(models.Model):
parent_type = models.ForeignKey(ContentType,blank=True,null=True)
parent_id = models.PositiveIntegerField(blank=True,null=True)
parent = generic.GenericForeignKey('parent_type', 'parent_id')
class Meta:
abstract = True
app_label = 'core'
you can try using .split(), with this your form would look easier and users wont have to keep on adding text fields.
What you can do is, make one textbox where user can add multiple emails and separate them by a coma. and then in your views you can do this
email = emails.split(',')
for i in emails:
#assign email and save.
in case of having an email type
it might still be a good idea to build a system like that. what you can do is
abc#gmail.com-work,xyz#k.com-school
and then you can split them like this
email-type=email.split(',')
for i in email-type:
email=i.split('-')[0]
if i.split('-')[1]:
type=i.split('-')[1]
else:
#give it a default type
I'm trying to add fields to the User model and add them to the admin page. There is a recommended method in the django docs here:
https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
So, I created a OneToOne field for my new model:
from django.contrib.auth.models import User
class UserProfile(models.Model):
user = models.OneToOneField(User)
designs = models.ManyToManyField('Design', blank=True)
prints = models.ManyToManyField('Print', blank=True)
rating = models.IntegerField(null=True, blank=True)
reliability = models.IntegerField(null=True, blank=True)
av_lead_time = models.IntegerField(null=True, blank=True)
Added an AUTH_PROFILE_MODULE to settings.py:
AUTH_PROFILE_MODULE = 'website.UserProfile'
Tried to add the UserProfile fields to the admin page:
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from website.models import UserProfile
from django.contrib.auth.models import User
# Define an inline admin descriptor for UserProfile model
# which acts a bit like a singleton
class UserProfileInline(admin.StackedInline):
model = UserProfile
can_delete = False
verbose_name_plural = 'profile'
# Define a new User admin
class UserAdmin(UserAdmin):
inlines = (UserProfileInline, )
# Re-register UserAdmin
admin.site.unregister(User)
admin.site.register(User, UserAdmin)
Now, when I try to access a registered user via the admin menu, I get:
Caught DoesNotExist while rendering: User matching query does not exist.
In template /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/includes/fieldset.html, error at line 19
19 {{ field.field }}
And when I try to add a new user via the admin menu, I get:
Caught DoesNotExist while rendering: User matching query does not exist.
In template /usr/local/lib/python2.7/dist-packages/django/contrib/admin/templates/admin/includes/fieldset.html, error at line 19
19 {{ field.field }}
Why doesn't it recognise that particular field?
Edit: After looking on the full error message I can see the error is not solely related to extending User. The error happens when rendering checkboxes and corresponding labels that are used to assign prints to UserProfile you are editing/adding. Django admin is calling Print.__unicode__ for rendering label for each Print instance, which in turn access (on line 33 of /threedee/website/models.py) the Print's "printer" attribute which is a foreign key to User. And for some reason one of the Prints does have invalid printer value which doesn't point to any User.
Can't really tell what is really happening here without seeing the Print model, I recommend you checking the Print database table (should be named website_print) and find if there is anything unusual (are you using PostgreSQL?). If you are not having any important data there, truncating whole Print table should do the trick.
This is my old answer which you should still follow but it's not related to the error you are experiencing:
I would just comment on others answers but there doesn't seem to be a way of doing that for me. You need to combine both Alexey Sidorov's and Like it's answers:
First use django shell to create UserProfile instances for existing users - just run commads provided by Like it's answer in the shell (python manage.py shell).
After that you should setup signal that will automatically create UserProfile for each new user according to answer from alexey-sidorov.
Add this to models.py, after UserProfile class.
from django.db.models.signals import post_save
def create_user_profile(sender, instance, created, **kwargs):
if created:
UserProfile.objects.create(user=instance)
post_save.connect(create_user_profile, sender=User)
more info https://docs.djangoproject.com/en/dev/topics/auth/#storing-additional-information-about-users
Add UserProfile entry for you existing users:
from django.contrib.auth.models import User
from website.models import UserProfile
for user in User.objects.all():
profile = UserProfile.objects.get_or_create(user = user)
and create profile for new user as well.
use signals for what.