Custom User model changes never migrate - python

I made the mistake of not using a custom user model for the first migration and I paid the price by having to delete all the migrations and makemigrations and migrate again as I switched the project to use my custom user.
models.py
"""
Changes are never picked by makemigrations
"""
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
username = models.CharField(max_length=120, unique=True, blank=False,
validators=[MinLengthValidator(2)])
email = models.EmailField('Email Address', unique=True, blank=False)
FCM_ID = models.CharField(max_length=300, blank=True)
def __str__(self):
return self.username
Everytime I made any changes to the custom user, I have had to delete all migrations related files and apply migrations again just to get past the errors- this SO answer and this.
Now I realized that I needed a newer change, but migrations are not detected after changing the User model. The only solution I have is to delete the migrations again! So far I have done this chore like 5 times and I am tired, what am I doing wrong?
I have tried python3 manage.py makemigration <app_name>, and of course, the custom user model is defined in settings.py using AUTH_USER_MODEL.

Related

Django: 0001_initial.py is not on current status after complementing models.py

I am new to Django/python and I am facing a problem with my models.py.
I added some attributes, saved it -> py manage.py makemigrations -> py manage.py migrate
but the current attributes are not shown in the 0001_initial.py.
Also when I am opening the database in my DB Browser for SQLite I still get the old status.
Here's my code:
models.py
from django.db import models
# from django.contrib.auth.models import User
# Create your models here.
category_choice = (
('Allgemein', 'Allgemein'),
('Erkältung', 'Erkältung'),
('Salben & Verbände', 'Salben & Verbände'),
)
class medicament(models.Model):
PZN = models.CharField(max_length=5, primary_key=True) # Maxlaenge auf 5 aendern
name = models.CharField('Medikament Name', max_length=100)
description = models.CharField('Medikament Beschreibung', max_length=500)
category = models.CharField(max_length=100, blank=True, null=True, choices=category_choice)
instructionsForUse = models.CharField('Medikament Einnehmhinweise', max_length=400)
productimage = models.ImageField(null=True, blank=True, upload_to="images/")
stock = models.PositiveIntegerField(default='0')
reorder_level = models.IntegerField(default='0', blank=True, null=True)
price= models.DecimalField(default='0.0', max_digits=10, decimal_places=2)
sold_amount = models.IntegerField(default='0', blank=True, null=True)
sales_volume = models.DecimalField(default='0.0', max_digits=10, decimal_places=2)
def __str__(self):
return self.name
And the 0001_initial.py
# Generated by Django 3.2.16 on 2023-01-05 14:33
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='medicament',
fields=[
('PZN', models.CharField(max_length=5, primary_key=True, serialize=False)),
('name', models.CharField(max_length=100, verbose_name='Medikament Name')),
('description', models.CharField(max_length=500, verbose_name='Medikament Beschreibung')),
('category', models.CharField(default='Allgemein', max_length=100)),
('instructionsForUse', models.CharField(max_length=400, verbose_name='Medikament Einnehmhinweise')),
('productimage', models.ImageField(blank=True, null=True, upload_to='images/')),
('stock', models.IntegerField(default='0')),
],
),
]
First a basic explanation and below an answer to your specific situation
There is 2 steps:
"makemigrations" scans your code, finds changes in models an will create migrations files according to changes like
001_initial.py
002_auto_xyz.....py
There is an initial file and then subsequent migration files having a running number and depend on each other which you can see in the file e.g.
dependencies = [
('users', '0003_auto_20210223_1655'),
]
Once a migration file is created it will not change anymore and all later modifications in the code will be reflected in new additional migrations file after a new makemigration is executed.
"migrate" will take the created migration files, will check your database which migrations have been applied already to this specific database(!) and apply the once that are pending. In the database there is a table created that stores info about the already applied migrations.
That means for example you can run a migrate on a database on your development server and independent from that run migrate on a database on your production server. Both migrate commands will read the existing migration files and perform migrations in the database.
So if you made an initial model -> makemigrations -> migrate, you will see an 001_initial.py migrations file.
If you make changes to the models -> makemigrations again -> migrate again you should find only the changes in the 002_... migrations file and find also the changes in your database.
In any Django project, you only run makemigrations once (at the first initialization of your models), after that you run ONLY migrate for any updates.
As for your problems, you should delete your SQLite DB, and also delete all migrations files that end with .pyc.
After that run makemigrations then migrate, (and don't run makemigrations again, the reason being that it will cause problems and collisions with older SQL migrations based on the previous makemigrations).

Adding db_table to model added a last_login field

Background: I started a project with a custom User model. However, noob that I am, I was unaware of the AbstractBaseUser class. So I just wrote my own. The app has been deployed to prod and working fine. But now I want to switch to using AbstractBaseUser so I can take advantage of some of the built-in Django utilities (like the pre-made password resetting process). I had done this with a different app and it worked fine. But that one wasn't in prod while I made the change. Because this one is, I needed to keep the old user table while I made the changes with a copy of it. So my first step was to add db_table = test_users to my old user model, so as to keep the prod app running with an unchanged table. I ran the migration, and two unexpected things happened (I'm a noob, and that's why they were unexpected):
The old user table was renamed. I thought a new table would be created. No problem, I quickly copied the new table and named the copy with the old table's name so the prod app could still find its users
A column last_login was added. Why??
Here's my model, with the added db_table
class User(models.Model):
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
email = models.CharField(max_length=255)
password = models.CharField(max_length=255)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
client_id = models.IntegerField(blank=True, null=True)
is_admin = models.BooleanField(default=False)
is_super = models.BooleanField(default=False)
is_active = models.BooleanField(default=True)
class Meta:
db_table = "test_users"
The big problem with this is that when I change to AbstractBaseUser and run the migration, I get an error. Looking at the migration file I see that this change creates a migration that all it tries to do is to add last_login to the table. So, of course, the error I get is "Duplicate column name 'last_login'"
So, my question is two-fold:
Why was that column added in the first migration?
If I just run migrate --fake and keep going, will it have unintended consequences? I thought this could be a good solution, given that the migration file shows nothing else is being done, and if the field already exists, then no harm done?
Maybe because you've changed the parent class django automatically change all the migrations that connected to your user class

Django AbstractEmailUser model column does not exist

I created a CustomUser model, inheriting from AbstractEmailUser.
I wanted to add an avatar field, after finishing it and making migrations but I'm getting the following error:
column account_customuser.avatar does not exist
LINE 1: ...user"."name", "account_customuser"."valid_email", "account_c...
models.py looks like this now
class CustomUser(AbstractEmailUser):
nickname = models.CharField('nickname', max_length=100, unique=True)
name = models.CharField(max_length=200, blank=True, null=True, default=None)
valid_email = models.BooleanField('valid email', default=False, blank=True)
avatar = models.ImageField(upload_to='profile/photo', blank=True, null=True, default=None)
What can I do to correctly add the avatar field?
As stated here: Django Programming error column does not exist even after running migrations
Something may have gone wrong in your migration process.
Go to your database and find a table named django_migrations where
all the migrations are listed.
Find the row with the migration in which you added the avatar column to your model and delete it from the database (only the row).
Migrate again: ./manage.py migrate
Another possibility is that you are using Django Toolbar like what happened here: Django Migration Error: Column does not exist, in which case you need to comment the toolbar in your installed apps and rerun migrations.
Did you apply a new migration with these changes?
You can check this using showmigrations or use makemigrations to create a migration and migrate to apply it.

Problems extending my Django user model

I have a simple django app, and am trying to set up a custom Django User Model so that I can have users log in with their email field. I think I set everything up well enough, its all fairly straightforward, however when trying to actually run the migrations I get this error:
django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency accounts.0001_initial
Seems weird?
I'm having trouble understanding why it's having trouble understanding.
Heres the User model Im implementing
from __future__ import unicode_literals
from django.db import models
from django.core.mail import send_mail
from django.contrib.auth.models import PermissionsMixin
from django.contrib.auth.base_user import AbstractBaseUser
from django.utils.translation import ugettext_lazy as _
from .managers import UserManager
class User(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'), unique=True)
first_name = models.CharField(_('first name'), max_length=30, blank=True)
last_name = models.CharField(_('last name'), max_length=30, blank=True)
display_name = models.CharField(_('display name'), max_length=30, blank=True)
bio = models.TextField(blank=True)
date_joined = models.DateTimeField(_('date joined'), auto_now_add=True)
is_active = models.BooleanField(_('active'), default=True)
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = []
class Meta:
verbose_name = _('user')
verbose_name_plural = _('users')
def get_full_name(self):
'''
Returns the first_name plus the last_name, with a space in between.
'''
full_name = '%s %s' % (self.first_name, self.last_name)
return full_name.strip()
def get_short_name(self):
'''
Returns the short name for the user.
'''
return self.first_name
def email_user(self, subject, message, from_email=None, **kwargs):
'''
Sends an email to this User.
'''
send_mail(subject, message, from_email, [self.email], **kwargs)
"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." reference->django docs
Then you have to specify to setting.py that you are using a new user model (again before you migrate for the first time.)
from django.contrib.auth.models import AbstractUser
class User(AbstractUser):
pass
# in settings.py
AUTH_USER_MODEL = 'myapp.MyUser'
I highly recommend checking out the link above.
Now to solve your problem you can delete your migrations in your app path under the migrations directory and reset your database and follow the instructions above.
Changing user model mid project is difficult in django and requires manually editing your schema so since your project is for educational purposes just reset it
Basically, you have already created some User accounts or at least have created superuser account. Since you are changing the User model after I assume you have already made migrations at least once, Django has conflict with old user model with the new one.
Solution is to delete all accounts in admin including superuser. Then delete your migrations files in migrations folder. And also I think delete your sqlite data file. Run migrations again and it should work.
You should have created custom user model before any migration.
One solution is to truncate the django_migrations table.
To do this you have to:
login to your database (In case you use Mysql) using mysql -u root -p
use your_db_name;
SET FOREIGN_KEY_CHECKS=0; to prevent relation errors
DELETE FROM django_migrations; truncates the django_migrations table
SET FOREIGN_KEY_CHECKS=1;
Then you can run your migrations!
Another solution is to run these commands before your migration to avoid migrations error:
python manage.py migrate admin zero --fake
python manage.py migrate auth zero --fake
python manage.py migrate contenttypes zero --fake
python manage.py migrate sessions zero --fake
Warning :
This solution may leave you with a database schema that's
inconsistent with the migrations applied, so only do this if
you know what you're doing. Thanks to #AKX
You can also use this solution too!

Django ForeignKey to AbstractBaseUser

I'm trying to set up an app that will handle reviews about registered users. So in my Review model, I want to have a ForeignKey to my User model.
I'm using a custom user profile that looks like this:
#In /profiles/models.py
class MyUser(AbstractBaseUser):
email = models.EmailField(
verbose_name='email address',
max_length=255,
unique=True,
)
company = models.CharField(default="", max_length=200)
is_active = models.BooleanField(default=True)
is_admin = models.BooleanField(default=False)
objects = MyUserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['company']
I have included it with settings.py AUTH_USER_MODEL = "profiles.MyUser". It works fine with registration, creating users etc. So I know its working.
In my review model I write the following:
class Review(models.Model):
company = models.ForeignKey(settings.AUTH_USER_MODEL)
reviewer = models.ForeignKey(Reviewer)
rating = models.IntegerField(default=0)
review = models.TextField()
pub_date = models.DateTimeField('date published')
Instead of settings.AUTH_USER_MODEL I have also tried writing profiles.MyUser, 'profiles.MyUser' and MyUser.
I can successfully use the python manage.py makemigrations reviews command. But when I do python manage.py migrate I get errors no matter what version I use above.
The error I get is the following:
ValueError: Lookup failed for model referenced by field reviews.Review.company: profiles.MyUser
nejc92 comment was correct. I had migrated my database earlier before I set AUTH_USER_MODEL for the first time.
I removed my whole database and created new migrations for all apps and migrated everything again from scratch. It then worked.
Sounds like a bug(?) to me.

Categories

Resources