Changing the name of automatic primary key field in Django - django

By default, Django gives each model the following field:
id = models.AutoField(primary_key=True)
(https://docs.djangoproject.com/en/1.10/topics/db/models/#automatic-primary-key-fields)
This is great and convenient. However, I would like to know whether it is possible to change the name of the id field to more informative name, e.g., item_id.
If this is indeed possible, how can I do that?
EDIT: From the answers I understand that it is impossible to do it without setting the primary key explicitly (which is what I wanted to know).
My model has many classes, and I think that it will be clearer to give more informative field names. Does it really matter?

You just reference the source!
If you’d like to specify a custom primary key, just 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.
class MyModel(models.Model):
item_id = models.AutoField(primary_key=True)

Related

Confusion in id parameter in django

I was making an E Commerce website and added various products in it. Now for making a cart i made a add to cart button. And in HTML i assigned an id to this button. The id was pr{{product.id}}. I have not made buttons individually for every item. There is a for loop running which creates buttons. Now My doubt is that i have not assigned any field id in the models class. But still this code is running and when i printed the id's on the console i realised that it prints like pr32, pr33, pr34 ie in a sequential manner. So is there any product.id field predefined in django??
My doubt is that I have not assigned any field id in the models class.
You don't need to. If you do not add a primary key yourself, Django will add a field with the name id that is an AutoField. This is documented in the Automatic primary key fields section of the documentation:
By default, Django gives each model the following field:
id = models.AutoField(primary_key=True)
This is an auto-incrementing primary key.
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).
So to answer your question:
So is there any product.id field predefined in django?
Yes, if you did not specify a field with primary_key=True yourself.

How to set 2 attributes to primary key together in Django?

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.

Is there a query to filter based on existence of a one-to-one relationship in django?

Consider the model schema:
class A(models.Model):
id = models.IntegerField(...)
...
class B(models.Model):
parent = models.OneToOneField(A, primary_key=True)
And further assume that there are more rows of A than B (e.g. not all As have details). How would I generate a query that gives me only As which have associated Bs?
I've tried A.objects.filter(b__isnull=False) which doesn't seem to work, it still returns all rows in A.
I just tried this, and it works for me:
A.objects.exclude(b=None)
or, a somewhat hackier version that relies on the (usually) integer non negative nature of primary keys
A.objects.filter(b__id__gte=0)
Now, I have a related_name, so if those don't work for you, try adding related_name.
class Profile(models.Model):
user = models.OneToOneField(User, related_name='profile')
If it's OneToOne, there's no manager, just the object itself. So it should be A.B, I think.
What you have should work. Just verified it myself on a OneToOneField reverse relation in my own app. However, I've never tried doing that on a OneToField that's also the primary key. It's possible that that messes with the query for some reason. It's a little extra work just to test the theory, but you may want to try using a standard AutoField (or let Django create it automatically by removing primary_key) as the primary key, and see if your query works then.
Since all B's must have A (and the reverse is not true):
B.objects.filter(parent__isnull=False)
A one-to-one relationship. Conceptually, this is similar to a
ForeignKey with unique=True, but the "reverse" side of the relation
will directly return a single object.

unique_together foreign key object properties

I've got two models: Common and ARecord. ARecord has a ForeignKey relationship to Common. I want to ensure that ARecord is unique with a combination of items from ARecord and Common.
class Common(models.Model):
NAIC_number = models.CharField(max_length=5)
file_location_state = models.CharField(max_length=2)
file_location_code = models.CharField(max_length=2)
class ARecord(models.Model):
common = models.ForeignKey(Common)
coverage_code = models.CharField(max_length=6)
record_type = models.CharField(max_length=1)
class Meta:
unique_together = ('coverage_code', 'common__NAIC_number')
However, when I attempt to access the foreign key object property via the usual double underscore, I get a model validation error.
`arecord.arecord: "unique_together" refers to common__NAIC_number, a field that doesn't exist. Check your syntax.`
This seems like it should be possible and, a slightly different question was asked that indicates it is , but perhaps I'm missing something obvious?
As Manoj implies, you can't do this with unique_together, because that is a database constraint and the sort of thing you want can't be done with database constraints.
Instead, you want do this programmatically, probably via model validation, which will ensure that no instances are created that violate your constraint.
This doesn't make sense to me. The documentation defines unique_together thus:
This is a list of lists of fields that must be unique when considered together. It's used in the Django admin and is enforced at the database level (i.e., the appropriate UNIQUE statements are included in the CREATE TABLE statement).
(Emphasis added)
I don't know how an UNIQUE statement can be added at the database level for such a case (using one column in the current table and another in a different table accessed through a foreign key). I hope those who know better about databases will correct me if I am wrong.

Model design question: custom fields at runtime?

I have some newbie questions about Django.
I want to write a generic ticket-management system, where the administrator of the site should be able to add custom fields to a ticket. It seems that the database tables are generated on initialization, so it is not clear to me how to add custom fields at runtime.
One way is to have a long list of fields of different types, all nullable, and let the administrator rename/select the fields she needs. Is there a better design?
Thanks!
I'm currently in charge of maintaining a similar site where a treatment for a medical condition is listed and there can be arbitrary number of "cases" which are user-posted experiences for that treatment/condition combo attached.
The method my company used to set it up was to have an Entry object which would be analogous to the custom field you described, which has a Foreign Key referencing the treatment/condition to which it belongs.
Then when we want to get all the entries for a particular treatment/condition combo, we simply do an
Entry.objects.filter(condition=ID)
So, in your case, I would suggest having a Ticket model, and an "Entry" style model which contains a Foreign Key reference to the Ticket to which it belongs.
I would make something like the code below. Store extra attributes in an attribute model. Store the values in AttributeValue.
class Ticket(models.Model):
name = models.CharField(max_length=200)
class Attribute(models.Model):
name = models.CharField(max_length=200)
class AttributeValues(models.Model):
attribute = models.ForeignKey(Attribute)
ticket = models.ForeignKey(Ticket)
value = models.CharField(max_length=200)