I'm currently developing a web-application for managing driving licenses as a web development homework assignment. Instead of just storing information on every driver as a model I want to make a user for each driver. What is the easiest way to do so? What am I doing wrong?
I updated a car owner model so that it is now inherited from djangdo Abstract User.
# models.py
class Car_owner(AbstractUser):
id_owner = models.IntegerField(primary_key=True)
last_name = models.CharField(max_length=30, null=False)
first_name = models.CharField(max_length=30, null=False)
birth_date = models.DateField(null=True)
passport = models.IntegerField(null=True, blank=True)
address = models.CharField(max_length=50, null=True, blank=True)
nationality = models.CharField(max_length=15, null=True, blank=True)
# username = models.CharField(max_length=16, unique=True, default=uuid4)
# password = models.CharField(max_length=16, default='password')
I also have forms.py file:
from django import forms
from project_first_app.models import Car_owner
class CreateOwner(forms.ModelForm):
class Meta:
model = Car_owner
fields = ['id_owner', 'last_name', 'first_name', 'birth_date', 'passport', 'address', 'nationality']
But when migrating I get the following issue:
UNIQUE constraint failed: new__project_first_app_car_owner.username
In migrations files I have:
migrations.AddField(
model_name='car_owner',
name='username',
field=models.CharField(default=uuid.uuid4, max_length=16, unique=True),
),
and then:
migrations.AlterField(
model_name='car_owner',
name='username',
field=models.CharField(error_messages={'unique': 'A user with that username already exists.'}, help_text='Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only.', max_length=150, unique=True, validators=[django.contrib.auth.validators.UnicodeUsernameValidator()], verbose_name='username'),
),
Those are automatically generated.
You have commented username and password in your model, why ?
Password field already exists in the abstractbaseuser, so comment it does not remove it. The abstract model user of Django need a unique information for authenticating user. You can use a Username or an Email.
For using the email instead of username, you can define USERNAME_FIELD = "email" in your class. But you have to define a field email, or you keep username field and add it to fields ModelForm.
There is a constraint on the username field (or email field), so you have to define it for each Car_owner you want to create (it is for authenticating purpose).
your field id_owner is useless, Django create automatically a field called id in each model which is the primary key.
so for resolving your problem easily, add username in fields list of your Form for beginning.
Related
In Django official guide, it reads:
Inside this django.contrib.auth model, there is a User class, who has following attributes (username, password, email, first_name, last_name).
When I check the source code in github, I did not find this definition in django.contrib.auth.
I can only see class AbstractBaseUser(models.Model): in django/contrib/auth/base_user.py on this link, and class User(AbstractUser): in django/contrib/auth/models.py in this webpage.
Q1: what does class models.User mean in above official document, it means User is a class under models.py ?
Q2: if above is right, then where User class get attributes such as username, email etc?
Q1: what does class models.User mean in above official document, it means User is a class under models.py?
In Django one refers to a model with the app_name.ModelName. So if you specify a model, this is implemented in the app_name/models.py, but since models are defined in the models.py file, it makes no sense to include that in the name of the model.
For example the default for the AUTH_USER_MODEL setting [Django-doc] is auth.User, since the name of the app is auth, and the name of the model is User.
Q2: if above is right, then where User class get attributes such as username, email etc?
Through inheritance. Indeed if we look at the source code of the models.py file [GitHub], we see:
class User(AbstractUser):
"""
Users within the Django authentication system are represented by this
model.
Username and password are required. Other fields are optional.
"""
class Meta(AbstractUser.Meta):
swappable = 'AUTH_USER_MODEL'
and the AbstractUser model [GitHub] defines the fields for username, email, etc.:
class AbstractUser(AbstractBaseUser, PermissionsMixin):
# …
username = models.CharField(
_('username'),
max_length=150,
unique=True,
help_text=_('Required. 150 characters or fewer. Letters, digits and #/./+/-/_ only.'),
validators=[username_validator],
error_messages={
'unique': _("A user with that username already exists."),
},
)
first_name = models.CharField(_('first name'), max_length=150, blank=True)
last_name = models.CharField(_('last name'), max_length=150, blank=True)
email = models.EmailField(_('email address'), blank=True)
is_staff = models.BooleanField(
_('staff status'),
default=False,
help_text=_('Designates whether the user can log into this admin site.'),
)
is_active = models.BooleanField(
_('active'),
default=True,
help_text=_(
'Designates whether this user should be treated as active. '
'Unselect this instead of deleting accounts.'
),
)
date_joined = models.DateTimeField(_('date joined'), default=timezone.now)
# …
AbstractUser is an abstract model. This means that Django does not create a table for it. Models that inherit from an abstract table will thus inherit fields, methods, etc. and these fields will then be defined on the model that inherits from AbstractUser.
I have a Custom User model in my app
class User(AbstractBaseUser, PermissionsMixin):
uuid = models.UUIDField(default=uuid.uuid4, unique=True)
email = models.EmailField(_('email address'), db_index=True, unique=True)
and this AUTH_USER_MODEL = 'users.User' in my settings file.
Now I want to create a model on the top of this custom user model(User), lets call it Agent, this model will have three columns:
user_uuid #Foreign Key Refernce(OnetoOne) to the Custom User Model
uuid # unique identifier for Agent model
scope # CharField specific to Agent model
What is the best way to do that?
While there is no best practice, it all depends on what you are doing, the most likely to work method is a type field specifying Agent and a one-to-one table (docs) for extra fields.
It'll be up to you to create the records as-needed. There isn't anything special about what you are doing just because it is a user.
class AgentDetails(Model):
user = OneToOneField(User, primary_key=True, on_delete=CASCADE)
...
A more complete user model would look something like this:
class User(AbstractBaseUser, PermissionsMixin):
USERNAME_FIELD = 'email'
EMAIL_FIELD = 'email'
REQUIRED_FIELDS = ["name"]
email = EmailField(unique=True, db_index=True)
name = CharField(max_length=100)
type = ChoiceField(choices=[('user','User'),('agent','Agent')])
is_staff = models.BooleanField(default=False, help_text='If the user can log into this admin site.')
is_active = models.BooleanField(default=True, help_text='If the user is active, instead of deleting')
created_at = models.DateTimeField('Date Joined', default=timezone.now)
objects = MyUserManager() #
In addition, you are probably going to need to add:
Custom admin page
Custom UserManager
You can derive one table from an abstract base, but this will generate 1 table for each user type which will not work with the standard authentication. For info, see Django's Model Inheritance.
class User(Model):
email = EmailField()
class Meta:
abstract = True
class Agent(User): # generates table 1
extra_field = CharField()
class Standard(User): # generates table 2
extra_field = CharField()
If the user model you have given is complete, then I don't think it will work with the default django infrastructure. From your question its not clear if you need help on that.
I have extended the in built user model in django via AbstractUser. However when it cam to deployment and to create a superuser it failed because of having a null entry in some of the additional fields in the extended model. Is there a way to have these fields not required for a superuser but required for a normal user. (I presume this is a typical use case - as I don't need an admin to fill out address, account number etc...)
models.py
class User(AbstractUser):
title = models.CharField(max_length=255, null=True)
date_of_birth = models.DateField()
phone_number = models.IntegerField(null=True)
account_name = models.CharField(max_length=255)
account_number = models.IntegerField()
house_name_number = models.CharField(max_length=255, verbose_name="house name or number")
street_name = models.CharField(max_length=255)
town_city = models.CharField(max_length=255)
county = models.CharField(max_length=255)
postcode = models.CharField(max_length=8)
Instead of using mandatory fields in models, you have to set them to optional using null=True, blank=True and let the validation happen in forms. For users other than admin create a form that checks for extra fields andvalidate those fields. Render this form through templates at the time of signup/registration. Also instead of using modelforms use forms.Form this will give you a better level of customization. This will make extra fields mandatory for all users other than Admin.
I am working on a django (1.8.6) site that involved two applications now. One is a custom user model with basic registration / login / logout functionality, the second is a feedback application. I want to have a foreign key relationship from a feedback to the user that submitted it.
When I try to run ./manage.py migrate I get the following error.
django.db.utils.ProgrammingError: relation "customauth_user" does not exist
This is of course since the database table does not YET exist. If I remove the related field, everything works fine. Here is my code.
My user model:
class User(AbstractBaseUser):
username = models.CharField(_('username'), max_length=100, unique=True)
email = models.EmailField(('email address'), max_length=254)
first_name = models.CharField(_('first name'), max_length=50)
last_name = models.CharField(_('lat_name'), max_length=50)
receive_newsletter = models.BooleanField(_('receive_newsletter'), default=False)
referral_id = models.CharField(_('referral id'), max_length=40)
USERNAME_FIELD = 'username'
REQUIRED_FIELDS = ['email', 'first_name', 'last_name']
And the model from my feedback form:
class Feedback(models.Model):
timestamp = models.DateTimeField(auto_now_add=True)
submitted_by = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='feedback')
title = models.CharField(max_length=100)
message = models.CharField('Users message', max_length=1024)
reviewed = models.BooleanField('Reviewed by staff', default='NEW', choices=FEEDBACK_STATUS_CHOICES, max_length=10)
jira_ticket_created = models.BooleanField('Created a Jira ticket to track this feedback.',
default=False)
jira_ticket_number = models.CharField(max_length=10, blank=True, null=True)
class Meta:
db_table = 'feedback'
def __str__(self):
return str(self.timestamp) + ' ' + self.title
I have configured my user model in settings, added both applications, and in my installed applications my applcaition with my custom user model is first.
Any thoughts?
Thanks
Craig
You need to add a dependency in your feedback migration to the customauth app. See the migrations docs.
You should use python manage.py makemigrations
and then python manage.py migrate
How can I create OrderUser model containing subfields of User model that are desired:
first_name
last_name
email
I want to avoid manually copying fields' structure from django.contrib.auth.models AbstractUser like
class OrderUser(models.Model):
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
email = models.EmailField(_('email address'), blank=True)
I wonder if there is any way to write something like this:
class OrderUser(models.Model):
first_name = User.fields.first_name
last_name = User.fields.last_name
email = User.fields.email
Usually, if I want two models to have the same fields, I use Abstract Model inheritance.
But inheriting from AbstractUser leads to many unnecessary fields like username, is_staff, is_active and so on.
Ok, my bad, I finally found an answer to my own question, maybe it will be helpful for someone else.
The _meta property worked for me:
class OrderUser(models.Model):
first_name = User._meta.get_field_by_name('first_name')[0]
last_name = User._meta.get_field_by_name('last_name')[0]
email = User._meta.get_field_by_name('email')[0]
More discussion about _meta:
Get model's fields in Django
How to introspect django model fields?