I can't get the last insert id like I usually do and I'm not sure why.
In my view:
comment = Comments( ...)
comment.save()
comment.id #returns None
In my Model:
class Comments(models.Model):
id = models.IntegerField(primary_key=True)
Has anyone run into this problem before? Usually after I call the save() method, I have access to the id via comment.id, but this time it's not working.
Are you setting the value of the id field in the comment = Comments( ...)
line? If not, why are you defining the field instead of just letting Django take care of the primary key with an AutoField?
If you specify in IntegerField as a primary key as you're doing in the example Django won't automatically assign it a value.
Simply do
c = Comment.object.latest()
That should return you the last inserted comment
c.pk
12 #last comment saved.
To define an automatically set primary key use AutoField:
class Comments(models.Model):
id = models.AutoField(primary_key=True)
Do you want to specifically set a new IntegerField called id as the primary key? Because Django already does that for you for free...
That being said, have you tried removing the id field from your comment model?
Related
I'm trying to give a field in Django a default value = value of pk, is this possible ?
I've found an old question about giving a field default = value of another field but it doesn't really help when working with pk value :
How do I set default field value to value of other field in a Django model?
Basicly is something like this possible using pk instead of "name" variable ? :
class MyModel(models.Model):
name = models.CharField(max_length=50)
fullname = models.CharField(max_length=100,default=name)
def clean(self):
self.fullname=name
Thanks.
Django creates auto primary keys, the model will have a field called "id" and it is also called "pk"
If you access your database you'll be able to see it.
If you want to set your own primary key you will need to do something like:
custompk = models.someField(primary_key=True)
As your question is vague I've attempted to answer to the best of my ability.
If you are trying to access a PK/ID of an object in a view let me know and I can help with that as well. :)
I am trying to apply a filter on a Django model based on a column name
That column is a Foreign Key
Code -
Inside models.py -
class History(models.Model):
testcaseidstring = models.ForeignKey('Testcaseidstructure', models.DO_NOTHING, db_column='testCaseIdString')
Inside views.py -
sessid_qs=History.objects.using("otherdb").filter(testcaseidstring="tc123")
This gives me the following ERROR -
Field 'testcaseidstring' expected a number but got 'tc123'
How am I supposed to filter on this column?
Testcaseidstructure module:
class Testcaseidstructure(models.Model):
testcaseidstring = models.TextField(db_column='testCaseIdString')
class Meta:
managed = False
db_table = 'testCaseIdStructure'
Any help would be highly appreciable
Thanks!!
ForeignKey is a number, unless you defined a custom primary key in your model. It's the primary key of the Testcaseidstructure model, so despite the fact that you call it testcaseidstring, it is probably not a string, so rename it testcase. If you want to filter by the string, then you can do something like this:
class History(models.Model):
testcase = models.ForeignKey('Testcaseidstructure', models.DO_NOTHING, db_column='testCaseIdString')
Then
sessid_qs=History.objects.using("otherdb").filter(testcase__testcaseidstring="tc123")
As suggested by weAreStarDust. Make sure there are two underscores here, testcase__testcaseidstring='tc123'
I gues if you want filter by column name you should use testcaseidstring__name in filter, or whatever your name field called in Testcaseidstructure model.
Working with Django 1.11 and a postgreSQL Database (just switched from sqlite and didn't have this problem before)
So I have 3 models:
models.py
class Person(models.Model):
is_parent = models.BooleanField()
class VideoGamePurchase(models.Model):
bought_by = models.ForeignKey(Person)
after_homework = models.OneToOneField(HomeWork, OPTIONS???)
class HomeWork(models.Model):
done_by = models.ForeignKey(Person)
content = models.CharField(blablaba)
So the logic I'm try to implement is that if Person.is_parent is True a VideoGamePurchase instance can be created with an empty or null field for after_homework. However, if Person.is_parent is False, I want this field to be the primary key of a unique HomeWork object.
I can't find the right options to achieve this:
If I don't have primary_key=True then the makemigrations fails:
You are trying to add a non-nullable field 'id' to video_game_purchase without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
so I guess I hav to have primary_key=True. But then it seems like I can't have null=Trueor blank=True.
Is there a way to have a OneToOneField optionally empty with postgreSQL?
Is there a other/simpler way to implement this sort of logic?
Thanks for your help!
If you want the after_homework field to be optional, then you should use null=True and blank=True.
class VideoGamePurchase(models.Model):
bought_by = models.ForeignKey(Person)
after_homework = models.OneToOneField(HomeWork, null=True, blank=True)
You don't want primary_key=True for the after_homework - that would make the after_homework the primary key field of the VideoGamePurchase model, which doesn't make sense if the field is optional.
It looks like your migrations are messed up because you had primary_key=True for the after_homework field earlier. The easiest fix would be to start with a fresh database, delete the migrations for that app, then rerun makemigrations and migrate. This time, the migration will automatically create a primary key field id for the VideoGamePurchase model.
We are trying to work with legacy DB Tables that were generated outside of Django and are not structured in an ideal way. We also can not modify the existing tables.
The DB uses the same user ID (pk) across all the tables, wether or not there is a record for that user ID. It also uses that ID as a PK on the other tables, rather than rely on them to auto increment their own IDs.
So imagine something like this below:
class Items(models.Model):
user_id = models.ForeignKey('User', db_column='UserID')
class User(models.Model):
user_id = models.IntegerField(primary_key=True)
class UserTypeA(models.Model):
user_id = models.IntegerField(primary_key=True) # Same Value as User
class UserTypeB(models.Model):
user_id = models.IntegerField(primary_key=True) # Same Value as User
What we thought of creating a relationship between Items and UserTypeA (as well as UserTypeB) is to create another field entry that uses the same column as the user_id.
class Items(models.Model):
user_id = models.ForeignKey('User', db_column='UserID')
user_type_a = models.ForeignKey('UserTypeA', db_column='UserID')
user_type_b = models.ForeignKey('UserTypeB', db_column='UserID')
This unfortunately returns a "db_column is already used" type error.
Any thoughts on how to better approach the way what we're trying to do?
A detail to note is that we're only ever reading from this databases (no updates to), so a read-only solution is fine.
Thanks,
-RB
I've solved a similar problem with this (this code should be put before the definition of your Model):
from django.db.models.signals import class_prepared
def remove_field(sender, **kwargs):
if sender.__name__ == "MyModel":
sender._meta.local_fields.remove(sender.myFKField.field)
class_prepared.connect(remove_field)
(Tested in Django 1.5.11)
Django uses local_fields to make the CREATE TABLE query.
So, I've just attached the signal class_prepared and check if sender equals the class I was expecting. If so, I've removed the field from that list.
After doing that, the CREATE TABLE query didn't include the field with same db_column and the error did not ocurr.
However the Model still working properly (with manager methods properly populating the removed field from local_fields), I can't tell the real impact of that.
It seems that the default primary key is int. Is there anyway to use the big integer for the autofield as the primary key?
I would suggest you use a newer Django. Official Django documentation doesn't go farther back than 1.3 now. And 1.3 is insecure and unsupported. I realize the question was asked over 3 years ago, but since there is still no accepted answer I will give it a shot.
In Django 1.6.5 you can just do this in your model:
class MyModel(models.Model):
id = models.BigIntegerField(unique=True, primary_key=True)
The primary_key=True will override the default id on the model. In use this field auto increments with each new model object. It just works!
There are a couple of ways I can see to implement this. Either way, you have to define your pk field.
First of all, just create your own id field and override the save method.
modelname(models.Model):
# model definition
def save(self):
self.pkfield = nextIntFucntion()
super(modelname, self).save()
The nextIntFunction() is easy enough with a query of objects ordered by id, then get the id+1
I also found this link BigIntegerField and BigAutoField which seems to solve the problem, but I have not tested it myself
I met the same question too.
I have add some code like
User._meta.has_auto_field = True
User._meta.auto_field = id
And I define the id field to BigIntegerField(primary_key=True)
After I use user.Save(), user.id will have its id, don't need I query again.
I think it works, but it is not a beautiful solution, so I still finding a good way.
Since Django 1.10 you can use BigAutoField as described on documentation works exactly as AutoField but it is guaranteed to fit numbers from 1 to 9223372036854775807.
So you can use it like:
class SomeModel(models.Model):
id = models.BigAutoField()
...
You can hack Django and change the default auto-keys to the right values. Check out:
http://code.djangoproject.com/browser/django/trunk/django/db/backends/mysql/creation.py
from django.conf import settings
from django.db.backends.creation import BaseDatabaseCreation
class DatabaseCreation(BaseDatabaseCreation):
# This dictionary maps Field objects to their associated MySQL column
# types, as strings. Column-type strings can contain format strings; they'll
# be interpolated against the values of Field.__dict__ before being output.
# If a column type is set to None, it won't be included in the output.
data_types = {
'AutoField': 'integer AUTO_INCREMENT',
'BooleanField': 'bool',
'CharField': 'varchar(%(max_length)s)',
You can modify this using a patch in your own code:
DatabaseCreation.data_types['AutoField'] = 'bigint AUTO_INCREMENT'
You will also have to patch the AutoField class:
http://code.djangoproject.com/browser/django/trunk/django/db/models/fields/__init__.py
(untested code, good luck)
http://docs.djangoproject.com/en/dev/topics/db/models/
class BigIntegerField([**options])
available option is :
primary_key
If True, this field is the primary key for the model.
And after all you do a south migration:
ALTER TABLE mytable MODIFY COLUMN myid BIGINT(20) NOT NULL AUTO_INCREMENT;
You are right, sorry. The neccessary snippet is here:
http://djangosnippets.org/snippets/1244/
Allows to create bigint (mysql), bigserial (psql), or NUMBER(19) (oracle) fields which have auto-increment set by using the AutoField of django, therefore ensuring that the ID gets updated in the instance when calling its 'save()' method.
If you would only subclass IntegerField to BigIntegerField and use that as your primary key, your model instance you create would not get the id attribute set when calling 'save()', buy instead you would have to query and load the instance from the DB again to get the ID.
These snippets work. Use the BigAutoField class as your primary key on your model and it works seemlessly without any hacking.