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.
Related
I am developing an app in Django.
I want to insert in my model an auto-incrementing alphanumerical ID field, having, by default, a fixed alphabetical part and an auto-incrementing numerical part.
But I also want the availability to change, from admin section, this id to another alphanumerical one, with a different alphanumerical and numerical part.
Please note: I don't want to overwrite the django default id field, I just want to include in my model a field that gets as default value an auto-incrementing alphanumerical value.
Example of what I want:
Desired alphabetical constant part: ITM
Desired numerical auto-incrementing part: 00000
So that every object of my model, when generated, get default
progressive values like: ITM00001, ITM00002, ITM00003, ...
Also, I would like to be able to change the field value from my admin
section into values like ABC0000001, DFG0051, RST034, ...
Max field length: 10 (It can be also higher)
I realize that I have to use AutoField and to somehow join the constant string with the auto-incrementing numerical variable, but I don't know how to do it.
class my_model(models.Model):
Field_1 = models.CharField(max_length=10, blank=True, null=True)
static_ID = models.AutoField(???)
What code should I write to get a field with the features I described upwards?
Instead of storing it, why not using a property method to generate that id? For example:
class MyModel(models.Model):
field_one = models.CharField(max_length=10, blank=True, null=True)
#property
def static_id(self):
'ITM{0:07d}'.format(self.pk)
If you are concerned with filtering, then you can use custom manager method:
class CustomManager(models.Manager):
def get_id(self, static_id):
return int(static_id[2:])
def filter_static_id(self, static_id):
_id = self.get_id(static_id)
return self.filter(pk=_id)
def filter_static_id(self, static_id):
_id = self.get_id(static_id)
return self.get(pk=_id)
class MyModel(models.Model):
objects = CustomManager()
Maybe you can split your field into three separate fields:
class MyModel(models.Model):
PREF = "ITM"
NUMS = 5
field1 = models.CharField(max_length=10, blank=True, null=True)
...
pref = models.CharField(max_length=3, default=PREF) # prefix that has defaul value and can be modified
nums = models.PositiveIntegerField(default=NUMS) # the number of digits
static_id = models.AutoField(primary_key=False) # auto increment field
class Meta:
unique_together = ('pref', 'nums', 'static_id')
#property
def static_key(self):
return self.pref + str(self.static_id).zfill(self.nums)
SOLVED:
Since I don't need a specific length for my id, nor a constant increment between two consecutive ids, I can use time.time() to get a unique time number every time the object in the model is created. Then I can turn that time number into a string and concatenate it with a constant prefix.
In models.py:
import time
def return_timestamped_id():
prefix = "ITCH"
timestamp = str(int(time.time()*10000000))
default_value = prefix + timestamp
return(default_value)
class my_model(models.Model):
Field_1 = models.CharField(max_length=256)
static_ID = models.CharField(max_length=256, blank=False, null=False, default=return_timestamped_id)
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.
I would like to have an entity as follows:
class EntitySharedLinkPermission(models.Model):
OFF = None
COMPANY_VIEW = "Company View"
COMPANY_EDIT = "Company Edit"
PUBLIC_VIEW = "Public View"
PUBLIC_EDIT = "Public Edit"
name = models.CharField(max_length=12, primary_key=True)
class Meta: db_table = 'entity_shared_link_permission'
However, I cannot have NULL as a primary key value here. What should I do here instead? One idea was to just remove the primary key on this table and have a unique key instead (no PK in the table) to get around this, but surely there must be a better solution.
Simply put, you can't have null as primary key column value. You should always supply non null value to the primary key. Also, don't go for unique, it just isn't the solution though it masquerades as being one. If you can't always supply non null value, introduce a new identity column to your table instead.
If you don't expect the list of items to change often, and the set is small, then it looks to me like you're trying to set up a "choices" field, for which Django already has nice support. Here's the example that the Django docs use, which you could easily adapt to your situation:
from django.db import models
class Student(models.Model):
FRESHMAN = 'FR'
SOPHOMORE = 'SO'
JUNIOR = 'JR'
SENIOR = 'SR'
YEAR_IN_SCHOOL_CHOICES = (
(FRESHMAN, 'Freshman'),
(SOPHOMORE, 'Sophomore'),
(JUNIOR, 'Junior'),
(SENIOR, 'Senior'),
)
year_in_school = models.CharField(
max_length=2,
choices=YEAR_IN_SCHOOL_CHOICES,
default=FRESHMAN,
)
def is_upperclass(self):
return self.year_in_school in (self.JUNIOR, self.SENIOR)
However, if you expect the list of permissions to be fluid and change often, you should consider making the permissions a Model of their own, and simply use a ForeignKey (or ManyToMany) relationship,
I'm trying to replace a field in an intermediate table with a generic field. Using Django 1.6, MariaDB/MySQL.
I have a class (PermissionGroup) that links a resource to a group. Works fine. However I have several other tables that are similar - linking some id to a group id.
I thought I could replace these tables with one table that uses a generic foreign key, along with the group id. However this does not validate.
Here's the original, which works:
# core/models.py
class PermissionGroup(models.Model):
resource = models.ForeignKey('core.Resource')
group = models.ForeignKey('auth.Group')
class Resource(models.Model):
groups = models.ManyToManyField('auth.Group', through='core.PermissionGroup')
# auth/models.py
class Group(models.Model):
name = models.CharField(max_length=80, unique=True)
Now, trying to change the PermissionGroup to use a GenericForeignKey:
# core/models.py
class PermissionGroup(models.Model):
content_type = models.ForeignKey('contenttypes.ContentType')
object_id = models.PositiveIntegerField()
content_object = generic.GenericForeignKey()
group = models.ForeignKey('auth.Group')
class Resource(models.Model):
groups = models.ManyToManyField('auth.Group', through='core.PermissionGroup')
# auth/models.py
class Group(models.Model):
name = models.CharField(max_length=80, unique=True)
The django model validation now fails with:
core.resource: 'groups' is a manually-defined m2m relation through model PermissionGroup, which does not have foreign keys to Group and Resource
Is this simply not possible, or is another means to accomplish this?
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.