unique=true doesn't create index - django

Email = models.EmailField(max_length = 300, unique = True)
Doesn't create an index on SQLite 3. Documentation says unique = True will create a index. But checking SQLite it is not created.
Documentation

Most database backends will automatically create an index if the field is marked as unique. Indeed, in the source code [GitHub] we see:
def _field_should_be_indexed(self, model, field):
return field.db_index and not field.unique
So if a field is marked as unique, by default it will not be indexed, since the database itself will already do that.
This is the same for foreign keys, for which some databases will also create an index automatically.

Related

Django "duplicate key value violates unique constraint" because of the save method

I am trying to update an existing instance from a model in Django admin interface but I'm getting django.db.utils.IntegrityError: duplicate key value violates unique constraint because of the save method.
According to the documentation, the save method should not have any problems UPDATING the model. https://docs.djangoproject.com/en/4.0/ref/models/instances/#how-django-knows-to-update-vs-insert .
Django abstracts the need to use INSERT or UPDATE SQL statements.
Specifically, when you call save() and the object’s primary key
attribute does not define a default, Django follows this algorithm:
If the object’s primary key attribute is set to a value that evaluates
to True (i.e., a value other than None or the empty string), Django
executes an UPDATE. If the object’s primary key attribute is not set
or if the UPDATE didn’t update anything (e.g. if primary key is set to
a value that doesn’t exist in the database), Django executes an
INSERT.
Now this is my model and the save method:
class Examene(models.Model):
saptamani = models.IntegerField(default=3, validators=[MinValueValidator(1), MaxValueValidator(5)])
zile = models.IntegerField(null=False, blank=True)
profesor = models.ForeignKey(Materii_profesor, on_delete=models.CASCADE)
materii = models.ManyToManyField(Materie)
def save(self, *args, **kwargs):
self.zile = (self.saptamani * 5)
super(Examene, self).save(self, *args, **kwargs)
I am using Postgres as database, how would I avoid the error? Is there a way to delete existing instance from the save method and save the updated version? Or is another way to pass this? I'm having the same problem for all the models that have override the save method.

Does Django index Autofield / ID keys in PostgreSQL?

Django's docs state that id fields created with AutoField are indexed:
id is indexed by the database and is guaranteed to be unique.
Similarly it applies an index to every FK relationship.
However, in PostgreSQL whilst FKs appear to be indexed, IDs are not. Here's an example:
class TestModelBase(models.Model):
name = models.CharField(max_length=50)
fkfield = models.ForeignKey(TestModelFK, blank=True, null=True,
on_delete=models.CASCADE)
m2mfield = models.ManyToManyField(TestModelM2M, related_name='base_m2m')
This model appears to apply the fkfield index, but not the id autofield. From PGAdmin below:
Am I missing something?
PostgreSQL automatically creates indexes for primary keys. From the docs:
Adding a primary key will automatically create a unique B-tree index on the column or group of columns listed in the primary key, and will force the column(s) to be marked NOT NULL.
It appears that PGAdmin does not show those indexes. This mailing list thread is the best source I could find.

How to autopopulate new field in models' existing objects with unique values in Django?

I have added new field called slug which need to be unique. It is already existing project.
During migrations Django asks what value should be used to fill already created objects. However any string will cause a conflict as value will not be unique.
I was planning to fill the slug field with values from other field of this model namely username.
Question: How can I populate above slug field (with unique = True) during migrations with unique values. Or maybe there is another way around that.
Thanks

Foregin key field name is followed by _id

In a model, when a foreign key field is created then Django apparently create another field with the same field name followed by _id.
for example if I have
class Post(models.Model):
user = models.ForeignKey(User,on_delete=models.CASCADE,default=None)
dated = models.DateTimeField(auto_now=True)
...
Then I will have the following fields available:
id,user,user_id,dated
I am not sure why this field (user_id) was added?
Later I wanted to override my queryset in a class view
so I was confused which one to use (user field or user_id field)
:
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user_id=self.request.user.id)
Or
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(user=self.request.user.id)
I tried both and both worked just fine
My question is:
1) What is the purpose of creating this additional field ?
2) What is the difference between the original foreign key field (user in my case) and user_id field?
3) Will both fields user and user_id available in the database? what is the point of that?
4) Is the content of user and user_id identical in each record? if so ,then what the purpose of this additional field that was created automatically by django?
Thanks a lot
Django only creates one column in the database for the foreign key.
The difference between the field and the _id attribute it generates is that accessing the field performs a query for the full set of columns from the related table in order to construct the complete related object. If you want the full object, use the field (and probably also use select_related() in the initial query to save you from doing N+1 queries).
On the other hand, if all you need is the DB-level value of the foreign key, which is usually the primary key of the related object (and often that is what you want), the _id attribute shortcut is there for you and already has the data, because that's what was actually in the foreign key column.
In other words, suppose I have models like this:
class ModelA(models.Model):
name = models.TextField()
class ModelB(models.Model):
name = models.TextField()
a_instance = models.ForeignKey(ModelA)
If you query for a ModelB, like ModelB.objects.get(pk=12), you'll get a query like this:
SELECT id, name, a_instance_id
FROM your_app.modelb
WHERE id = 12;
Notice a_instance_id is the name of the column -- it's just a foreign key, all it stores is a pointer to the primary key of a ModelA instance. If you just need that primary key, accessing the a_instance_id attribute has it already without needing to do another query. If you access the a_instance field, though, you get to do another query:
SELECT id, name
FROM your_app.modela
WHERE id = (whatever the value of that foreign key was);

Django ORM cannot auto set primary key for model after loading data from legacy db

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.