I created a model for posts in Django and I'm trying to update one of the fields in the database (MySQL).
I have the following block of code:
model.py
class Post (models.Model):
title = models.CharField()
preamble = models.CharField()
body = models.TextField ()
createdAt = models.DateTimeField(auto_now_add=True, blank=True)
I want to add another field called author author=models.ForeignKey(User, on_delete=models.CASCADE
Also, I want to change the name of one of the fields from preamble to introduction
Whenever I run the command python manage.py makemigrations and then python manage.py migrate, I get an error which terminates the migration process. it's telling me that the field preamble which I have in my database is not recognized. Is it possible to update preamble to introduction?
Ensure you have a migration of the initial state of your app, before any modifications.
Rename the preamble field to introduction in your model, making no other changes.
Run makemigrations. It should ask you whether it was a rename.
Add the author foreign key.
Run makemigrations. It should ask you for a default for the user field if it's not nullable; 1 should hopefully refer to the first user created in your system.
Run migrate.
This should be work:
delete the SQLite database and also migrations directory
change the model
then run the migrate command
Related
from django.db import models
from datetime import datetime
from django.contrib.auth import get_user_model
User = get_user_model()
class Blog(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
headline = models.CharField(max_length=250)
content = models.CharField(max_length=2050)
time_created = models.DateTimeField(default=datetime.now, blank=True)
def __str__(self):
return self.user.username
every time I migrate this
"(venv) PS C:\Users\user\Desktop\APPS\web_app_project> python manage.py makemigrations"
I always get this message:
"It is impossible to add a non-nullable field 'user' to blog without specifying a default. This is because the database needs something to populate existing rows.
Please select a fix:
Provide a one-off default now (will be set on all existing rows with a null value for this column)
Quit and manually define a default value in models.py.
Select an option:"
How do I go about this
Because you've added the non-nullable field user to Blog Django needs to add a user to all instances of blogs in the database, both new ones and existing. If you've created a blog instance in the database, what should Django do with its new user column? That's what it is asking you.
Only if there is no data in the database or you are completely OK with losing data, you can migrate your app to zero with python manage.py migrate <your app name> zero (You might want to reverse to migration besides zero. You can read more about reverse migrations). This will effectively undo all of your migrations for that app. You can then delete the existing migrations for that app and run makemigrations again. Django will no longer complain about the non-nullable field user, as this results in a migration that creates a Blog table with a user field, instead of a migration that attempts to add a user field to an existing Blog table. Once again, do not do this unless you are OK with losing data. This should never be done if your app is already running in production, but it is OK if you have never deployed the app and have no "real" data, and you are still in the initial development phase. Also, make sure you have a backup of deleted migrations in case you need to add them back.
As others have suggested, you can create a default user model that is used as the one-time default to add users to Blogs. For example (in Django shell)
from django.contrib.auth import get_user_model
User = get_user_model()
user = User(username='default_blog_user')
user.set_unusable_password() # Nobody should be able to log in as this user
user.save()
print(user.id) # keep this ID
Then, in the migration, you can use whatever that user.id value was as the one-time-default. But this once again assumes that you haven't deployed to production, as the one-time-default and the IDs in development and production may not match.
If you have already deployed to production, I think the only thing you can do is make the user field nullable for the sake of your migration, but assert that it is not null in your programming logic. For example, by adding a validator to the field.
Side note: instead of running get_user_model in your models module, you should do this:
from django.conf import settings
class Blog(models.Model):
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
# etc.
When you define a foreign key or many-to-many relations to the user model, you should specify the custom model using the AUTH_USER_MODEL setting.
source
You could probably get away with adding the user manually by using the python shell• python manage.py shell then import the required models.
Read more from a similar question here:
How to use the python shell
https://stackoverflow.com/a/5150535/15383032
Maybe add a UUID to your User Model and make the fields that require a user in other models a CharField that stores the Users UUID.
In the middle of the project, I was faced with the fact that I needed to expand my user model. Since it is very problematic to create a custom model at the moment, I decided to use the onetoone field and everything is successful, but there is a question. I would like to add a relationship to my user model proxy for existing users and set permissions for them. How can I do that? I need to set start value for all users
class UserPermission(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
start = models.BooleanField(default=True)
professional = models.BooleanField()
team = models.BooleanField()
last_update = models.DateTimeField()
If you can do this from your shell, then follow only step 2. If you want to do it from a migrations file, follow steps 1-3. (From the shell is easier).
In your terminal: run python manage.py make migrations app_name --empty
Add a function in your new migrations file that does the work you want to do for existing users.
def add_perms(apps, schema_editor):
UserPermissions.objects.bulk_create([UserPermissions(user_id=user_id) for user_id in User.objects.values_list("id", flat=True)], ignore_conflicts=True)
If you're doing this from your shell, you don't need the function itself. Just what it runs. UserPermissions(user_id=user_id) is just a base and you should add the defaults alongside that user_id part.
In the operations list, write:
operations = [
migrations.RunPython(add_perms)
]
In my django project I use django-registration reusable app. I install this app and run syncdb. It's create for me table 'registration_registrationprofiles' in my database. Then I create a new app and write this code in my models.py:
class Comments(models.Model):
text = models.TextField()
pub_date = models.DateTimeField(auto_now=True)
user = models.ForeignKey('registration_registrationprofiles')
And run manage.py makemigrations and it throw me exception:
ERRORS:
comments.Comments.user: (fields.E300) Field defines a relation
with model 'registration_registrationprofiles', which is either
not installed, or is abstract.
How I can fix this problem?
Try this:
from registration.models import RegistrationProfile
and then:
user = models.ForeignKey(RegistrationProfile)
Migrations can have dependencies declared. Usually, makemigrations does a good job with that, but it looks like it missed it this time. I suggest you locate the migration file it created (in your_app/migrations) and check its dependencies. It should look like this:
class Migration(migrations.Migration):
dependencies = [("registration", "0042_some_migration")]
# operations...
The key here it the dependencies array should reference the registration app, and the latest migration (or at least the latest you depend on).
Then manage.py makemigrations will detect the dependency and run migrations in the correct order.
I added a many-to-many field to an existing model and was expecting syncdb to create a new table, but there's nothing there. This is what the model looks like:
class Author(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
email = models.EmailField()
def __unicode__(self):
return "{0} {1}".format(self.first_name, self.last_name)
class Book(models.Model):
title = models.CharField(max_length=100)
authors = models.ManyToManyField(Author)
def __unicode__(self):
return self.title
Running sql myapp prints the correct statements with the new table, but this is not reflected when I run syncdb. validate also returns no errors. Does anyone know what could be the matter here? Or a better diagnostic?
The syncdb command does not create many to many tables for existing models by design. This decision is explained on ticket 2229.
That leaves you with a few options.
If you don't have any data in your Book model, drop the table and rerun syncdb. Django will recreate the book table and the many to many table.
Use the dbshell command, and create the many to many joining table using the output of sql myapp.
If you're doing multiple schema migrations with Django, make friends with South.
I found this explanation at the django docs useful: SchemaEvolution.
The de facto standard for database migration is Django South.
Its not perfect, but, it works pretty well. You should always check(and edit if necessary) your migration file before running it, to make sure that it actually does what it supposed to do.
You can check out their tutorial here.
Also, if you run:
python manage.py inspectdb > somefile.txt
You can get quickly check out if your database structure is matching your django models.
I have a new field in the Client called note which has a one-to-one relation with Notes.
I want to be able to add the note column under the Client table in mysql. It does not work when I use python manage.py syncdb. So I would like to know how to add a one-to-one field in mysql to an existing table.
models.py
class Note(models.Model):
datetime = models.DateTimeField(default=datetime.now)
user = models.ForeignKey(User)
note = models.TextField()
def __unicode__(self):
return unicode(self.name)
class Client(models.Model):
note = models.OneToOneField(Note) # new
def __unicode__(self)
return unicode(self.user)
Syncdb doesn't change your database in order not to destroy your data. See django book.
You can update the database manually or use an automated migration tool (at your own risk) like South.
EDIT:
In django book, you can also read detailed instructions about manual changes along with SQL examples. Other useful information can be found in MySQL manual.
You didn't say what the application name is so I'll assume it is fooapp.
First look at the SQL Django would have used to create the relevant tables:
python manage.py sql fooapp
For additional fields run this sql command:
ALTER TABLE fooapp_client ADD ...
where ... is the field declaration you saw in the output of "manage.py sql fooapp"
Remember to also execute any index/constraint commands in the "manage.py sql fooapp" output that operate on the new field.