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. :)
Related
Here is the declaration of my field:
partner_id = fields.Many2one(string="Child", comodel_name="res.partner")
I would like to know if it is possible to target another field of the table res.partner besides the "name"?
And why not a field that depends on another field?
It is possible to declared options?
Thanks for your help !
EDIT :
I'm trying to understand one thing.
When I export my partner_id field via the Odoo interface, I do not have a value of type res_partner_5096 but the value of another field which is an external identifier. "N0000542145"
This is what I need to be able to prepare an import file
On the other hand I have a second field "foyer_id" which exports me something of the style "relation_foyer_6055". I understand that it is the identifier that corresponds to registration of this person.
Yet my fields are declared the same way.
partner_id = fields.Many2one(string="Child", comodel_name="res.partner")
foyer_id = fields.Many2one(string="Foyer", comodel_name="horanet.relation.foyer")
I can not understand why this difference when exporting these two fields for the same partner.
An idea ?
I think you exactly looking for the "_rec_name" attribute. Odoo models uses a field as record name to display records in context where a representative “naming” is necessary. If you don't set _rec_name, model uses name field as record name by default.
Class HoranetRelationFoyer(models.Model):
# ...
_rec_name = 'my_field'
my_field = fields.Char()
I am writing a script and want to fake a User with an id (PK) of 2
var = Table(FKToUser=2)
var.save()
the problem is I'm getting :
"Table.FKToUser" must be a "User" instance
I've verified that the auth_user has a record with id=2
How can I fake this 2 value for testing purposes?
Thank you!
Assuming that Table is your model and FKToUser is a foreign key, there are two ways. The first is to set the FKToUser_id attribute to 2 and save the model. The other is to fetch the user and set the FKToUser attribute to the right user model instance.
This is also basically how a foreign key works. The actual column in the database is the FKToUser_id column, and it's a simple Integer foreign key to an id in another column. Django magic makes it possible to automatically retrieve the right instance by accessing FKToUser, and to set the right value by assigning a model instance to FKToUser.
Using Django 1.5.1. Python 2.7.3.
I wanted to do a unique together constraint with a foreign key field and a slug field. So in my model meta, I did
foreign_key = models.ForeignKey("self", null=True, default=None)
slug = models.SlugField(max_length=40, unique=False)
class Meta:
unique_together = ("foreign_key", "slug")
I even checked the table description in Postgres (9.1) and the constraint was put into the database table.
-- something like
"table_name_foreign_key_id_slug_key" UNIQUE CONSTRAINT, btree (foreign_key_id, slug)
However, I could still save into the database table a foreign_key of None/null and duplicate strings.
For example,
I could input and save
# model objects with slug="python" three times; all three foreign_key(s)
# are None/null because that is their default value
MO(slug="python").save()
MO(slug="python").save()
MO(slug="python").save()
So after using unique_together, why can I still input three of the same valued rows?
I'm just guessing right now that it might have to do with the default value of None for the foreign_key field, because before the unique_together, when I just had unique=True on slug, everything worked fine. So if that is the case, what default value should I have that indicates a null value, but also maintains the unique constraint?
In Postgresql NULL isn't equal to any other NULL. Therefore the rows you create are not the same (from Postgres' perspective).
Update
You have a few ways to deal with it:
Forbid the Null value for foreign key and use some default value
Override the save method of your model to check that no such row exists
Change SQL standard :)
Add a clean method to your model, so you can edit an existing row.
def clean(self):
queryset = MO.objects.exclude(id=self.id).filter(slug=self.slug)
if self.foreign_key is None:
if queryset.exists():
raise ValidationError("A row already exists with this slug and no key")
else:
if queryset.filter(foreign_key=self.foreign_key).exists():
raise ValidationError("This row already exists")
Beware, clean (or full_clean) isn't called by the default save method.
NB: if you put this code in the save method, update forms (like in the admin) won't work: you will have a traceback error due to the ValidationError exception.
Just manually create secondary index on slug field, but only for NULL values in foreign_key_id:
CREATE INDEX table_name_unique_null_foreign_key
ON table_name (slug) WHERE foreign_key_id is NULL
Please note, that Django does not support this, so without custom form/model validation you will get pure IntegrityError / 500.
Possible duplicate of Create unique constraint with null columns
As hobbyte mentioned, "In Postgresql NULL isn't equal to any other NULL. Therefore the rows you create are not the same (from Postgres' perspective)."
Another possible way to address this challenge is to add custom validation at the view level in the form_valid method.
In views.py:
def form_valid(self, form):
--OTHER VALIDATION AND FIELD VALUE ASSIGNMENT LOGIC--
if ModelForm.objects.filter(slug=slug,foreign_key=foreign_key:
form.add_error('field',
forms.ValidationError( _("Validation error message that shows up in your form. "),
code='duplicate_row', ))
return self.form_invalid(form)
This approach is helpful if you are using class based views, especially if you are automatically assigning values to fields that you want to hide from the user.
Pros:
You don't have to create dummy default values in the database
You can still use update forms (see Toff's answer)
Cons:
- This doesn't protect against duplicate rows created directly at the database level.
- If you use Django's admin backend to create new MyModel objects, you'll need to add this same validation logic to your admin form.
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.
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?