PasswordField in Django model? - django

I am trying to create a simple model called Username like this:
class User(models.Model):
username = models.CharField(max_length=100) #Id is automatically generated by Django
password = models.CharField(max_length=100)
This is the Django model that I am trying to create. The problem is username and password attribute is stored as CharField whereas I want password to be stored as ** or encrypted form in the database.It seems like they don't have PasswordField like CharField in Django. What's the best way to do it?

as per THE DOCS it's
password = forms.CharField(
widget=forms.PasswordInput(render_value=False),
label="Your Password"
)
and this lends to a
<input type="password" />
in your rendered form
About your storing part, you will need to store an hash of the password, not a list of * or you won't be able to retrieve it anyway. You could use the hashlib module
user.password = hashlib.sha224(user.password).hexdigest()
user.save()
of course you have to pay big attention when implementing this. This above is just a quick example, check the docs for further learning

Django comes with User model. It's under django.contrib.auth.models. The model has everything you need and it's would be silly to start creating your own if there is one already. You also have a user creating and authentication forms in django.contrib.auth.forms, things like set_password method in user model and heaps more stuff.

Related

Django Auth User Model Set different field name for password

I recently look into Django framework and plan to migrate my old system into it. Therefore, there is legacy mysql database that I need to follow. Is there anyway to change the field name of password of Django User Model? such as "pwd" or "password2".
I got research the Django document, only able to find out changing the username field
https://docs.djangoproject.com/en/2.2/topics/auth/customizing/#django.contrib.auth.models.CustomUser.USERNAME_FIELD
I think you can create a new class that inherits from user model and set the password field to be whatever you like.
Something like:
class MyUser(AbstractBaseUser):
...
password = models.CharField(max_length=100, db_column='custom_name')
...

extending default User model in Django

I've written my first application Django 2.0.
Everything is working fine and the application is almost ready when I realized to replace id primary key field from default integer type to UUID to make database entry more secure.
When I searched for this how to change id of user table to UUID I got many tutorials extending AbstractBaseUser.
Here is I have written own User model.
account/models.py
class User(AbstractBaseUser):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
But I'm confused more with examples on different sources.
Every example is adding few more fields in extended model like
first_name
last_name
is_staff
is_admin
active
and functions as
def get_fullname(self):
def get_shortname(self):
etc.
I think all these fields and functions are there by default in AUTH_USER_MODEL.
Does extending AbstractBaseUser overwrites AUTH_USER_MODEL and it is required to add all fields which is there by default?
also, I'm using settings.AUTH_USER_MODEL as foreign key in different models. Should It be replaced by account.User model?
I'm also using django-allauth plugin to enable login using the social network and use email only for authentication. Do I require to add email field in the extended model with unique=True?
Django AbstractBaseUser provides only following fields: password, last_login, is_active. So if you are using custom User model inherited from AbstractBaseUser you need to define all other fields such as email manually.
As another part of question just adding AUTH_USER_MODEL = 'users.User' to your settings.py file should make everything works without replace code in your project.
UPD
If you need field like first_name, last_name, etc. to be includet to the model you can use AbstractUser instead of AbstractBaseUser.
As the Django documentation indicates, it's difficult to extend the User table after-the-fact, and not recommended at all for apps. A better way is to create an auxiliary table which has a 1:1 relationship with the user-id. Leave Django's user-table alone and just use this other table to pony-up to it.
The "Django Annoying" project, at https://github.com/skorokithakis/django-annoying#autoonetoonefield, has some very useful "juice" to make this much easier: an AutoOneToOneField. Whereas Django's foreign-key field will throw an error if an record doesn't exist, this field will automagically create one on-the-fly, thereby side-stepping the entire issue. (The documentation page linked-to above shows exactly how this is done.)

The relation between a model and it's form in Django, and user authentication

I'm migrating something from an old PHP/apache server to Django. I'm a bit stumped with the 'ModelForm'.
As far as I understand, a "Model" is the abstraction for persistent elements in my website/server - specifically this is something stored physically, say in a database, and defines the fields (read columns) in the DB.
I started moving the authentication part of the site, and discovered models, and specifically the User model (I made an empty User inheriting AbstractUser just in case I will ever need to extend things). Now I want to create a simple two field form, to authenticate login.
The form:
Username (which is a field of User, by default)
Password (Which is not).
Even the 'Username' needs a redefinition in the model form. So my questions:
What is the advantage of the model form (over just a form)? - seems like you're redefining fields anyway, and obviously sometimes adding fields on top of the model.
Specifically for authentication, I probably need to store my salted hash associated with the user somehow, compare my password using that and retrieve the user object. This is something I find very hard to find in the Django docs - they just have too much written on authentication, and not one full code example. Do I put this in the "validate" method of form, retrieving there an object and storing it in a session or something?
If there is a deeper relation between a model form and the associated model, I would like to know as well.
Simple django forms and modelforms have quite differences.
class ArticleForm(ModelForm):
class Meta:
model = Article
fields = ['pub_date', 'headline', 'content', 'reporter']
The above example illustrates that you don't have to write any form field in here. The model form will itself create a form which is based on the attributes provided in the model ('Article' in this example).
If you create a simple django form then it would be something like:
class ArticleForm(forms.Form):
some_field = forms.CharField(some_attrs)
...
The django User model provides you everything you need for authentication. When you want to create users just import django.contrib.auth.models.User and use create method to create objects. Then when you want to authenticate a user use authenticate method.
from django.contrib.auth import authenticate, login
def user_login(request):
username = request.POST.get('username')
password = request.POST.get('password')
user = authenticate(request, username=username, password=password)
# after authentication login the user or set cookies or modify the session or some other action can be taken
return HttpResponse("Some response or use render for html page")
username and password will be coming from your post request.
If you want to extend default Django user model you can use django user model as onetoonefield in your extended model.
class AppUser(models.Model):
user = models.OneToOneField(User)
... # other custom fields

Django: model.ForeignKey referring to field type

I try to build a model, e.g. Userprofile, in which fields will be chosen in the admin panel.
class UserProfile(models.Model):
user = models.OneToOneField(User)
regfield = models.ForeignKey(Regfields)
This model refers to a second model Regfields:
class Regfields(models.Model):
field_name = models.CharField(max_length = 256, unique=True, blank=False)
field_type = models.ForeignKey(FOREIGNKEY_TO_DATATYPES)
I want to choose the Fieldname and the Fieldtype (e.g. Char_field ...) to use this in a second model Userprofile, to refer to the field names and field types in the Regfields model. What is the best approach to realize this?
Edit:
I don't seek to have a kind of dynamic database for the user profile. I think I could achive something like this by using a "static" choice list, e.g.:
FIELD_TYPE_CHOICES = (
(BigIntegerField,'Long Int'),
(BooleanField,'Boolean'),
(CharField,'Char'),
...
)
field_type = models.CharField(max_length=20, choices=FIELD_TYPE_CHOICES, default=CharField)
However, this way I can have the required registration fields to be choosen from a given set, but I only get the fieldtypes as strings, which in turn might lead to complicated data validation.
Example of what i try to achive:
In the admin panel I want the admin to have they choice what kind of data is required (additionally to username and password) at the registration page. The admin might like to ask for (username, password and email) but might also ask for (username, password, email, first_name, last_name, company, department)
Allowing users to customize forms via forms is not that simple, and will probably drag you into more non standard problems... How about trying out a ready made django package that helps building forms?
https://www.djangopackages.com/grids/g/form-builder/

How to make email field unique in model User from contrib.auth in Django

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.