Python Django: Remove null=true from Model CharField - python

Unfortunately I have a large model in production (Django 2.0.5) defined with null=True on CharFields:
class FooterMenu(models.Model):
text_de = models.CharField(verbose_name=u"Menüpunkt (de)", max_length=100, default='', blank=True, null=True)
text_en = models.CharField(verbose_name=u"Menüpunkt (en)", max_length=100, default='', blank=True, null=True)
text_fr = models.CharField(verbose_name=u"Menüpunkt (fr)", max_length=100, default='', blank=True, null=True)
Unfortunately there are plenty of NULL Values in the postgres DB already.
If I just remove the null=True and makemigrations the migrate tells me: cannot ALTER TABLE "doctor_footermenu" because it has pending trigger events
I understand this happens because of the NULL values in the table.
Is there a proven strategy that I can use?

Related

Django, tried to add a field to exsting model raises error

I Have a Django rest framework API which contained the following model:
class Points(models.Model):
mission_name = models.CharField(name='MissionName',
unique=True,
max_length=255,
blank=False,
help_text="Enter the mission's name"
)
latitude = models.FloatField(name="GDT1Latitude",
unique=False, max_length=255, blank=False,
help_text="Enter the location's Latitude, first when extracting from Google Maps.",
default=DEFAULT_VALUE)
longitude = models.FloatField(name="GDT1Longitude",
unique=False, max_length=255, blank=False,
help_text="Enter the location's Longitude, second when extracting from Google Maps.",
default=DEFAULT_VALUE)
Added User Field:
class Points(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
# rest of fields...
Iv'e added a User field, When trying to makemigrations and migrate it I get the following error:
django.db.utils.ProgrammingError: column find_second_gdt_points.user does not exist
LINE 1: SELECT "find_second_gdt_points"."id", "find_second_gdt_point...
Which I don't get, of course, this column does not exist.
This is what migartions are for, no?
Try adding default=None,
class Points(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, default= None)
# rest of fields...
These errors are usually because you need to include a default null value for the new field, as well as allowing it to be nullable, it should be as simple as:
class Points(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, default=None)
...
The reason being, is that the migration is applied to exisiting records in your database, as well as all future records. The migration needs to know how to populate the new field (column) in the DB for existing records...

Migrations being applied according to User in models.py instead of being applied according to migrations in the database

I have written a custom django migrations command as shown below
User = get_user_model()
def populate_asset_assignee(apps, schema_editor):
for user in User.objects.all():
user.save()
# Some more code
The user model looks as follows
class User(AbstractUser):
username = None
email = models.EmailField(max_length=50, unique=True)
cohort = models.IntegerField(blank=True, null=True)
slack_handle = models.CharField(max_length=50,
blank=True, null=True)
picture = models.CharField(max_length=255, blank=True, null=True)
phone_number = models.CharField(max_length=50, blank=True, null=True)
last_modified = models.DateTimeField(auto_now=True, editable=False)
password = models.CharField(max_length=128, blank=True, null=True)
location = models.ForeignKey('SomeCentre',
blank=False,
null=True,
on_delete=models.PROTECT)
# Some more fields
I added the location field recently and have the migrations for it which is applied after this custom migration has been applied. The problem I am having is that whenever I try to make the migrations on the test db or a new database, I get the error django.db.utils.ProgrammingError: column core_user.location_id does not exist which is being raised inside the populate_asset_assignee method when I try to do the user in User.objects.all()
Any ideas why location_id is beeing checked yet I haven't applied the migrations for the location field yet.

Do I need to make a migration if I change null and blank values on a Model field?

I have the following model
#python_2_unicode_compatible
class Booking(models.Model):
session = models.ForeignKey(verbose_name=_('Session'), to=Session, default=None, null=False, blank=False)
quantity = models.PositiveIntegerField(verbose_name=_('Quantity'), default=1, null=False, blank=False)
price = models.DecimalField(verbose_name=_('Price'), max_digits=10, decimal_places=2,
default=None, null=False, blank=False)
name = models.CharField(verbose_name=_('Name'), max_length=100, default=None, null=False, blank=False)
email = models.EmailField(verbose_name=_('Email'), default=None, null=True, blank=True)
phone_number = models.CharField(verbose_name=_('Phone Number'), max_length=30, default=None, null=True, blank=True)
Say I need to change my email and phone_number fields. I want them to have null=False and blank=False. Do these alterations require a new migration?
Yes they do. null=False requires a change to the database schema itself; blank=False does not, but Django needs a migration anyway so that the migration runner's internal graph of the model state is up to date.
Sure. To check it you can run python manage.py makemigrations --dry-run (the --dry-run doesn't save a new migration file, but shows if it's necessary)
https://docs.djangoproject.com/en/1.11/topics/db/models/#field-options
Django document says:
null
If True, Django will store empty values as NULL in the database. Default >is False.
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.
For change in null you need to migrate
For change in blank you need not to migrate, because its admin form related
Sure they do. Every change you made to your model fields (from simply altering the help_text to completely rename a model field) requires to makemigrations and migrate in order to reconstruct your model in the future.

Django ProgrammingError Caused By Model Field

I have a model called "news", defined below:
class News(models.Model):
title = models.CharField(max_length=30, null=False, blank=False, verbose_name="news title")
content = models.TextField(max_length=300, null=False, blank=False, verbose_name="news content")
cta = models.CharField(max_length=50, null=False, blank=False, verbose_name="news call-to-action")
mini_image = models.URLField(null=False, blank=False, verbose_name="news image helper")
is_promo = models.BooleanField(null=False, blank=False, verbose_name="promo code")
promo_benefit = models.DecimalField(max_digits=7, decimal_places=2, blank=False, null=False, default=0.00, verbose_name="promo benefit")
promo_duration = models.IntegerField(null=False, blank=False, default=0, verbose_name="promo duration")
date_published = models.DateTimeField(auto_now_add=True, null=False, blank=False)
def __str__(self):
return self.title
And when I try to access a template that uses the news model (whether I'm logged into admin trying to create a new instance or on a custom template), I get the following error:
ProgrammingError at /admin/myapp/news/
column omninectar_news.cta does not exist
LINE 1: ...app_news"."title", "myapp_news"."content", "myapp...
^
Any ideas on how I can fix this issue?
column omninectar_news.cta does not exist
That should be self-explanatory. Your database is out of date.
If you use South, migrate. Otherwise, try to remove the table "omnictar_news" and then run syncdb.
You should to delete the migrations folder and then
python manage.py migrate --run-syncdb
python manage.py migrate --fake appname

migrating an existing app via south

I have the following model -
class ToDo(models.Model):
todo_title = models.CharField(null=True, blank=True, max_length=200)
todo_status = models.IntegerField(choices=TASK_STATUS, null=True, blank=True)
assigned_to = models.ManyToManyField(OrgStaff, null=True, blank=True, related_name='assigned_to')
assigned_by = models.ManyToManyField(OrgStaff, null=True, blank=True, related_name='assigned_by')
assigned_time = models.DateTimeField(auto_now_add=True)
completed_time = models.DateTimeField(null=True, blank=True)
I then run python manage.py convert_to_south todoapp where todoapp is the name of the
app. Then I run python manage.py migrate todoapp.
Once that is done, I add another field in the above model -
class ToDo(models.Model):
todo_title = models.CharField(null=True, blank=True, max_length=200)
todo_slug = models.SlugField(null=True, blank=True)
todo_status = models.IntegerField(choices=TASK_STATUS, null=True, blank=True)
assigned_to = models.ManyToManyField(OrgStaff, null=True, blank=True, related_name='assigned_to')
assigned_by = models.ManyToManyField(OrgStaff, null=True, blank=True, related_name='assigned_by')
assigned_time = models.DateTimeField(auto_now_add=True)
completed_time = models.DateTimeField(null=True, blank=True)
Now I do a schemamigation - python manage.py schemamigration todoapp --auto and then python manage.py migrate todoapp doing this gives the following error -
Running migrations for taskbase:
- Migrating forwards to 0002_auto__add_field_todo_todo_slug.
> taskbase:0002_auto__add_field_todo_todo_slug
KeyError: u'todo_title'
Any idea why I am getting this error?
I banged my head, but unable to find the reason.
It's possible that prefixing 'title' and 'status' with 'todo_' is causing a collision with the name of the table fields. In fact, in the database Django is naming the fields todoapp_todo_todo_status, and South might just be confused. South does some creative things internally, hence the collision. I would suggest trying:
class ToDo(models.Model):
title = models.CharField(null=True, blank=True, max_length=200)
status = models.IntegerField(choices=TASK_STATUS, null=True, blank=True)
assigned_to = models.ManyToManyField(OrgStaff, null=True, blank=True, related_name='assigned_to')
assigned_by = models.ManyToManyField(OrgStaff, null=True, blank=True, related_name='assigned_by')
assigned_time = models.DateTimeField(auto_now_add=True)
completed_time = models.DateTimeField(null=True, blank=True)
I wanted to get pedantic, I could also point out that todoapp should be called todos, but that won't a difference to your project.

Categories

Resources