When I inspect the Trac database I get:
class TicketChange(models.Model):
ticket = models.IntegerField()
time = models.BigIntegerField()
author = models.TextField(blank=True)
field = models.TextField()
oldvalue = models.TextField(blank=True)
newvalue = models.TextField(blank=True)
class Meta:
managed = False
db_table = 'ticket_change'
With not primary key:
>>> TicketChange.objects.all()
DatabaseError: column ticket_change.id does not exist
LINE 1: SELECT "ticket_change"."id", "ticket_change"."ticket", "tick...
Because I need to specify a pk but the original primary key of ticket_change in Trac is:
Primary key (ticket, time, field)
But It's not possible in Django: Django Multi-Column Primary Key Discussion.
If I define time like pk I can't add two tickets changes in the same time.
What can I do?
You're right. It's a known problem. So the only solutions are hacks (sort of).
Your best option is to use django-compositepks. The drawbacks are that it doesn't really support model relationships, so you will not be able to navigate to any relationship from your composite-pk model. However, looking at your TicketChange model this doesn't seem like an issue (unless you have more models with relationships to this one).
Another option would be to manually add the id column (and make sure to apply any additional changes to the db), thereby creating the new one-column primary key. A third option (and what I would probably do), pretty similar to the last one but cleaner, would be to create a new database from scratch and then populate it with a script by fetching the data from your existing legacy db.
Sorry I don't have any better solution for you, that's the way it is. Legacy dbs and django are always a headache, have gone through some similar processes myself. Hope this helps!
This is a use case the Django ORM simply does not support. If you're able to modify the database schema, add an additional column that will serve as the primary key for Django: An integer field with AUTO_INCREMENT (MySQL) or a SERIAL (PostgreSQL). It shouldn't desturb your other applications using the table since it will be managed by your database when new records are inserted. You can still use the actual primary key when making queries through the ORM:
ticket_change = TicketChange.objects.get(ticket=1234, time=5678, field='myfield')
If you’d like to specify a custom primary key, specify primary_key=True on one of your fields. If Django sees you’ve explicitly set Field.primary_key, it won’t add the automatic id column.
Each model requires exactly one field to have primary_key=True (either explicitly declared or automatically added).
https://docs.djangoproject.com/en/3.1/topics/db/models/#automatic-primary-key-fields
Related
I am new to django and I am facing some problem.
This was my previous model.
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
I added some data to this model.
After that I added one more field to it.
Now my model looks like this..
class Blog(models.Model):
name = models.CharField(max_length=100)
tagline = models.TextField()
age = models.IntegerField()
When I ran the command python manage.py makemigrations I got the following error which is obvious.
You are trying to add a non-nullable field 'age' to blog without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Select an option:
I don't want to add default so I deleted the table contents by accessing db.sqlite3
But again after running python manage.py makemigrations I am getting the same error.why?
Even though you have deleted the table, any changes to your Django model will always refer to the previous migration of that model, hence it still requires you to set a default value. If you're still in development, then you could delete the migrations for that model and then makemigrations again. But, this is terrible practice and you should never do this unless you are consciously squashing your models, the better way is to do what Django is telling you and set a default. This'll help in the long run anyways with error handling.
The other answers address how to set defaults quite well.
When you add a new field (i.e., column) to a database table, that field applies to all rows in the table...the existing ones and any new ones. If the field cannot be null, then some value must be specified for all of the existing rows.
By default, IntegerField() is non-nullable. This explains why you are getting the warning. You have a few options:
You can choose a default "one-off" initial value like Django suggests. All existing rows will use this value for the new field.
Assign your own values to each existing row for the new field.
Use the blank and null arguments in your model field to allow the field to accept null values.
For the last option, you'd do this like so:
models.IntegerField(blank=True, null=True)
But that might not be the best choice depending on your use case. If nullable values don't make sense for your field, I would avoid making the field support nulls.
age = models.IntegerField(null=True)
Django models fields are null set to true by default.
The way you can solve this:
Delete the Blog table from the database.
Delete the migrations folder from the app that contains Blog model.
Remove all data from django_migrations table.
Now run makemigrations and then migrate command.
Hope this will solve your problem.
Do what Django is telling you, then you can remove the default attribute if you don't need it. But it's a good practice to keep it anyway
Say you have the following legacy model:
class Foo(models.Model):
bar_id = models.IntegerField(null=True, blank=True)
# more fields
bar_id is supposed to refer to a primary key from the Bar model, but for some reason, it's not registered as a foreign key. Now, how can I filter out all the Foos that do not have corresponding Bar objects?
We can make a list of primary keys of Bars, and then filter out all Foos that refer to such primary key.
Foo.objects.exclude(bar_id__in=Bar.objects.all().values_list('pk', flat=True))
This is a QuerySet that will give all Foo objects with an "invalid" bar_id (so an id that refers to a non-exiting Bar).
But it is better to use ForeignKey since then most databases will enforce this constraint in a transparant way. As a result, the database typically ensures that no such rows can exist at all. Typically you also add triggers to it what to do in case the Bar object that is referenced is for example removed.
Reading some of the comments makes me understand that OP would prefer to implement a foreign key but can not do so because of corrupt / missing data into database.
Two solutions:
Mark the column as foreign key in your Model, but do not enforce it
in the database (use --fake flag while migrating using manage.py
file. This approach helps in actually better defining your business
/ Model logic and enforces data Integrity in local development and
environments.
Mark the column as foreign key in your Model and use
db_constraint=False flag. Read more here. Use this approach
for legacy systems where data integrity has already been compromised
and you just need to use Django's ORM joins the natural way.
I have a PSQL database with portfolios and their values each day for a few years.
I'm using Django to develop a web app behind this. I used this link:
https://docs.djangoproject.com/en/1.10/howto/legacy-databases/
to generate the models for Django. I did not explicitly define a primary key in my database or in the models.py file. Is it necessary to define a primary key in order to retrieve data from the DB?
If so, is there a way to make multiple fields a primary key? In this case it has to be the portfolio ID and the date, since there are multiple portfolios and dates.
Thanks for any help!
It is not necessary to define primary key in your code. By default it is taken care by django. It creates variable called id as Primary key.
However you can explicitly define primary key by using primary_key = True option.
Example.
key1 = models.IntegerField(primary_key=True)
If you want to define composite primary key then you can have a look at this question How to create composite primary key
Hope this helps !
By default, django created a column called id for each table, which is the PK.
You can use your own PK using primary_key=True.
Also, you can use unique_together Meta option, but you still need to use another column as PK.
If what you want is to use composite primary key, you need to use another thirdparty solution.
I faced the same issue and it was solved by replacing IntegerField by AutoField as below,
order_id = models.IntegerField(primary_key=True)
by
order_id = models.AutoField(primary_key=True)
And it worked !!
PostgreSQL dont make auto pk field. so you need to make it manually.
models.py
test = models.AutoField(primary_key=True)
you dont need unique=True, because pk is always unique
or you can use this, to generate a auto pk field
settings.py
DEFAULT_AUTO_FIELD='django.db.models.AutoField'
I've got a bunch of previously created database entries of a model class I created, called Equations. I created a new type of model, EquationGroup, and I want to be able to link the existing Equations in the database to newly created EquationGroups. How would I do that?
Update:
I forgot to mention that I've got a ForeignKey relationship in Equation to EquationGroup.
Here is short version of my models.py
class EquationGroup(models.Model):
name = models.CharField(max_length=50)
def __str__(self):
return self.name
class Equation(models.Model):
name = models.CharField(max_length=50, null=False, blank=False)
group = models.ForeignKey(EquationGroup)
You can create a script that goes through all the equations and attaches them to equations groups. Using Equations.objects.all() you can get an iterable of all of the equations objects.
You can then go through in a for loop and assign each one to the specified Equations group.
Example:
for equation in Using Equations.objects.all():
equation.equationGroup = some_group #based on however you specify what goes in a group.
equation.save()
Do you want to make associations Equation <-> EquationGroup? If so, you should add OneToOne relation field. Look here for examples.
There is many other ways to add relations, like ManyToMany and ForeighKey.
Do you need to associate instances? In this way, you should have data to find related data and save it as OneToOne/ForeignKey.
How do you plan to update the database with the new change to your equation model? If you are using django 1.7+ you can use the built-in migrations. If not you will need to look to something like South. Thirdly you can alter the database by hand.
Anyway, the reason i bring up migrations is because you cant add a null foreign key field. When adding the field to the database table you will need to specify a default FK value, that you can go back and update using #user3154952 suggestion.
Depending on the database you are using, you may be able to remove the foreign-key constraint check temporarily. Allowing you to add the new field to the table without a dummy value, by allowing null.
I have a legacy database with an integer set as a primary key. It was initially managed manually, but since we are wanting to move to django, the admin tool seemed to be the right place to start. I created the model and am trying to set the primary key to be an autofield. It doesn't seem to be remembering the old id in updates, and it doesn't create new id's on insert. What am I doing wrong?
The DB is responsible for managing the value of the ID. If you want to use AutoField, you have to change the column in the DB to use that. Django is not responsible for managing the generated ID