Schema - Ability to change email address (primary user id) in Django - python

Currently my user table looks like this - (all fields are not null)
display_name = CharField # string
email_address = EmailField (primary key) # string
password = CharField # string
However, I have decided to add additional functionality and to allow users to change their email addresses.
The flow goes like this
Does anyone have any ideas on how to do this?
Currently I am thinking of something like
display_name = CharField # string
email_address = EmailField (primary key) # string
password = CharField # string
pending_email = EmailField (unique) # string
And simply hold the new email address in pending_email before replacing the old email address in email_address
But obviously this is far from perfect (e.g. pending_email unique constraint does not cover email_address)
Ive thought about just leaving it like this and performing more selects against the database with AJAX queries to check if the desired new email address already lives in email_address before allowing it to be entered into pending_email but this seems still vulnerable to race conditions and poor user experiences on top of being not very database friendly.

The standard practice in this sort of situation is to create a separate table for email addresses. That allows users to have more than one email address at a given time and one of them can be marked as default.
This is what django-allauth's EmailAddress model looks like. In fact, unless you have a very compelling reason to write your own authentication system, I highly recommend that your swith to django allauth or any of the widely used django authentication/registration system.
class EmailAddress(models.Model):
user = models.ForeignKey(allauth_app_settings.USER_MODEL,
verbose_name=_('user'))
email = models.EmailField(unique=app_settings.UNIQUE_EMAIL,
max_length=app_settings.EMAIL_MAX_LENGTH,
verbose_name=_('e-mail address'))
verified = models.BooleanField(verbose_name=_('verified'), default=False)
primary = models.BooleanField(verbose_name=_('primary'), default=False)
objects = EmailAddressManager()

Related

Django Python change user default attributes for authentication

In Django, the default attributes for user:
username
password
email
first_name
last_name
I would like to remove email, first_name, last_name
and replace it with company
Is that possible ? Can someone show me the process of performing an authentication session with these 3 modified attributes:
- company
- username
- password
Thanks.
You should read the documentation regarding customizing authentication in Django especially the part regarding User model substitution if you would like to create your own model.

Why is Django's `add()` method in my `many-to-many` Django models not taking?

Question / Problem:
I am building a Django app, with 2 models: User and Secret. Secrets can be made by Users, and other Users can "like" them. I've setup my likes field as a ManyToManyField, so that Users whom like a Secret can be stored there and later retrieved, etc. However, when I try to query for a User and a Secret and use my_secret.likes.add(my_User) nothing happens. I don't receive an error and when I print my Secret's many-to-many likes field, after the add, I see: secrets.User.None.
Why is my add() method running but I am not receiving any errors, and why is my User not properly being added to my Secret's likes?
Note: I've saved both the User and Secret objects upon initial creation. Outside this application I've been able to use the add() method just fine, but in those scenarios I was creating objects in the moment, and not retreiving already existing objects.
Is there a different way to handle add() when using data retreived from a Query? That's my only other line of reasoning right now, and I've followed the documentation here exactly: Django Many-to-Many Docs
I also apologize if this was answered elsewhere on the site. I did find one other post here, but there was no solution provided, granted they were experiencing the exact same issue.
My Models:
class User(models.Model):
"""
Creates instances of a `User`.
Parameters:
-`models.Model` - Django's `models.Model` method allows us to create new models.
"""
first_name = models.CharField(max_length=50) # CharField is field type for characters
last_name = models.CharField(max_length=50)
email = models.CharField(max_length=50)
password = models.CharField(max_length=22)
created_at = models.DateTimeField(auto_now_add=True) # DateTimeField is field type for date and time
updated_at = models.DateTimeField(auto_now=True) # note the `auto_now=True` parameter
objects = UserManager() # Attaches `UserManager` methods to our `User.objects` object.
class Secret(models.Model):
"""
Creates instances of a `Secret`.
Parameters:
-`models.Model` - Django's `models.Model` method allows us to create new models.
"""
description = models.CharField(max_length=100) # CharField is field type for characters
user = models.ForeignKey(User, related_name="secrets") # One-to-Many Relationship
likes = models.ManyToManyField(User) # Many to Many Relationship
created_at = models.DateTimeField(auto_now_add=True) # DateTimeField is field type for date and time
updated_at = models.DateTimeField(auto_now=True) # note the `auto_now=True` parameter
objects = SecretManager() # Attaches `SecretManager` methods to our `Secret.objects` object.
Problem Example:
The model migrates fine, everything seems to be in proper syntax. However, when I try and retrieve a User and a Secret, and add the User to the Secret.likes, the add() method gives no errors, runs, but no objects are saved.
Here's an example:
tim = User.objects.get(email="tim#tim.com") # Gets a user object
my_secret = Secret.objects.get(id=2) # Gets a secret object
# This is where nothing seems to happen / take:
my_secret.likes.add(tim) # add() method per Django many-to-many docs
print my_secret.likes # returns: `secrets.User.None` -- why?
Why when printing my_secret.likes above, is nothing printed?
Especially when:
tim.secret_set.all() shows the secret containing an id=2 as in the above example....so the User is recording the relationship with the Secret, but the Secret is not recording any relationship with the User. What am I doing wrong?
You need to call the all method of the many-to-many field to view all related objects:
print my_secret.likes.all()
# ^^^^^

