In the Django docs it was stated that besides the Primary Key, if another attribute has the setting "unique" set to True, an IntegrityError would be thrown if a model with the same attribute was being added to the database (much like how the PK is handled).
However, even after setting the unique = True to one of my fields, no IntegrityErrors are thrown, and in the manage.py shell, i'm blatantly saving models with identical fields where the unique = True, and it's letting me.
The PK of my models is unset, aka the AutoIncrementing Integer (i think this may be part of the problem).
Here is my unique=True field.
url = models.URLField("The URL", unique=True)
Nothing else is notable about this model, no Foreign relationships, nothing. Just A unique field which must be enforced (but is not), and an auto incrementing PK.
For the sake of some search engines, the PK must remain an auto incrementing integer.
Here is the SQLall for the model:
BEGIN:
CREATE TABLE `Model_model` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`url` varchar(200) NOT NULL UNIQUE,
....
Thank you.
Try dropping and recreating your database. The unique constraint will not be updated in database, if you add it after creating the database tables. If you don't want to lose your data, you need to add the property manually in the database.
Related
I have a particular situation which I need help clarifying.
I have an existing Oracle table with an auto increment ID as a primary key
I am creating a django model to sync with that table so i can make use of django's ORM methods such as save(), filter() etc.
I read from the django docs the .save() method can perform both a UPDATE and INSERT depending on if the values passed to the primary key results in a True value (i.e. not a None or null).
In my table I have two columns which together will form a composite primary key.
If I specify primary_key = True on the two attributes on the django model, do I need to remove the primary key tag from oracle table?
Also, do i need to specify the unique_together to tell the django model that they are unique or will it be able to derive the index i created in the django oracle table?
Thanks.
I have a model with a foreign key that references the username field of auth.User. The original field has a maximum length of 150. But Django generates a foreign key with a maximum length of 30.
In my app's models.py:
class Profile(models.Model):
user = models.ForeignKey('auth.User', to_field='username')
In django.contrib.auth.models:
username = models.CharField(
_('username'),
max_length=150,
Generated SQL:
CREATE TABLE "myapp_profile" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"user_id" varchar(30) NOT NULL REFERENCES "auth_user" ("username")
);
This only happens when referencing auth.User.username. If I reference a long field in my own model, the foreign key is generated fine.
Why is that? How can I overcome it?
Using Django 1.11.4 and Python 3.6.2. I tried PostgreSQL and SQLite and the problem occurs on both.
CLARIFICATION:
From the answers so far I think my question was misunderstood. I am not looking for a way to have long usernames. My problem is that the stock User model that comes with Django has one max_length (150), but when your model refers to it, the foreign hey has a shorter max_length of 30. Therefore if a user is registered with a username of 31 characters, I will not be able to create child objects of that user, because the foreign key constraint will be violated. And I need this because I have a REST API whose URLs nest resources under uses, that are referred by username, not ID. For example: /users/<username>/profiles/...
UPDATE:
I think the reason for this behavior is the undocumented swappable property of the User model. It is designed to be replaceable by custom models. However, the configured model must have its data in the initial migration of the app that defines the model. The migrations code seems to generate references to the initial migration of swappable models. I am using the default User model, and its initial migration sets the username to 30 chars. Hence my username FKs are 30 chars long. I am able to work around this with a RunSQL migration to alter the FK data type to varchar(15), but I am in doubt if it's the right thing to do.
Is recommended use short identifier, varchar(30) is a long number, something like 999999999999999999999999999999, when Django make identifiers always use the same number. I don't think that you are going to use so much users if you reach that number you should create another type of identifier. Remember the long of the user_id field is the id of the username and not the string
You can use this hack described in this SO answer,
but be very careful!.
Or you can use this package.
However, I think that, as described in this discussion, the best way would be to create a custom User model and do whatever you want there.
Hope it helps!
You must use custom user model.Taken from django docs.
150 characters or fewer. Usernames may contain alphanumeric, _, #, +, . and - characters.
The max_length should be sufficient for many use cases. If you need a longer length, please use a custom user model. If you use MySQL with the utf8mb4 encoding (recommended for proper Unicode support), specify at most max_length=191 because MySQL can only create unique indexes with 191 characters in that case by default.
I am using a custom primary key for a model that has a few ManyToManyFields. When I update the model and add an object to a ManyToManyField (using add(new_object)), I get an error signifying that its looking up the primary key using the id field (which perhaps exists in the intermediary table, but not in the model).
psycopg2.DataError: invalid input syntax for integer: "TL98GK"
LINE 1: ...WHERE ("placedir_place_place_categ"."place_id" = 'TL98GK' A...
I have been searching on SO for a while but havent been able to zero in the exact issue. I guess I may have to use custom through table for ManytoManyFields (as a punishment for using custom primary key) but I honestly dont want to go down that route.
Using Django 1.10 and Python 3
It seems the migration doesn't detect Foreign Key type changes well. It's a known bug. A workaround is mentioned here (i.e to explicitly change the field type to varchar(32)).
However, you may need to do more (like updating the constraints etc. on the table) depending on your use case. (For those interested to go that route, here is one example case with corresponding migration code).
(p.s I just decided to not use a custom primary key on models with manytomany fields)
I've been trying to create a model that has a primary key, but I don't want that primary key to auto increment.
I know I can specify the value each time, but I want the field to be required that I specify it (hopefully enforced by the database and django), and fail fast if I forget.
It seemed logical that I would be able to say auto_increment=False on my field, but that isn't supported by the field :(
Just create id field with primary_key=True explicitly in your model:
class SomeModel(models.Model):
id = models.IntegerField(primary_key=True)
That way it won't be auto-incremented, but it will still be an primary key.
I'm trying to reuse a primary key in one of my tables with SQLAlchemy and am getting foreign key constraint error.
In a nutshell:
PostgreSQL 8.4
Python 2.7
SQLAlchemy 0.7
I have 3 tables: User, Inventories and Devices. Inventories and Devices have a one-to-one relationship with User. User.id is Inventories.user_id and Devices.user_id foreign keyed.
I've got User, Devices and Inventories set up in models/ according to standard python practices.
Within interactive python I can issue the following commands no problem:
>>>newUser = User.create()
>>>newUser.device = User.create_device(<*args>)
>>>Session.add(newUser)
>>>Session.commit()
(an inventory record is automatically created in code)
Now, let's say I want to re-use User record 1 (it's the only record that will allow a method called reset in code for security and internal testing reasons)
>>>oldUser = User.retrieve(1)
>>>Session.delete(oldUser)
>>>Session.commit()
(confirm that user 1 no longer exists)
>>>newUser = User.create()
>>>newUser.device = User.create_device(<*args>)
>>>newUser.id = 1
>>>Session.add(newUser)
>>>Session.commit()
At this point I'll either get an eror that Key(id)=(<id>) is still referenced from table "devices" (or "inventories") where <id> is the newUser.id before re-assigning it to be id 1
I've looked into cascading and have tried the various options (all, save-update, etc) with no effect.
Any information pointing to where I'm going wrong would greatly be appreciated,
Thanks,
Krys
To address the error you're seeing, you could update the foreign keys on all of the Device and Inventory models associated with that User model before committing. You'll have to make sure that your User model doesn't auto-increment the id (i.e., that it isn't a PostgreSQL sequence).
For example, the SQLAlchemy model declaration should be
class User(base):
__tablename__ = 'user'
id = Column('id', Integer, primary_key=True, unique=True, nullable=False)
instead of
class User(base):
__tablename__ = 'user'
id = Column('id', Integer, Sequence('user_id_seq'), primary_key=True)
BUT, this is probably not the right way to do it! It would be a better design to use a sequence on User.id (like in the second model declaration), and add another field on the user table that indicates if the user is an admin (for the security/testing purposes you mentioned). This way you don't have to rely on magic numbers in your application (e.g., the user id) for application logic, especially security.
I ma not using SQLAlchemy, so i do not have a proper answer, but i can say that you must ask yourself what you want is really necessary?
Because,
You probably will break the data integrity, and that may couse serious problems.
You will need to break the auto-increment structure of the ID, so until then, you have to assign id's by hand or use a hand-written pre-save trigger to get a proper id.
If you have tables that have a User foreginkey that sets NOT null, thn you probably will have problem with freeing records related to a deleted user. If you do not null them, a re-used id will create a serious data-integrity problem (wrongly referanced relations)...
So first of all, you must decide if it worth it?
Since this is a problem that shouldn't be seen in production, just use SET CONSTRAINTS. You could use INITIALLY DEFERRED on your FOREIGN KEYs but I wouldn't recommend that since you're not dealing with a cyclic dependency that exists in production.