How to update my models.py from the database

Hi,

Some month ago, I start learning Django and I could build an App.
Due to a new job opportunity, I had to postpone that job and additional, I had the replace my laptop (mac). I kept all my Django files, but I laso need to reinstall Django on my new laptop.

The problem, I do remember about some steps, because I stupidly badly kept some note grrr.

I remember of those two commands

python3 manage.py makemigrations
python3 manage.py migrate

For now,

  • I installed Django 4.1.4
  • I imported my database with existing tables and a lot of measures
  • I configured my settings.py file to match to my database

My models.py file is still empty.

The first question:
I ran

./manage.py inspectdb

and I was surprised to have this error message

django.core.exceptions.ImproperlyConfigured: Could not find the GDAL library (tried “gdal”, “GDAL”, “gdal3.4.0”, “gdal3.3.0”, “gdal3.2.0”, “gdal3.1.0”, “gdal3.0.0”, “gdal2.4.0”, “gdal2.3.0”, “gdal2.2.0”). Is GDAL installed? If it is, try setting GDAL_LIBRARY_PATH in your settings.

gdal is geospacial library. Is a mandatory library??? What’s the reason of this message?

Second question:
As I want to update my models.py file according to my existing database, I do not remember of those commande work as well

python3 manage.py makemigrations
python3 manage.py migrate

As far as I remember, it will update my database acording to my models.py file, that right?
Is it

./manage.py inspectdb > models.py

or something close to it?

many thanks

Normally in this situation, you publish your code to a remote repository, like git, on github, gitlab, bitbucket or other similar platform.

The makemigrations command will generate new database schema changes based on your models.py file, and the migrate will apply these changes. If you don’t have the models.py, then this won’t work.

So, if you still has access to the database that contains the latest changes, then maybe the inspectdb will work.

This particular error indicates you are trying to use PostGIS or something similar for your database. Check your DATABASES setting to make sure you’re using the engine you expect to.

Dear @CodenameTim and @leandrodesouzadev

Thanks a lot for your replies and sorry for my late reaction.

That’s make sense. My database has geospacial coordinate (lat, long). I have two columns which contain latitute and longitude


This also remind me, I previously need to create a new column for Django, named ‘location’. I do not remember exactly why but that was required.

As I imported my lastest updated database (production) to ma local Django app, I do not have this ‘location’ columns yet and I need to create it. However, I have my previous modeles.py file, and I noticed this: (look at ‘location’ and ‘def save’

class Stations(models.Model):
    id_station = models.AutoField(primary_key=True)
    fields_id_field = models.ForeignKey(Fields, models.DO_NOTHING, db_column='fields_id_field')
    stations_types_id_stations_type = models.IntegerField()
    station_name = models.CharField(max_length=20)
    station_longname = models.CharField(max_length=45, blank=True, null=True)
    station_active = models.BooleanField()
    station_archive = models.BooleanField()
    location = PointField(blank=True, null=True, srid=4326)
    station_lat = models.FloatField(blank=True, null=True)
    station_lng = models.FloatField(blank=True, null=True)
    station_alt = models.DecimalField(max_digits=6, decimal_places=2, blank=True, null=True)
    installed = models.DateTimeField()
    station_description = models.TextField(blank=True, null=True)
    ttn_app_id = models.CharField(max_length=20)
    ttn_dev_id = models.CharField(max_length=20)
    ttn_hardware_serial = models.CharField(max_length=20)
    station_created = models.DateTimeField()
    station_order = models.IntegerField()
    map = models.BooleanField()

    class Meta:
        managed = False
        db_table = 'stations'

    def save(self, *args, **kwargs):
        self.location = Point(float(self.station_lng), float(self.station_lat))
        super(Stations, self).save(*args, **kwargs)

I remember, this copy the content of lat and lng to location for an entry. Then Django consider ‘location’ value.

My worry now, I do not how to well process. I already imported my databse but it does not contain the location column yet.

But next what should I do to make sure that the columns ‘location’ are filled?

Should I

  1. ./manage.py inspectdb → models.py
  2. Adding location = PointField(blank=True, null=True, srid=4326) and the def save function
  3. run ./manage.py makemigrations
  4. run ./manage.py migrate

Does it will create the ‘location’ column and adding the value?

Or should I first create the ‘location’ colum and the above step witl update the ‘location’ column?

What would you be your recommendation

PS: I fixed the GDAL issue

Thanks

If you’re using managed = False, those models won’t have migrations created for them. You need to manage those outside of django’s migrations.

You can delete and re-create your database. You will lose your data but the logic remains.
Use this method only as a last resort.
Here is a bash scrpit that I use in my case

#!/usr/bin/env bash

find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc"  -delete

rm db.sqlite3

python manage.py makemigrations
python manage.py makemigrations your_app1
python manage.py makemigrations your_app2
python manage.py makemigrations your_app_n
python manage.py migrate

Dear CodenameTim,
Thanks for your reply and sorry for my late reaction. I just did the following
./manage.py inspectdb > models.py
I compared the new generated models.py file with the models.poy file I archived.
I update the new generated models files and I added the following

location = PointField(blank=True, null=True, srid=4326)

and


    def save(self, *args, **kwargs):
        self.location = Point(float(self.station_lng), float(self.station_lat))
        super(Stations, self).save(*args, **kwargs)

I generate new database schema changes based on my models.py file with

(.env) ./manage.py makemigrations
(.env) ./manage.py migrate

Then I checked my database and the location field was not created.

If I understand you well, I should change


    class Meta:
        managed = False
        db_table = 'stations'

to

    class Meta:
        managed = True
        db_table = 'stations'

Then I should do again the both commands

(.env) ./manage.py makemigrations
(.env) ./manage.py migrate

The field location will be create, that’s correct?
(then I put back managed to False)

That might be one way to do it. I would recommend not using Django migrations to manipulate a non-django managed table though.