While Django documentation https://docs.djangoproject.com/en/3.1/ref/models/options/#managed
mentions the use of managed = False field in meta is used to not create migrations
I am still getting migrations when I call makemigrations.
This is the meta of the model:
class FieldOpsBooking(models.Model):
.
.
class Meta:
managed = False
db_table = 'field_ops_booking'
And I am getting this after makemigrations
python manage.py makemigrations
Migrations for 'user_analysis':
user_analysis/migrations/0001_initial.py
- Create model FieldOpsBooking
- Create model RewardManagementLeads
Migrations for 'od_engagement':
od_engagement/migrations/0001_initial.py
- Create model NormalisedTonnage
And it creates 0001_initial.py file with all migrations to apply as well.
Any help is appreciated
I checked my own projetcs with models having managed=False: YES there is an entry in migrations file like:
operations = [
migrations.CreateModel(
name='xyz',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
options={
'db_table': 'xyz_table',
'managed': False,
},
),
BUT: this will not create a new table on database level when you execute "makemigration".
Sorry if a insiste but your original solution was absolutely correct!!
this is from django documentation about abtract base class:
" ... since it is an abstract base class. .... and cannot be instantiated or saved directly."
You can set abstract=True in Meta to prevent model from migration as follows:
class FieldOpsBooking(models.Model):
.....
class Meta:
abstract = True
.....
Related
from django.db import models
class Town(models.Model):
name: models.CharField(max_length=70,unique=True)
country: models.CharField(max_length=30,unique=True)
class Meta:
pass
This is my model Town whith two attributes: name and country. When I create a migration in the initial_0001.py file only id column is shown
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Town',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
],
),
]
What kind of problem could it be?
The ID-Field is always automatically generated by Django when making migrations. You can specifiy your own ID field aswell, but using an auto-incremented like this is fine for your use case.
You also might want to get rid of the unique=True, as it would prevent adding multiple towns from the same country.
Create your model like this and redo your migration process:
class Town(models.Model):
name = models.CharField(max_length=70)
country = models.CharField(max_length=30)
When you have 'no changes detected' when making migrations, I usually follow these steps:
First, Delete migrations folder in project.
Then delete django-migration entries in your Database with this query:
DELETE from django_migrations WHERE app='yourAppName'
Then, create new folder ‘migrations” in app folder + init.py
Lastly, redo the migration process:
py manage.py makemigrations
py manage.py migrate --run-syncdb
I had the same problem, and this solved it. Hope it helps.
Instead of : it should be =
You also need to provide a default value for all the previous rows that were created
Then run python manage.py makemigrations
Run python manage.py migrate
class Town(models.Model):
name = models.CharField(max_length=70,unique=True, default='')
country = models.CharField(max_length=30,unique=True, default='')
class Meta:
pass
Unique Class or extend Class or Subclass in Python Django?
In the following situation, I have a feeling I need to ?extend? the Migration class instead of re-stating it in the second module. Or is a child class needed?
A goal here: To create a postgres table called venues. There is already a models/venues.py that seems to be set up ok.
migrations/0001_initial.py:
class Migration(migrations.Migration):
initial = True
dependencies = [('auth', '0012_alter_user_first_name_max_length'),]
operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, ...)),
('password', models.CharField(max_length=128, ...)),
...
migrations/0002_venue.py:
class Migration(migrations.Migration):
dependencies = [('app', '0001_initial'),]
operations = [
migrations.CreateModel(
name='Venue',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True...)),
('name', models.CharField(blank=True ...)),
('address', models.CharField(blank=True...)),
...
** models/venue.py:**
class Venue(models.Model):
name = models.CharField(blank=True, null=True...)
address = models.CharField(blank=True, null=True...)
city = models.CharField(blank=True, null=True, ...)
zip = models.CharField(blank=True, null=True...)
#gps_coords = models.CharField(blank=True...)
gps_lat = models.DecimalField(max_digits=14...)
gps_long = models.DecimalField(max_digits=14...)
description = models.TextField(blank=True, ...)
website = models.URLField(blank=True...)
contact_phone = models.CharField(blank=True...)
contact_email = models.EmailField(blank=True...)
contact_name = models.CharField(blank=True...)
def __str__(self):
return self.name + " " + self.description
Help?
Once you create your model class, you need to run python manage.py makemigrations and django will create a migration file. (Make sure you've added the app to the INSTALLED_APPS on project's settings.py
Once you run the makemigrations, you'll be able to see the migration file in your app's migrations folder. Having this file doesn't mean the table is created. It just represents the set of instructions that'll run on database when you run the migrate command.
When you have the new migration file, you can run python manage.py migrate, and that migration file will be applied to your database.
You can run the showmigrations command to see which migrations are applied on your database.
python manage.py showmigrations
or
python manage.py showmigrations app_name
I have a database in microsoft sql server. I created tables and views in it.
I ran py manage.py inspetdb view_Name > Models.py and populated my models.py file with managed=false. I also dont want my model to alter my database. I just want it for data retrieval.
Should I definitely run migrate/makemigrations?
After inspectdb should i apply makemigrations on my app or is just migrate enough? And also what are the points to remember while using inspectdb on an existing database.
Also I have something like the below in my models.py file for all columns
created = models.DateTimeField(db_column='Created', blank=True, null=True) # Field name made lowercase
Is having the fieldname in lowercase safe ? Or should I change it as it is in my column? And what are those db_column='Created', blank=True, null=True fields. Not all my views have such fields. Only a few have such values.
Models.py contents
# This is an auto-generated Django model module.
# You'll have to do the following manually to clean this up:
# * Rearrange models' order
# * Make sure each model has one field with primary_key=True
# * Make sure each ForeignKey has `on_delete` set to the desired behavior.
# * Remove `managed = False` lines if you wish to allow Django to create, modify, and delete the table
# Feel free to rename the models, but don't rename db_table values or field names.
from django.db import models
class test1table(models.Model):
created = models.DateTimeField(db_column='Created', blank=True, null=True) # Field name made lowercase.
class Meta:
managed = False
db_table = 'Test1'
Migrations file 0001_intial.py
# Generated by Django 2.1.14 on 2019-11-28 07:22
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='test1table',
fields=[
('created', models.DateTimeField(blank=True, db_column='Created', null=True
],
options={
'db_table': 'Test1',
'managed': False,
},
),
]
This solution solved my problem: I created a notepad file, pasted the code, changed the extension to .py and replaced the models.py file.
Success in migrate!
I'd like to add to existing models new CharFields via one common mixin or abstract model but names of these fields depend on configuraton. so one model will have someprefix1_title field and another model - someprefix2_title.
Is it possible to make this approach to work:
class AbstractModel(models.Model):
self.fields_prefix + '_title' = models.CharField(max_length=255, blank=True, default='')
class Meta:
abstract = True
class ModelOne(AbstractModel):
fields_prefix = 'someprefix1'
id = models.AutoField(primary_key=True)
class ModelTwo(AbstractModel):
fields_prefix = 'someprefix2'
id = models.AutoField(primary_key=True)
so ModelOne could have fields id and someprefix1_title.
upd: what about monkey-patching with add_to_class() will it work or it's an antipattern and should not be used?
Try using a factory pattern to set up your different versions of AbstractModel.
With this approach, you can more strictly control the way AbstractModel is modified by way of the factory function dynamic_fieldname_model_factory.
We're also not modifying ModelOne or ModelTwo after their definitions -- other solutions have pointed out that this helps avoid maintainability problems.
models.py:
from django.db import models
def dynamic_fieldname_model_factory(fields_prefix):
class AbstractModel(models.Model):
class Meta:
abstract = True
AbstractModel.add_to_class(
fields_prefix + '_title',
models.CharField(max_length=255, blank=True, default=''),
)
return AbstractModel
class ModelOne(dynamic_fieldname_model_factory('someprefix1')):
id = models.AutoField(primary_key=True)
class ModelTwo(dynamic_fieldname_model_factory('someprefix2')):
id = models.AutoField(primary_key=True)
Here is the migration generated by this code:
# Generated by Django 2.1.7 on 2019-03-07 19:53
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='ModelOne',
fields=[
('someprefix1_title', models.CharField(blank=True, default='', max_length=255)),
('id', models.AutoField(primary_key=True, serialize=False)),
],
options={
'abstract': False,
},
),
migrations.CreateModel(
name='ModelTwo',
fields=[
('someprefix2_title', models.CharField(blank=True, default='', max_length=255)),
('id', models.AutoField(primary_key=True, serialize=False)),
],
options={
'abstract': False,
},
),
]
Django models can be created with dynamic field names . Here is a simple Django model:
class Animal(models.Model):
name = models.CharField(max_length=32)
And here is the equivalent class built using type():
attrs = {
'name': models.CharField(max_length=32),
'__module__': 'myapp.models'
}
Animal = type("Animal", (models.Model,), attrs)
Any Django model that can be defined in the normal fashion can be made using type().
To run migrations:South has a reliable set of functions to handle schema and database migrations for Django projects. When
used in development, South can suggest migrations but does not attempt to automatically apply them
from south.db import db
model_class = generate_my_model_class()
fields = [(f.name, f) for f in model_class._meta.local_fields]
table_name = model_class._meta.db_table
db.create_table(table_name, fields)
# some fields (eg GeoDjango) require additional SQL to be executed
db.execute_deferred_sql()
The cleanest way would probably be using add_to_class():
ModelOne.add_to_class(
'%s_title' % field_prefix,
models.CharField(max_length=255, blank=True, default='')
)
Still this can be considered "monkey-patching" with all its downsides like making the app more difficult to maintain, have code that is more difficult to understand etc... Bu if your use case makes it really necessary to do something like that it would probably be the best solution as add_to_class() is some functionality provided from Django itself and has been stable for quite some time.
Technically, Its bad practice by creating model fields dynamically because this breaks the standard rule of keeping the database schema history using the django's migration process.
All you need is to store some fields under a django model which have flexibility to store dynamic fields. So I would suggest you to use the HStoreField.
Using HStoreField you can store data in a key-value pair format or json. So this will resolve the problem of storing the dynamic fields.
Here is an example given by Django docs.
from django.contrib.postgres.fields import HStoreField
from django.db import models
class Dog(models.Model):
name = models.CharField(max_length=200)
data = HStoreField()
def __str__(self):
return self.name
This is how you can query the HStoreFields.
>>> Dog.objects.create(name='Rufus', data={'breed': 'labrador'})
>>> Dog.objects.create(name='Meg', data={'breed': 'collie'})
>>> Dog.objects.filter(data__breed='collie')
<QuerySet [<Dog: Meg>]>
I hope this would resolve your problem. Please do let me know if you have any queries.
Thanks
I'm looking to use the PostgreSQL-specific ArrayField in my Django project, but it doesn't show up in the migrations after I run makemigrations. Any ideas why?
Django v2.1
Postgresql v9.6.6
# Models.py
from django.db import models
from django.contrib.postgres.fields import ArrayField
class MyClassName(models.Model):
udi = ArrayField(models.CharField()),
version = models.IntegerField()
Then I run: python3 manage.py makemigrations
# 0001_initial.py
migrations.CreateModel(
name='MyClassName',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('version', models.IntegerField()),
],
),
As you can see, the field 'udi' is suspiciously missing.
The problems are a comma at the end of the ArrayField() and CharField would need max_length too.
class MyClassName(models.Model):
udi = ArrayField(models.CharField(max_length=10))
version = models.IntegerField()
Run makemigrations again and you will get a migration you want.