I have to store Customer information in a Customer table. We don't need to store their username and password. But to create customer groups and users, I'm using django's User and Group Models. Here is the customer Model which I use to store it's basic information.
class Customer(models.Model):
"""
The Customer
"""
UID = models.TextField(blank=True, null=True, db_index=True)
fk_user = models.ForeignKey(User, primary_key=False)
fk_details = models.ForeignKey(UserDetails, primary_key=False)
fk_contact_details = models.ForeignKey(ContactDetails, primary_key=False)
...
This is a class method which creates user object for which later I'm using it to store customer information :
from django.contrib.auth.models import User
def create_user(self, req_dict):
'''
Create a new User
'''
try:
user=User.objects.create_user(**req_dict)
user.save()
except:
return None
return user
But this code is throwing an IntegrityError which is because we are not passing username in the req_dict
req_dict = {'first_name': u'John', 'last_name': u'Smith', 'email': u'john.smith#xyz.com'}
What's the way to store username optional while creating a new user?
If you want to use django.contrib.auth you can't make the username field optional. You always have to put a value in the database.
In order to bypass that, I suggest you generate a value in create_user() for username. You could either use a random value, or create a username from email. Just make sure that it's unique.
You could make a pre_save signal to just provide default values
pre_save.connect(give_default_username, sender=User)
def give_default_username(sender, instance, *args, **kwargs):
instance.username = 'default'
Any time a user object's save method is invoked, it will go through this method first to append your required values before continuing with the save method.
I agree with #zanderle that it would be better to generate some username for your users. Maybe you can user their UID, or email, or something like this.
pre_save signal could solve your problem, but, as for me, it makes you system more implicit, because your models will be not consistent with your database.
Another way - to create some Default user for anonymous users. So, every db record will have user assignment and you will not force your customers to 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 want to increase the length of the username in django from 30 to around 80, I know it may be duplicate question but the previous answers are not working, for example https://kfalck.net/2010/12/30/longer-usernames-for-django
this is for Django 1.2.
Did anyone try similar hack for Django>1.5
Thanks in advance
In Django 1.5 and above, the recommended approach would be to create a custom user model. Then you can make the username field exactly as you want.
I had the same problem few days ago. Finally, I ended just with cutting off first 30 characters of the (old) username (into the new database table), and adding a custom authentication backend that will check the email instead of user name. Terrible hack I know, and I'm planning to fix it as soon as I have some time. The idea is following:
I already have a model class that has one-to-one relation with djangos auth.User. I will add another field there called full_username.
class MyCustomUserModel(models.Model):
user = models.OneToOneField(
settings.AUTH_USER_MODEL, related_name="custom_user")
full_username = models.CharField(max_length=80, ...)
...
Then, I'll add another custom authentication backend that will check this field as username. It would look something like this:
from django.contrib.auth.backends import ModelBackend
class FullUsernameAuthBackend(ModelBackend):
def authenticate(self, username=None, password=None, **kwargs):
UserModel = get_user_model()
if username is None:
username = kwargs.get(UserModel.USERNAME_FIELD)
try:
user = UserModel._default_manager.filter(custom_user__full_username=username)
# If this doesn't work, will use (the second case):
# user = MyCustomUserModel.objects.filter(full_username=username).user
if user.check_password(password):
return user
except UserModel.DoesNotExist:
# Adding exception MyCustomUserModel.DoesNotExist in "(the second case)"
# Run the default password hasher once to reduce the timing
# difference between an existing and a non-existing user (#20760).
UserModel().set_password(password)
After this, you need to change settings.py:
AUTHENTICATION_BACKENDS = (
"....FullUsernameAuthBackend",
# I will have the email auth backend here also.
)
I hope that it will work.
Custom User Models are a huge change to make and aren't always compatible with apps. I solved it by running this very pragmatic migration. Note this only solves it at the database level.
migrations.RunSQL("alter table auth_user alter column username type varchar(254);")
I have a Django model:
class Project(models.Model):
user = models.ForeignKey(User)
zipcode = models.CharField(max_length=5)
module = models.ForeignKey(Module)
In my views.py:
def my_view(request):
...
project = Project.objects.create(
user=request.user,
product=product_instance,
...
)
project.save()
I want to be able to save user as an authenticated user OR an AnonymousUser (which I can update later). However, if I'm not logged in I get this error:
ValueError: Cannot assign "<django.utils.functional.SimpleLazyObject object at 0x1b498d0>": "Project.user" must be a "User" instance.
I guess that Django won't save the AnonymousUser because it is not a User as defined in the User model. Do I need to add the anonymous user to the User model, or am I missing something?
Any assistance much appreciated.
The user field is a ForeignKey. That means it must reference some user.
By definition, the AnonymousUser is no user: in Django, there is no AnonymousUserA and AnonymousUserB. They're all the same: AnonymousUser.
Conclusion: you can't put an AnonymousUser in a User ForeignKey.
The solution to your issue is pretty straightforward though: when the User is anonymous, just leave the field blank. To do that, you'll need to allow it:
user = models.ForeignKey(User, blank = True, null = True)
I have a User Profile which is currently shown in the Admin via a Stacked Inline. However because I have fields such as last_name_prefix and last_name_suffix (for foreign names such as Piet van Dijk to cover proper sorting by last name) I would like to be able interleave the user profile fields with the normal change user fields. So in the Change User admin interface it would appear like this:
First Name:
Last Name Prefix:
Last Name
Last Name Suffix:
I have tried this solution: http://groups.google.com/group/django-users/browse_thread/thread/bf7f2a0576e4afd1/5e3c1e98c0c2a5b1. But that just created extra fields in the user form that weren't actually coming from the user profile (they stayed empty even though they should get values from the user profile).
Could someone explain to me if this could be done and how?
Thanks very much!
I'm pretty sure you'd need to overwrite normal User admin.
What I would actually do is create a special forms.ModelForm for UserProfile called, say UserProfileAdminForm which included fields from the User model as well. Then you'd register UserProfile for admin and the save function for the UserProfileAdminForm would capture the user-specific fields and either create or update the User record (This is left as an exercise to the OP).
More info
When I say add more fields to a form, I mean manually add them:
class UserProfileAdminForm(forms.ModelForm):
username = forms.CharField(...)
email = forms.EmailField(...)
first_name = ...
last_name = ...
def __init__(self, *args, **kwargs):
super(UserProfileAdminForm, self).__init__(*args, **kwargs)
profile = kwargs.get('instance', None)
if profile and profile.user:
self.user = profile.user
self.fields['username'].initial = self.user.username
self.fields['last_name'].initial = ...
...
class Meta:
model = UserProfile
This question has been solved by the new Django version 1.5: https://docs.djangoproject.com/en/1.5/topics/auth/customizing/#auth-custom-user.
I need to patch the standard User model of contrib.auth by ensuring the email field entry is unique:
User._meta.fields[4].unique = True
Where is best place in code to do that?
I want to avoid using the number fields[4]. It's better to user fields['email'], but fields is not dictionary, only list.
Another idea may be to open a new ticket and upload a patch with new parameter inside settings.py:
AUTH_USER_EMAIL_UNIQUE = True
Any suggestions on the most correct way to achieve email address uniqueness in the Django User model?
Caution:
The code below was written for an older version of Django (before Custom
User Models were introduced). It contains a race condition, and
should only be used with a Transaction Isolation Level of SERIALIZABLE
and request-scoped transactions.
Your code won't work, as the attributes of field instances are read-only. I fear it might be a wee bit more complicated than you're thinking.
If you'll only ever create User instances with a form, you can define a custom ModelForm that enforces this behavior:
from django import forms
from django.contrib.auth.models import User
class UserForm(forms.ModelForm):
class Meta:
model = User
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
if email and User.objects.filter(email=email).exclude(username=username).exists():
raise forms.ValidationError(u'Email addresses must be unique.')
return email
Then just use this form wherever you need to create a new user.
BTW, you can use Model._meta.get_field('field_name') to get fields by name, rather than by position. So for example:
# The following lines are equivalent
User._meta.fields[4]
User._meta.get_field('email')
UPDATE
The Django documentation recommends you use the clean method for all validation that spans multiple form fields, because it's called after all the <FIELD>.clean and <FIELD>_clean methods. This means that you can (mostly) rely on the field's value being present in cleaned_data from within clean.
Since the form fields are validated in the order they're declared, I think it's okay to occasionally place multi-field validation in a <FIELD>_clean method, so long as the field in question appears after all other fields it depends on. I do this so any validation errors are associated with the field itself, rather than with the form.
What about using unique_together in a "different" way? So far it works for me.
class User(AbstractUser):
...
class Meta(object):
unique_together = ('email',)
Simply use below code in models.py of any app
from django.contrib.auth.models import User
User._meta.get_field('email')._unique = True
In settings module:
# Fix: username length is too small,email must be unique
from django.contrib.auth.models import User, models
User._meta.local_fields[1].__dict__['max_length'] = 75
User._meta.local_fields[4].__dict__['_unique'] = True
It's amazing, but I found a best solution for me!
django-registration have form with checking uniqueness of email field: RegistrationFormUniqueEmail
example of usage here
Your form should look something like this.
def clean_email(self):
email = self.cleaned_data.get('email')
username = self.cleaned_data.get('username')
print User.objects.filter(email=email).count()
if email and User.objects.filter(email=email).count() > 0:
raise forms.ValidationError(u'This email address is already registered.')
return email
To ensure a User, no matter where, be saved with a unique email, add this to your models:
#receiver(pre_save, sender=User)
def User_pre_save(sender, **kwargs):
email = kwargs['instance'].email
username = kwargs['instance'].username
if not email: raise ValidationError("email required")
if sender.objects.filter(email=email).exclude(username=username).count(): raise ValidationError("email needs to be unique")
Note that this ensures non-blank email too. However, this doesn't do forms validation as would be appropriated, just raises an exception.
Django has a Full Example on its documentation on how to substitute and use a Custom User Model, so you can add fields and use email as username.
One possible way to do this is to have a pre-save hook on the User object and reject the save of the email already exists in the table.
I think that the correct answer would assure that uniqueness check was placed inside the database (and not on the django side). Because due to timing and race conditions you might end with duplicate emails in the database despite having for example pre_save that does proper checks.
If you really need this badly I guess you might try following approach:
Copy User model to your own app, and change field email to be unique.
Register this user model in the admin app (using admin class from django.contrib.auth.admin)
Create your own authentication backend that uses your model instead of django one.
This method won't make email field unique at the database level, but it's worth trying.
Use a custom validator:
from django.core.exceptions import ValidationError
from django.contrib.auth.models import User
def validate_email_unique(value):
exists = User.objects.filter(email=value)
if exists:
raise ValidationError("Email address %s already exists, must be unique" % value)
Then in forms.py:
from django.contrib.auth.models import User
from django.forms import ModelForm
from main.validators import validate_email_unique
class UserForm(ModelForm):
#....
email = forms.CharField(required=True, validators=[validate_email_unique])
#....
Add the below function in any of the models.py file. Then run makemigrations and migrate. Tested on Django1.7
def set_email_as_unique():
"""
Sets the email field as unique=True in auth.User Model
"""
email_field = dict([(field.name, field) for field in MyUser._meta.fields])["email"]
setattr(email_field, '_unique', True)
#this is called here so that attribute can be set at the application load time
set_email_as_unique()
Since version 1.2 (May 11th, 2015) there has been a way to dynamically import any chosen registration form using the settings option REGISTRATION_FORM.
So, one could use something like this:
REGISTRATION_FORM = 'registration.forms.RegistrationFormUniqueEmail'
This is documented here.
And here's the link to the changelog entry.
Django does not allow direct editing User object but you can add pre_save signal and achieve unique email. for create signals u can follow https://docs.djangoproject.com/en/2.0/ref/signals/. then add the following to your signals.py
#receiver(pre_save, sender=User)
def check_email(sender,instance,**kwargs):
try:
usr = User.objects.get(email=instance.email)
if usr.username == instance.username:
pass
else:
raise Exception('EmailExists')
except User.DoesNotExist:
pass
Add somewhere this:
User._meta.get_field_by_name('email')[0]._unique = True
and then execute SQL similar to this:
ALTER TABLE auth_user ADD UNIQUE (email);
The first answer here is working for me when I'm creating new users, but it fails when I try to edit a user, since I am excluding the username from the view. Is there a simple edit for this that will make the check independent of the username field?
I also tried including the username field as a hidden field (since I don't want people to edit it), but that failed too because django was checking for duplicate usernames in the system.
(sorry this is posted as an answer, but I lack the creds to post it as a comment. Not sure I understand Stackoverflow's logic on that.)
You can use your own custom user model for this purpose. You can use email as username or phone as username , can have more than one attribute.
In your settings.py you need to specify below settings
AUTH_USER_MODEL = 'myapp.MyUser'.
Here is the link that can help you .
https://docs.djangoproject.com/en/1.8/topics/auth/customizing/#auth-custom-user
from an User inherited model, redefine the attribute correctly. It should work, as is it's not usefull to have that in django core because it's simple to do.
I went to \Lib\site-packages\django\contrib\auth\models
and in class AbstractUser(AbstractBaseUser, PermissionsMixin):
I changed email to be:
email = models.EmailField(_('email address'), **unique=True**, blank=True)
With this if you try to register with email address already present in the database you will get message: User with this Email address already exists.