I am using django and Sql server as a database.
I have a table with a multiple primary key using the unique_together
class Attribute_tmp(models.Model):
useridtmp = models.ForeignKey(User_tmp, on_delete=models.CASCADE, blank =True, null = True)
userid = models.ForeignKey(User, on_delete=models.CASCADE, blank =True, null = True)
fk_str = models.ForeignKey(Stream, on_delete=models.CASCADE)
class Meta:
unique_together = (('userid', 'fk_str'),('useridtmp', 'fk_str'))
So when i add objects of this table when the useridtmp is null, it doesn't work because i will have a duplicated key.
My Question is how can i avoid the null values.
Thank you
Did you tried this?
class Meta:
constraints = [
models.UniqueConstraint(fields=['userid', 'fk_str'], name='name of constraint'),
models.UniqueConstraint(fields=['useridtmp', 'fk_str'], name='another name of constraint')
]
Since you have null=True and blank=True in your ForeignKey field, it is reasonable for db to store null values.
If in any case, the two ForeignKeys shouldn't be null, you can mark null and blank as false. Simply removing them from field settings will do the trick as they are set to false by default. You probably need to recreate the database to make the new settings working.
Then, the unique_together will not have an issue with null values.
Related
How to create a model with 2 different fields with the same db_column?
In my example queue_id and content_type_id are always the same id value. So I don't want to store that information twice in a DB table.
I set a db_column for both fields but got the error
(models.E007) Field 'content_type' has column name 'queue_id' that is used by another field.
I added error supression. As result I have an invalid sql code for migration:
CREATE TABLE `queue_items_generic` (
`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY,
`object_id` integer UNSIGNED NOT NULL,
`queue_id` integer NOT NULL,
`queue_id` integer NOT NULL);
Manual migration patch has helped.
But is there an easier way to do the same stuff? I don't want to patch migrations and supress any errors.
Here is the reproducing problem code:
from django.db.models import (
Model,
ForeignKey,
OneToOneField,
CASCADE,
PositiveIntegerField,
)
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
class QueueGeneric(Model):
content_type = OneToOneField(
ContentType,
on_delete = CASCADE,
primary_key = True,
)
last_object_id = PositiveIntegerField(
default = 0,
)
last_object = GenericForeignKey('content_type', 'last_object_id')
class QueueItemsGeneric(Model):
queue = ForeignKey(
QueueGeneric,
db_column = 'queue_id',
on_delete = CASCADE
)
content_type = ForeignKey(
ContentType,
db_column = 'queue_id',
on_delete = CASCADE
)
object_id = PositiveIntegerField()
object = GenericForeignKey('content_type', 'object_id')
Update #1
A bit digging into Fields topic helps to solve the migration problem.
If we provide the db_type is None then it won't produce a new column in DB table.
class ShadowForeignKey(ForeignKey):
def db_type(self, connection):
return None
class QueueItemsGeneric(Model):
queue = ForeignKey(
QueueGeneric,
db_column = 'queue_id',
on_delete = CASCADE
)
content_type = ShadowForeignKey(
ContentType,
db_column = 'queue_id',
on_delete = CASCADE
)
object_id = PositiveIntegerField()
object = GenericForeignKey('content_type', 'object_id')
It looks OK. Some tests will show how it's a stable solution.
Now I have only a problem with error supression. It seems that the field names check into migrations module. For now I have no idea how to override it nicely.
I have a column which should be MUL key, but I couldn't find out how I can do that. Here's the code:
class table(models.Model):
field2 = Models.int(max_length=9, null= False, default = 0)
Non-unique indexes are defined in the metadata options for the model.
class Table(models.Model):
...
class Meta:
indexes = [
models.Index(fields=['field2'])
]
MUL keys are simply non-unique indexes (other index types are PRI for Primary Key and UNI for Unique, which are both unique indexes. You can add a non-unique index to any field using the db_index argument:
field2 = models.IntegerField(null=False, default=0, db_index=True)
PS: I assume that the code in the question has a typo and you actually meant IntegerField and not int. Also, max_length has no effect when used with IntegerFields.
I have these tables:
class OpeDatos(models.Model):
id_dato = models.IntegerField(primary_key=True)
id_usuario = models.ForeignKey(SisUsuarios, db_column='id_usuario')
id_region = models.ForeignKey(SisRegiones, db_column='id_region')
titulo = models.CharField(max_length=70, blank=True)
class Meta:
managed = False
db_table = 'ope_datos'
class OpeProductos(OpeDatos):
id_producto = models.IntegerField(primary_key=True)
iddato = models.OneToOneField(OpeDatos, primary_key=True, db_column="id_dato", parent_link=True)
id_producto_tipo = models.ForeignKey(DefProductosTipos, db_column='id_producto_tipo')
class Meta:
managed = False
db_table = 'ope_productos'
I want to insert data :
from apps.inicio.models import SisUsuarios, SisRegiones, OpeDatos
usuario = SisUsuarios.objects.get(pk=1)
region = SisRegiones.objects.get(pk=1)
datos = OpeDatos()
datos.id_usuario = usuario
datos.id_region = region
datos.save()
producto = OpeProductos()
producto.iddato = datos.id_dato
producto.save()
displays this message:
ValueError at /productos/add/
Cannot assign None: "OpeProductos.iddato" does not allow null values.
can you help me, please.
When creating an id manually you should use AutoField instead of IntegerField
id_dato = models.AutoField(primary_key=True)
https://docs.djangoproject.com/en/1.6/ref/models/fields/#autofield
What is happening is that since you are not explicitly defining the 'datos' object's id it doesnt have one, and then producto complains because the key can't have an empty value.
AutoField should fix this
I am surprised it doesn't fail at the earlier line: datos.save() because you have not supplied a value for the primary key datos.id_dato
Normally in Django you would need to use an AutoField to get an auto-incrementing primary key.
Also you should not be specifying primary_key=True on the OpeProductos.iddato field, you can only have one primary key per model.
Then the error you are seeing is due to the fact that datos.id_dato is None since you did not provide any value for it before saving the datos instance.
Table in PostgreSQL database:
CREATE TABLE pmss_recordmodel
(
id serial NOT NULL,
"Name" character varying(100),
CONSTRAINT pmss_recordmodel_pkey PRIMARY KEY (id)
)
WITH (OIDS=FALSE);
ALTER TABLE pmss_recordmodel OWNER TO postgres;
Model:
class RecordModel(models.Model):
def __unicode__(self):
return self.Name
Name = models.CharField(max_length = 100, unique = False, null = True, blank = True)
When I POST data with blank Name field, form.is_valid() returns False. Why? Am I missing something?
EDIT:
class RecordForm(forms.ModelForm):
class Meta:
model = RecordModel
Name = forms.CharField(label = "Имя ", widget = forms.TextInput(attrs = {'size': 15}))
Django forms documentation:
By default, each Field class assumes the value is required
Set the "required" argument to False as such:
Name = forms.CharField(required = False, label = "Имя ", widget = forms.TextInput(attrs = {'size': 15}))
You could be having problems with how the field is defined in your database.
This seems like it could be the common situation of doing syncdb with the field initially not having blank=True null=True and then adding those terms later (after initial syncdb) to make the field not required. These settings will not be applied by simply running syncdb again. It requires a database migration or a database flush (will clear existing data, which isn't necessarily bad in development).
A field on a model, foo = models.ForeignKey(Foo) will automatically add a database index for the column, in order to make look-ups faster. That's good and well, but Django's docs don't state whether the fields in a model-meta's unique_together receive the same treatment. I happen to have a model in which one char field which is listed in unique_together requires an index for quick lookups. I know that it won't hurt anything to add a duplicate db_index=True in the field definition, but I'm curious.
For anyone coming here wondering if they need an index_together in addition to unique_together to get the index's performance benefit, the answer for Postgres is no, they are functionally the same.
If unique_together does add an index, it will be a multiple column index.
If you want one of the columns to be indexed individually, I believe you need to specify db_index=True in the field definition.
unique_together does not automatically add indexes for each field included in the list.
The new versions of Django suggest using Index & constraint meta options instead:
https://docs.djangoproject.com/en/3.2/ref/models/options/#unique-together
https://docs.djangoproject.com/en/3.2/ref/models/options/#index-together
https://docs.djangoproject.com/en/dev/ref/models/indexes/
And an example model from an open source project:
class GroupResult(models.Model):
"""Task Group result/status."""
group_id = models.CharField(
max_length=getattr(
settings,
"DJANGO_CELERY_RESULTS_TASK_ID_MAX_LENGTH",
255
),
unique=True,
verbose_name=_("Group ID"),
help_text=_("Celery ID for the Group that was run"),
)
date_created = models.DateTimeField(
auto_now_add=True,
verbose_name=_("Created DateTime"),
help_text=_("Datetime field when the group result was created in UTC"),
)
date_done = models.DateTimeField(
auto_now=True,
verbose_name=_("Completed DateTime"),
help_text=_("Datetime field when the group was completed in UTC"),
)
content_type = models.CharField(
max_length=128,
verbose_name=_("Result Content Type"),
help_text=_("Content type of the result data"),
)
content_encoding = models.CharField(
max_length=64,
verbose_name=_("Result Encoding"),
help_text=_("The encoding used to save the task result data"),
)
result = models.TextField(
null=True, default=None, editable=False,
verbose_name=_('Result Data'),
help_text=_('The data returned by the task. '
'Use content_encoding and content_type fields to read.'))
def as_dict(self):
return {
'group_id': self.group_id,
'result': self.result,
'date_done': self.date_done,
}
def __str__(self):
return f'<Group: {self.group_id}>'
objects = managers.GroupResultManager()
class Meta:
"""Table information."""
ordering = ['-date_done']
verbose_name = _('group result')
verbose_name_plural = _('group results')
indexes = [
models.Index(fields=['date_created']),
models.Index(fields=['date_done']),
]
In Django 1.5 and higher, you can use the {Model}.Meta.index_together class attribute. If you had two fields named foo and bar, you would add:
class Meta(object):
index_together = unique_together = [
['foo', 'bar']
]
If you have only one set of unique fields, you can use a one-dimensional iterable for unique_together. However, the documentation does not indicate that the same applies to index_together.
This would also be okay:
class Meta(object):
unique_together = 'foo', 'bar'
index_together = [
['foo', 'bar']
]
This, however, is NOT supported by the documentation:
class Meta(object):
unique_together = 'foo', 'bar'
index_together = 'foo', 'bar'
According to the docs, it will only enforce uniqueness on database level. I think generally making a field unique does not imply it has an index. Though you could also simply check on db level if the index exists. Everything indicates though it does not.