Im working on a data migrations which needs to change a Foreign key to a different model and alter all the existing instances foreign keys to the new Model pk. I think this can be achieved with data migrations on Django. My question is:
¿How can I access previous versions of my models in order to perform the data migration?
I would like to do something like this:
MyPreviousModel = previousModels.MyModel
ModelAfterMigration = afterMigrations.MyModel
all_previous = MyPreviousModel.objects.all()
for element in all_previous:
element.previous_fk = new_foreignKey
ModelAfterMigrations.create(element)
Use the versioned app registry to get the model, rather than an import statement.
def my_migration(apps, schema_editor):
MyModel = apps.get_model("my_app", "MyModel")
The first argument passed to your migration worker function is an app registry that has the historical versions of all your models loaded into it to match where in your history the migration sits.
Related
I had this model where the price was an Integer Field. I did run migrations and all was fine.
from django.db import models
class Bill(models.Model):
price= models.IntegerField()
Then due to requirement changes, I had to make the price field as JSONField which would store the price value based on certain keys similar to this
price={"actual_price":100, "tax_price":20}
I made the changes in the model like below:
from django.db import models
class Bill(models.Model):
price= JSONField(blank=True, null=True)
I performed makemigrations and migrate operations, the migrations are not getting reflected in DB. There are no errors as well. I get the error "Column: price does not exist" when my code tries to read from the DB.
I tried the following things by referring to StackOverflow other questions:
Removed the field. Run migrations, applied it. Removing field works
fine. But when I add the field back instead of considering it as new
field to be added, it just doesn't get inserted.
Removing the migrations from the migrations.py folder, re-running it and re-applying it.
Please note:
I am using Postgres DB. The same thing works for SQLite DB which is in-house provided by Django but not for Postgres.
Losing the data is not a feasible option as the DB data is of production server.
I tried adding the column manually through PostGres using the query ALTER Table ADD Column which worked perfectly fine. This is a hook that I used which was used as a last resort.
The data in the initial integer field was present for some of the records before applying the updated migration. Strange thing is I also wasn't asked by Django to set the value in case I want to override the data.
I need the Django migrations for applying the changes automatically to work. Due to this issue, only the addition of new column and modifying the datatype of the column is not working at all (Rest operations like removing the column works).
Since there was no other option and no solutions provided, I had to point my application to new DB in PostGres and then it started working fine. Lesson Learnt for future:
Not to update directly the datatype of the model attribute and then apply migrations.
First Remove the field, apply migrations and then create the field with same name and required data type and then apply migrations.
Use the same Database that you are using for production in your local itself. In this way, you can avoid conflicts after deploying to production. I had used SQLite for local and PostGres for Production. From now on, I will use PostGres for Local also so that I can debug issues in my local itself.
I'm developing a Django application that uses mongodb in a part of it. My database schema is changing (some fields are deleted/added continuously), so how to integrate it with Django in a way that accepts the changes without changing the old data, and without affecting the search queries?
I have searched about the available libraries, and I found the below:
mongoengine and django-mongodb-engine: mongoengine is not supported for a while now and not updated, also django-mongodb-engine required a forked old django-nonrel package. This matches with the question: Use pymongo in django directly
djongo: Initially it is working fine with the most updated versions of python and Django, and it accepts the changes in my database models without migrations and Django admin panel is working fine. Later on, after applying some changes, I have faced an issue when it comes to querying the database or listing the data in the admin panel. The old data fails to fit with the new model if the change includes deleted fields.
pymongo: The disadvantage is that I cannot use django models or panel and I have to build my own database abstract layer, but the advantage is about the higher control that I will have over the database. It will be like the first solution in Use pymongo in django directly , then I can build some layers for the different database structures that I will have
Using djongo
Let's say that I have a model called Test:
models.py
from djongo import models
class Test(models.Model):
x = models.CharField(max_length=100)
y = models.CharField(max_length=100)
I have created a new object as below:
{
_id: ObjectId("..."),
x: "x1",
y: "y1"
}
Then, I have removed the y field and added a new field called z, then I have created a new object, so it is created as below:
{
_id: ObjectId("..."),
x: "x2",
z: "z2"
}
Now, I want to extract all the collection data as below:
python manage.py shell
>>Test.objects.all()
Error as field "y" is not exist in the model
>>Test.objects.filter(z="z2")
Error as field "y" is not exist in the model
I can understand that it cannot be mapped to the new changed model, but I want the old fields to be ignored at least without errors exactly like the queries in mongodb directly.
According to my request, it is the wrong approach to use djongo? Or is there any workaround for to handle that issue? If no, how to apply that properly using pymongo? I expect to change my collection fields with addition or deletion anytime, and extracting all the data anytime without errors.
I'm trying to create a database view from django instead of associate a model from an existing database table. I'm new in django world and i don't know how how can i do this. Anyone have any ideia where to start look to solve this? Maybe this is not possible but can you see any alternative solution?
I understand how to define a model that as no management, by consider managed=False like i found on django docs, but how can i create an customized SQL view in my model class?
something like this:
Class myModel(models.Model):
Object = models.raw("CREATE VIEW foo AS SELECT * FROM table.A")
class Meta:
db_table = 'myview\".\"mymodeltable'
managed = False
With inspectdb management command, you can obtain the models definition from existing tables. To do that, you need to configure your settings.py file to have access to the database you want to work with and then do:
python manage.py inspectdb > models.py
You will see that it also automatically sets the managed=False. From that point, you can start querying its objects with typical objects.all(), objects.filter() and this stuff
Note: Don't forget to add the app with the imported models to the INSTALLED_APPS variable of your settings.py file.
Unfortunately maybe this is the final answer that can be found on DjangoDocs
This is useful if the model represents an existing table or a database view that has been created by some other means.
The import statement import the needed parts. but is the "user" class already made when you put that into your installed apps? or do you still need to clarify in models.py in order to make the table in the db? or can someone expand on how to use django users and sessions? I'm looking over the django docs right now and they all just go over how to use the thing once. they never put the code in a syntax where users are going to be the ones using the code through a browser and not you through a python shell.
All installed apps can contribute to the database schema. django.contrib.auth.models contributes, among others, the auth_user table behind the django.contrib.auth.models.User model, therefore you do not have to worry about recreating it unless you have a specific reason to do so.
There's a number of things going on here. As you're aware, Django comes with a number of "contrib" packages that can be used in your app. You "activate" these by putting them into your INSTALLED_APPS.
When you run python manage.py syncdb, Django parse the models.py files of every app in INSTALLED_APPS and creates the associated tables in your database. So, once you have added django.contrib.auth to your INSTALLED_APPS and ran syncdb, the tables for User and Group are there and ready to be used.
Now, if you want to use these models in your other apps, you can import them, as you mention, with something like from django.contrib.auth.models import User. You can then do something like create a ForeignKey, OneToOneField or ManyToManyField on one of your models to the User model. When you do this, no tables are created (with the exception of ManyToManyField; more on that in a bit). The same table is always used for User, just as for any of your own models that you might create relationships between.
ManyToManyFields are slightly different in that an intermediary table is created (often called a "join table") that links both sides of the relationship together. However, this is purely for the purposes of that one particular relationship -- nothing about the actual User table is different or changed in any way.
The point is that one table is created for User and this same table is used to store all Users no matter what context they were created in. You can import User into any and all of your apps, create as many and as varied relationships as you like and nothing really changes as far as User is concerned.
If the table name or something else does not fit in your needs you can always just extend the User model.
from django.contrib.auth.models import User
class Employee(User):
...
Any class extending Model class in models.py contributes to database schema. That means, django search your (and also django core) model.py files and looks for any class that extends Model like:
some models.py
class SomeModel(Model):
...
...
class Otherthing(Model):
...
that is also applies for django core code files. Since all Database tables named using application label and model name, database ables created by django also have that...
For example,
from django.contrib.auth.models import User
If you track file hierarchy django -> contrib -> auth and open models.py file, you will see related model. Ther are also other Model classes in here, like Permission and Group models.
Since these models are under auth application, database tables are auth_user, auth_perission and auth_group
When you run manage.py syncdb command for the first time, django will create these tables...
I am having hard time to understand how to make field value unique while using Django MongoDB.my models.py has a model:
class Projects(models.Model):
projectName =models.CharField(max_length = 100,unique=True)
projectManager = EmbeddedModelField('Users')
Here i want whenever a new project instance is added it should have unique projectName.But this code is not working out as it allows adding same value for projectName and doesn't give me error.I read its possible to make field value Unique by using indexes in pymongo but how do I do it in Django MongoDB.
Answer to my own question is I had to add unique=True for model field before doing syncdb.Thanks to culebron.Its working now