So I have this as a base model:
class BaseModel(models.Model):
"""
base class for all models enforcing a UUID
"""
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
class Meta:
abstract = True
Programmatically, from my Django classes, when I derive from this class and call .save() a new object it's created with a fresh UUID.
However, when I look at the database schema (latest Postgres) with a tool like DataGrip, I find that the column id has nothing in the default definition - Why hasn't the default=uuid.uuid4 translate over to the database schema somehow?
When I edit the database with DataGrip, I have to insert a new UUID manually for records I put in manually to be able to save correctly.
Is there a way around this? To have the UUID automatically generate when I add rows from a 3rd party database client?
According to django docs here
Universally unique identifiers are a good alternative to AutoField for
primary_key. The database will not generate the UUID for you, so it is
recommended to use default:
It means, unlike AutoField default for UUIDField is not implemented (or used if your databese implements this kind of functionality) on database level. It is handled on application level. That's why you have to pass default value (uuid.uuid4). whenever a record is inserted, uuid.uuid4 function is called to generate a uuid and this value is inserted in database. If you are doing direct insertions, you have to handle it yourself.
However if you set default value for id column by running a direct query on db like
ALTER TABLE <TABLE_NAME> ALTER COLUMN id SET DEFAULT uuid_generate_v4();
Django won't complain about it. And it will work fine from outside django app.
Related
I have an unmanaged model in Django:
class Person(models.Person):
name = models.CharField(max_length=200)
class Meta:
managed = False
db_table = '"public"."person"'
Somewhere in my tests, I try to create a Person entry in the DB:
person = Person(name="Ariel")
person.save()
But then I get an error:
django.db.utils.IntegrityError: null value in column "id" of relation "person" violates not-null constraint
DETAIL: Failing row contains (null, Ariel).
Outside tests, everything works fine. In the tests, I initialize the DB with the tables referenced by the unmanaged by loading a schema dump.
The Django docs states that "no database table creation, modification, or deletion operations will be performed for this model", and that "all other aspects of model handling are exactly the same as normal", including "adding an automatic primary key field to the model if you don’t declare it". But doesn't that mean this code should work? How come Django and Postgres are not taking care of the id? Am I doing something wrong? How can I fix it?
Surely the issue that you're having is that in your PostgreSQL table, id is not an auto incremental field and it nulls by default.
It's quite a common issue when using unmanaged models on Django. You need to cover every single aspect of the table you're using.
I have a model in Django:
class Subject(models.Model):
level = models.CharField(max_length=50)
subject_name = models.CharField(max_length=50)
teacher_name = models.ForeignKey(Teacher, on_delete=models.CASCADE)
total_seats = models.IntegerField()
subject_details = models.CharField(max_length=50)
For the Subject table I want the level and the subject_name together to be primary keys. In fact, I dont want any other objects to have the same name and level. I know I can use unique_together but where do I mention the primary_key = True?
You don't. Django does not work with composite primary keys. This is specified in the documentation:
Each model requires exactly one field to have primary_key=True (either explicitly declared or automatically added).
In the FAQ section it also continues with:
Do Django models support multiple-column primary keys?
No. Only single-column primary keys are supported.
But this isn’t an issue in practice, because there’s nothing stopping
you from adding other constraints (using the unique_together model
option or creating the constraint directly in your database), and
enforcing the uniqueness at that level. Single-column primary keys are
needed for things such as the admin interface to work; e.g., you need
a single value to specify an object to edit or delete.
It is a feature that is often requested (see for example this Django ticket), but it was not implemented. It will probably be quite cumbersome, first of all a lot of existing Django tooling will need to be updated (for example JOINs should be done with the two keys, FOREIGN KEYs should then result in two or more fields constructed, etc.). But another, and probably even more severe problem might be the large number of packages built on top of Django that make the assumption that the primary key is not a composite. It would thus break a lot of packages in the Django "ecosystem".
There are some packages like django-compositekey [GitHub] that aim to implement this. But the last update is made in october 2014.
It is not per se a problem not to make it a primary key. In fact Django's GenericForeignKey [Django-doc] only works if the primary keys are all of the same type. So using unique_together should be sufficient. Normally this will also make a UNIQUE INDEX at the databaes side.
I think you want this 2 fields indexed by database because the main cause of primary key is to make field unique and indexed by the DBMS, so you can make your fields unique_together in Meta class and set db_index=True in field args.
I have a legacy Django Application (1.11) which uses UUID as primary key, hence doesn't have an ID field. My DB is postgres
class model_name(models.Model):
.... #model data ...
companyId = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
.... # Other model data
I now need to add a human readable auto-incrementing identifier which will be used by users to refer to the records outside the system.
The challenges are as follows:
The system can have multiple entries being added simultaneously, so it needs to manage that without collisions
ideally would need to add this to the save() method because new
I have around 20000 records already in the database for this model. So whatever method I use, I will need to be able to add values for all previous records.
I need to start numbering at 100,000
Is there a way to do this (Autofield may not work because its not going to be primary key and i already have n records in the system.) so it will remain consistent?
When creating migrations for Django I'm running into an instance where I need to set the default value for a custom user based on another table.
# models.py
def get_default_item():
return Item.objects.filter(name='XXXX').first().id
class CustomUser(AbstractUser):
# ...
item = models.ForeignKey(Item, on_delete=models.CASCADE, default=get_default_item)
# ...
I'm running into two issues:
I need to ensure that the table for Item is already created. I think I can do this using dependencies.
I need to ensure that the Item "XXXX" is created before it is referenced. Unfortunately this can't happen until I migrate the data over because the Item IDs need to be consistent with the old system and (unfortunately) I can't use id 0 with a Django / MySQL combination because that has special meaning.
Is there a way to tell the migration "don't worry about this default for now, you'll get it later"?
I'm working with a new Django project which need to load data from a legacy db, but saving new model object always fails with IntegrityError: null value in column "id" violates not-null constraint after I loaded data from the legacy db.
Primary key in legacy db is in range from 10000 to 200000, the new db is Postgres 9.5 and never manual set SQL schema on it.
My model could be simple like:
class MyModel(Model):
id = IntegerField(primary_key=True)
This will fails when I run MyModel().save() or MyModel.create(). It's OK to run MyModel(id=233).save() like I used at loading data.
I guess it's because it does not know where to start to auto generate primary key from. How to fix this?
To add an auto-increment field in django, you are supposed to use AutoField
You should define your id field like this:
id = models.AutoField(primary_key=True)
If you want to name it as id, you are not required to define the field, django does that for you.
A model without explicit id field will still have a AutoField id as a primary key.