I have created 31 objects in my database. Now, for some reason, if I create a new object through the Django admin page, the new object will have an id of 33. Now, suppose I change I change its id and then delete it. If I try to create a new object, it's id will be 34. So, the id is always shifted by 2. I'm very new to databases and Django, is there any reason for behaving like this? Thanks
Note: I didn't upload any code, because I don't think that's the problem...
By default, the id is an integer that is always incremented at the creation of an object. It is also incremented such that ids of deleted objects are never used again.
The incrementation is handled by the database itself, not Django. For example, with PostgreSQL, the corresponding database field corresponding the "id" has the "PRIMARY KEY" constraint. It basically means that the field should be not null, and with no duplicates. Moreover the field will be associated with a sequence, that stores the id to use for the next row creation. To change this number, run this in the database shell:
ALTER SEQUENCE yourobjectstable_id_seq RESTART WITH 1234;
However, as emphasized in the comments to your question, this is something you should not do: it is better to keep the "uniqueness" feature of the primary key, even for deleted objects, since other tables may use the id to refer to a row in your main table.
Related
I have been working on an offline version of my Django web app and have frequently deleted model instances for a certain ModelX.
I have done this from the admin page and have experienced no issues. The model only has two fields: name and order and no other relationships to other models.
New instances are given the next available pk which makes sense, and when I have deleted all instances, adding a new instance yields a pk=1, which I expect.
Moving the code online to my actual database I noticed that this is not the case. I needed to change the model instances so I deleted them all but to my surprise the primary keys kept on incrementing without resetting back to 1.
Going into the database using the Django API I have checked and the old instances are gone, but even adding new instances yield a primary key that picks up where the last deleted instance left off, instead of 1.
Wondering if anyone knows what might be the issue here.
I wouldn't call it an issue. This is default behaviour for many database systems. Basically, the auto-increment counter for a table is persistent, and deleting entries does not affect the counter. The actual value of the primary key does not affect performance or anything, it only has aesthetic value (if you ever reach the 2 billion limit you'll most likely have other problems to worry about).
If you really want to reset the counter, you can drop and recreate the table:
python manage.py sqlclear <app_name> > python manage.py dbshell
Or, if you need to keep the data from other tables in the app, you can manually reset the counter:
python manage.py dbshell
mysql> ALTER TABLE <table_name> AUTO_INCREMENT = 1;
The most probable reason you see different behaviour in your offline and online apps, is that the auto-increment value is only stored in memory, not on disk. It is recalculated as MAX(<column>) + 1 each time the database server is restarted. If the table is empty, it will be completely reset on a restart. This is probably very often for your offline environment, and close to none for your online environment.
As others have stated, this is entirely the responsibility of the database.
But you should realize that this is the desirable behaviour. An ID uniquely identifies an entity in your database. As such, it should only ever refer to one row. If that row is subsequently deleted, there's no reason why you should want a new row to re-use that ID: if you did that, you'd create a confusion between the now-deleted entity that used to have that ID, and the newly-created one that's reused it. There's no point in doing this and you should not want to do so.
Did you actually drop them from your database or did you delete them using Django? Django won't change AUTO_INCREMENT for your table just by deleting rows from it, so if you want to reset your primary keys, you might have to go into your db and:
ALTER TABLE <my-table> AUTO_INCREMENT = 1;
(This assumes you're using MySQL or similar).
There is no issue, that's the way databases work. Django doesn't have anything to do with generating ids it just tells the database to insert a row and gets the id in response from database. The id starts at 1 for each table and increments every time you insert a row. Deleting rows doesn't cause the id to go back. You shouldn't usually be concerned with that, all you need to know is that each row has a unique id.
You can of course change the counter that generates the id for your table with a database command and that depends on the specific database system you're using.
If you are using SQLite you can reset the primary key with the following shell commands:
DELETE FROM your_table;
DELETE FROM SQLite_sequence WHERE name='your_table';
Another solution for 'POSTGRES' DBs is from the UI.
Select your table and look for 'sequences' dropdown and select the settings and adjust the sequences that way.
example:
I'm not sure when this was added, but the following management command will delete all data from all tables and will reset the auto increment counters to 1.
./manage.py sqlflush | psql DATABASE_NAME
I have this special case, where a customer requires a specific (legacy) format of booking numbers, the first one starts with the current year:
2015-12345
So basically every year I would have to start from 0
The other one is starting with a foreign-key:
7-123
So the first document created by every the user gets number 1, and so on.
Unfortunately there will be long lists starting with this booking number, so fetching all the records and calculating the booking number is not really an option. I have also thought about overriding the save() method, reading and auto-incrementing manually, but what about simultaneous inserts?
The best and most reliable way to do this is with a sql trigger That would completely eliminate the worries about simultaneous inserts. But overriding the save method is also perfectly workable.
Explicitly declare a primary key field and choose integer for it. In your save method if the primary key is None that means you are saving a new record, query the database to determine what should be the new primary key, asign it and save. Wherever you call your save method you would need to have a atomic transaction and retry the save if it fails.
BTW, you are starting for 0 each year. That's obviously going to be leading to conflicts. So you will have to prefix your primary key with the year and strip it out at the time you display it. (believe me you don't want to mess with composite primary keys in django)
I have little to no experience with databases and i'm wondering how i would go about storing certain parts of an object.
Let's say I have an object like the following and steps can be an arbitrary length. How would I store these steps or list of steps into an sql database?
class Error:
name = "" #name of error
steps = [] #steps to take to attempt to solve error
For your example you would create a table called Errors with metadata about the error such as an error_ID as the primary key, a name, date created, etc... then you'd create another table called Steps with it's own id, lets say Step_ID and any fields related to the step. The important part is you'd create a field on the Steps table that relates back to the Error that the steps are for we'll call that field again error_ID, then you'd make that field a foreign key so the database enforces that constraint.
If you want to store your Python objects in a database (or any other language objects in a database) the place to start is a good ORM (Object-Relational Mapper). For example Django has a built-in ORM. This link has a comparison of some Python Object-Relational mappers.
I want to save Entries in my database such that I can delete them later. To identify them, i put the key attribute in my class Entry in models.py as shown below:
class Entry(models.Model):
name = models.CharField(max_length=200)
key = models.IntegerField(unique=True,default=0)
Every time I start the server, I will find the biggest key that is in Entry.objects.all().
Every time I create the first new Entry after starting the server, I want to take the key I found in the very beginning, increase it by 1 and then set this as the key for my new Entry. For every subsequent Entry, I will just take the key of the previous element, increase it by 1 and. set it as the key for my new Entry
However, before I do this, I want to know what Django considers as unique. For example, if i added three entries initially with keys 1, 2 and 3, and then I delete the last element with key 3. If I then restart the server, the biggest key I will find is 2 and the next Entry I will add will have key 2+1 which is equal to 3 again.
Is this key unique?
It was entered before but I deleted that element right? So is uniqueness determined by whatever I entered in the past or just depending on the elements currently in the database?
Also, does Django keep a track of all the instances of Entry that I added, so that it would somehow know if I added an Entry with key 3 before?
Note that my data is stored in a file called db.sqlite3
Thank you.
Seems like you are looking for something that already exists; models have an id field by default which is unique and monotonic (newer entries have bigger id).
None of this has anything to do with Django at all. This is pure database stuff: unique constraints are handled exclusively by the database, in your case SQLite, although the functionality is exactly the same for other DBs as well.
Of course, a unique constraint only takes into account rows that actually exist: what would be the point otherwise?
There are other things to bear in mind with your proposal as well. In particular, there is the issue of race conditions: if you do a query to get the maximum key value, and then create a new row with key+1, you run the risk of another user in the meantime adding their own row at key+1. Much better, as Iris and ryanageles suggest, to use the built-in primary key which is already automatically defined as the id field.
try to add primary_key=True in your key field.
I'm trying to add a new entry by using the admin panel in Django
The problem is that I've already populated my DB with 200 records and if I try to add a new entry from admin I get a duplicated key error msg that keep increasing whenever I try the process again
error:
duplicate key value violates unique constraint "app_entry_pkey"
admin.py:
admin.site.register(Entry)
model:
class Entry(models.Model):
title = models.CharField(max_length=255)
url = models.TextField(max_length=255)
img = models.CharField(max_length=255)
def __unicode__(self):
return self.title
If you created the database table using Django, then most likely your auto_increment value was not updated when you imported the data outside of Django.
It may also be that when you imported the data you did not give the 200 records each their own unique primary key. I think that (some versions of) SQLite will sometimes allow that in mass imports.
MySQL
For example, I’m looking at a MySQL table in Sequel Pro and see that it has an “auto_increment” value of 144. This means that the next primary key value will be 144.
You can see this value for your table (in MySQL) using:
SHOW TABLE STATUS FROM databaseName where name="entry"
Replacing “databaseName” with the name of your Django database. Other database software will likely have different syntax.
You can set the next auto_increment value (in MySQL) using:
ALTER TABLE databaseName.entry AUTO_INCREMENT ###
Again replacing databaseName with the name of your database; and as before, the syntax may vary depending on the database software you’re using.
If this doesn’t help, you may find it useful to show the table’s status and copy that into your question. This might also be useful in tracking down the issue:
SHOW CREATE TABLE databaseName.entry
Postgres
In Postgres, you can get the current value of the auto increment variable (called sequences in Postgres) using something like:
SELECT last_value FROM app_entry_pkey;
And you will likely set it to a new value with something like:
ALTER SEQUENCE app_entry_pkey RESTART WITH ###
or
SELECT setval('app_entry_pkey', ###)
Note, though, that I do not have a Postgres database handy to test these on. You may also find the following commands useful:
SELECT MAX(id) FROM entry
SELECT nextval('app_entry_pkey')
The latter should generally be larger than the former, and note that “id” is the name of the column in your “entry” model’s table; it may be different in your table. See http://www.postgresql.org/docs/8.1/static/functions-sequence.html for more information.