Create DB tables with different user types and authenticate user with username and password

I am stuck with the schema creation so could you provide me an idea to implement this scenario
i do have 4 types of users Student, Teacher, Parent and Admin
i have tried to create 4 tables for each users and a table for username, password and tokens but i am not able to relate this table to the users because more than one user cannot have same username
What i want is i need to authenticate each user withe their user name and password and the Student table might be having relationship with Parent table !!!!
so while authenticating i need to know which type of user he/she is
i am using python Django 1.9
Instead of creating four separate tables, you can simply add a field which will reflect the user_type of the user.
class CustomUser(AbstractBaseUser):
...
[other model fields]
...
USER_TYPE_CHOICES = (
('student', 'Student'),
('teacher', 'Teacher'),
('parent', 'Parent'),
('admin', 'Admin'),
)
user_type = models.CharField(choices=USER_TYPE_CHOICES, max_length=7)
By doing this, all users will have unique usernames and they will become easy to manage too.
You can check type of user just by accessing its user_type, it'll return one of this text values "Student, Teacher, Parent and Admin". So you'll be able to handle business logic for different user types.
You can use the Django authentication system :
Using the Django authentication system
and for each category of user you can use : Groups
django.contrib.auth.models.Group models are a generic way of categorizing users so you can apply
permissions, or some other label, to those users. A user can belong to
any number of groups.
Creating four tables is not the correct way.
Alternatively you can ,
class User():
id = Column(PrimaryKey)
username = Column(String, constraints)
password = Column(String, constraints)
usertype = Column(Enum('student','teacher','parent','admin'))
-- The code is only for representation .
For setting user role , you can use the Enum Property. In case you are using SQLALchemy , check this out
How to create ENUM in SQLAlchemy?

Creating users in the database

Im modeling database tables for register/login pages. At the first insert all ends without any errors, but following insert return IntegrityError exception:
duplicate key value violates unique constraint
"mainws_user_role_id_key" DETAIL: Key (role_id)=(1) already exists.
If OneToOneField making rows only as unique, it means, that I cant create many users with one role, right? Then better using ForeignKey(Role) for this situation, or not?
Source code:
class User(models.Model):
login = models.CharField(max_length=50)
password = models.CharField(max_length=50)
address = models.CharField(max_length=255)
phone = models.CharField(max_length=25)
postcode = models.CharField(max_length=25)
email = models.EmailField()
role = models.OneToOneField(Role, primary_key=False)
class Role(models.Model):
role_name = models.CharField(max_length=25, unique=True)
def create_user(user_data):
md5 = hashlib.md5()
md5.update(user_data['password'])
user_role = Role.objects.filter(role_name='user')[0]
password_md5 = md5.hexdigest()
new_user = User(login=user_data['login'],password=password_md5,address=user_data['address'],
phone=user_data['phone'],postcode=user_data['postcode'],
email=user_data['email'],role=user_role)
new_user.save()
I would think your issue is in the OneToOneField. As its name implies, you can only associate one role with one user. A foreign key represents a ManyToOne relationship, that is what you want in this case, many users can have one role.
On the other hand, you are trying to create users on your own when Django already has most of that by default. Frameworks are there to avoid you making sensitive parts of your application manually.
You may want to check documentation if you don't know how to do that.

Django EmailField accepts any value (including blank)

Having this Django model:
class Subscriber(models.Model):
email = models.EmailField(unique=True, blank=False)
I do not face any exceptions when creating a Subscriber with empty email:
>>> Subscriber.objects.create(email='')
<Subscriber: Subscriber object>
Interesting is that for the second time it will raise the IntegrityError:
>>> Subscriber.objects.create(email='')
...
IntegrityError: column email is not unique
So it seems to validate for integrity, but neither for email format nor for blank entries. How do I have the email validated?
The parameter blank is used from the form, it's not enforced at database level
From the documentation
Field.blank If True, the field is allowed to be blank. Default is
False.
Note that this is different than null. null is purely
database-related, whereas blank is validation-related. If a field has
blank=True, form validation will allow entry of an empty value. If a
field has blank=False, the field will be required.
Indeed the validator documentation says that
Note that validators will not be run automatically when you save a model
to enforce that you have to use the full_clean() method.
The error is thrown because you are trying to insert two times the empty string and you have
the unique constraint on the field.
you got to validate your e-mail field with a built in email-validator like this
from django.core.validators import validate_email
and declare your e-mail field in this way
email = models.EmailField(unique=True, validators=[validate_email,])
this way it will validate your e-mail field with a built in regular expression

Categories