I found an interesting behavior in djangos syncdb mechanism, as I tried to sync my database for a new deployment last time.
I got two apps alphabet and core where core stores most of my models.
Now I created a new abstract model in alphabet with a code like:
class Compare(models.Model):
percentage = FloatField(default=0)
speakers = IntegerField(default=Speaker.objects.count())
class Meta:
abstract = True
and the referring model in the core app:
class Speaker(models.Model):
language = CharField(max_length=300)
When I try to sync the database with the syncdb command it fails with ProgrammingError because the table core.speaker does not exist.
Why is syncdb even checking abstract models? How can I solve this circular reference in my project?
(I am using Django 1.6 by the way)
Calling count() in the field definition is incorrect. Django tries to evaluate the query when the model is loaded. In your case, this is before the table has even been created. Even if the table had been created, the query would only be evaluated once each time the module loads, and would not update as instances were created and deleted.
You can pass a callable to a model field as the default, so you could try
speakers = IntegerField(default=Speaker.objects.count)
Then the query will be evaluated when the model instance is created.
Related
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.
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.
How to move models to another section in the Django admin site?
In my application module models.py, I have models that are displaying in admin tool in section called "Backend". I want them to display in another section under the name "Requests".
I tried the following
class TransportationRequest(models.Model):
...
class Meta:
app_label = _('Requests')
db_table = 'backend_transportationrequest'
It is works, but now I have issues with South as it is creating migrations to delete all of these models.
Your current issue is that you are trying to change the app_label and db_table, which ends up changing the location of the model data within the database. By default, the database table is generated as [app_label]_[model_name] (backend_transportationrequest in your case), so when you modify both of these, South detects that the model has been removed and created again, even if this isn't actually the case.
The Django migrations framework introduced in 1.7 should have fixed this, so it detects that the model was moved (instead of deleted and created). You may need to fake a migration along the same lines as this with south, which can be done by modifying the two mgirations it generates to not actually delete and create the tables, but rename them.
Django does not currently allow you to easily do this, as the admin site expects that each application that is registered has a unique app_label. You may have luck playing with the label property of your AppConfig, but this is specifically not recommended and has been historically known to cause massive headaches.
One possibility may be to create a clone of your previous model, and only use it to register the app with the Django admin. You would need to create a proxy model with the custom app_label and db_table. If this didn't work (though it should), the other option would be to clone the model as a unmanaged model using the app_label and db_table.
EDIT:
I fixed a few typos below
I added a zip file to a small app to demonstrate this problem here. You can download it and run python manage.py testselectrelateddefer after you syncdb and migrate.
I added a couple of observations below
I fix I am having a multi-table inheritance model as following:
class Image(models.Model):
# other fields are removed for simplicity
image = models.ImageField(upload_to="image")
class ItemImage(Image):
# other fields are removed for simplicity
display_name = models.CharField(max_length=50)
I want to query this model and defer the image field when I don't need the image (which is in the parent model). My container model looks somewhat like this:
class Item(models.Model):
item_image = models.OneToOneField(ItemImage)
The query looks like this:
test.models.Item.objects.select_related('item_image').defer("item_image__image").get(pk=1)
Django is throwing an error saying:
ValueError: u'image_ptr_id' is not in the list.
Django does not throw an error if I query for the field that is not in the parent model:
test.models.Item.objects.select_related('item_image').defer("item_image__display_name").get(pk=1)
Do you know how to fix this issue?
Observations:
As I mentioned above, this only happens if the deferred field is in the parent model; it does not happen if the deferred field is in the child model.
It does not matter if the parents field have any extra field.
I changed my former user model so that now it inherits from django's user model.
from django.contrib.auth.models import User
class UserProfile(User):
#fields..
but other models were pointing to my former model and now if i want to migrate, i am getting the error:
(user_id)=(9) does not exist in auth_user table.
reasonable error message. But what should i do now? i am really stuck. i am using django version 1.4
I made a screenshot of the error:
You don't say what version of Django you're using; if you're using 1.5, then you also need to set the AUTH_USER_MODEL setting to tell Django to use it (see the auth docs for more info). If you're on an earlier version, you probably don't want to subclass the User model at all, but create a profile (like your class name indicates) as a separate model and link it with a ForeignKey (see the old profile docs for more on that).
Did you also change the name of the model when you added the parent class? You probably want to set the name of the table in UserProfile so that it matches the old name. From the Django model docs:
To save you time, Django automatically derives the name of the database table from the name of your model class and the app that contains it. A model’s database table name is constructed by joining the model’s “app label” – the name you used in manage.py startapp – to the model’s class name, with an underscore between them.
For example, if you have an app bookstore (as created by manage.py startapp bookstore), a model defined as class Book will have a database table named bookstore_book.
To override the database table name, use the db_table parameter in class Meta.
So something like this would do the trick:
class UserProfile(User):
# other stuff
class Meta:
db_table = "myapp_user"
Hope this helps!