Django models: set default IntegerField to number of instances - python

I would like to set the "order" IntegerField of my Achievement model to the current count of objects in Achievement. The order field is used to order achievements, and users can change it. For now I have 1 as default.
class Achievement(models.Model):
title = models.CharField(max_length=50, blank=True)
description = models.TextField()
order = models.IntegerField(default=1) #Get the number of achievement objects
class Meta:
db_table = 'achievement'
ordering = ['order', 'id']
For example, if I already have one achievement in my database with whatever order the next one should get order=2 by default.

As far as I understood, you want to have a default value of 1 to the order integer field and increment it with each entry of Achievment (same functionality as the id), but also allow users change it.
For this purpose you can use Django's AutoField:
An IntegerField that automatically increments according to available IDs. You usually won’t need to use this directly; a primary key field will automatically be added to your model if you don’t specify otherwise.
Like this:
class Achievement(models.Model):
...
order = models.AutoField(default=1, primary_key=False)
# Also specify that this autofield is *not* a ^ primary key
class Meta:
ordering = ['order', 'id']

Related

Django only one default row

I have a ManyToMany relationship that indicates a Doctor can have many specialties, but only one of them is the PRIMARY one.
I've designed a custom M2M class as follows:
class Doctor(models.Model):
account = models.ForeignKey(Account, on_delete=models.CASCADE)
specialty = models.ManyToManyField(Specialty, through='DoctorSpecialty')
.....
class Specialty(models.Model):
title = models.CharField(max_length=45)
.....
class DoctorSpecialty(models.Model):
doctor = models.ForeignKey(Doctor, on_delete=models.CASCADE)
specialty = models.ForeignKey(Specialty, on_delete=models.CASCADE)
default = models.BooleanField(default=True)
The doctor can have many specialties, but only one of them can be the default one. He or she can have many specialties with the default field set as False, but cannot have more than one with the default field set as True
I wanted to do something like this:
class Meta:
constraints = [
models.UniqueConstraint(fields=['doctor', 'specialty', 'default'], name='unique specialty')
]
But this will mean that the doctor can have only one specialty as a default one, and only one other as a non default one.
How can we achieve this with the minimum of code?
PS: I could leave it without constraints and try to validate adding new entries by checking if another default specialty exists, but this will add a lot of overhead and exception raising.
I think there is no way we can achieve this with built-in functions. So I came up with this solution (since no one else answered):
I created another ForeignKey for the Primary Specialty, and ditched the DoctorSpecialty custom M2M class and left the M2M relationship with Specialty. One doctor can have only one primary specialty, and can also choose additional specialties as secondary. Later on in the views, I can put in place an algorithm to remove the primary specialty from the list of specialties when entering additional ones in case there is an existing primary specialty.

Saving Auto-Incrementing line number in Inline field Django

I have the following model as an inline field in another model:
class route_ordering(models.Model):
route_id = models.ForeignKey(route, on_delete=models.CASCADE)
activity_id = models.ForeignKey(activity, on_delete=models.CASCADE)
day = models.IntegerField()
order = models.IntegerField()
And in the admin.py:
class RouteAdmin(admin.ModelAdmin):
inlines = (RouteOrderingInline,)
I would like to make "order" self-incrementing from one, so it will be auto filled when I go to the Django admin panel (in the first line order=1 , then order-2 etc.)
I know you can use Default to set an autofilled value, but I want it to increment by itself.
How can I do this?
I can't guarantee this will work, and I'm not able to test out right now, but I think you can pass in a generator to your default value arg.
define increment():
return range(1, 1000)
And wherever your passing in a default just call next(increment())
Sorry I can't provide a more detailed example, I'm writing this on my phone XD, but I think that should work.

Can I create model in Django without automatic ID?

I need a table without a primary key (in Django it was created automatically). So my question is: Can I create a model without an ID/primary key?
I'm using Django 1.7.
You can create a model without an auto-incrementing key, but you cannot create one without a primary key.
From the Django Documentation:
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).
No, you can't. Excerpt from the documentation:
Each model requires exactly one field to have primary_key=True (either explicitly declared or automatically added).
I've found the solution.
Since django need Primary Key (either it's composite or single-field ID) so, I've tried to set primary_key=True in every fields in its composite-key combination, and add those fields in Meta and groups in unique_together
class ReportPvUv(models.Model):
report_id = models.ForeignKey(Reports, primary_key=True)
rdate = models.DateField(primary_key=True)
fdate = models.DateTimeField(primary_key=True)
ga_pv = models.BigIntegerField()
ga_uv = models.BigIntegerField()
ur_pv = models.BigIntegerField()
ur_uv = models.BigIntegerField()
da_pv = models.BigIntegerField()
da_uv = models.BigIntegerField()
class Meta:
db_table = 'report_pv_uv'
unique_together = ('report_id', 'rdate', 'fdate')
and when I run makemigrations, there are no ID field in it's migrations script :D
thanks everybody

Django create_or_update(), unique_together, unique, and primary

I'm still trying to fully understand Django models, let's say I have the following model:
class Manufacturer(models.Model):
name = models.CharField(amx_length=255, unique=True)
class Car(models.Model):
name = models.CharField(max_length=255)
color = models.CharField(max_length=255)
manufacturer = models.ForeignKey(Manufacturer)
unique_together = ('manufacturer', 'name')
And I run the following commands:
honda = Manufacturer.objects.get(name='Honda') #Let's assume this object already exists
car = Car.objects.get_or_create(name='Honda Accord', color='Red', manufacturer=honda)
car = Car.objects.get_or_create(name='Honda Accord', color='Green', manufacturer=honda)
Will Django simply update the existing car to change the color from Red to Green? Or will issues arise because I don't have a primary_key set?
Also, does it matter if I use primary_key or unique or are they the same? I'm using a mySQL backend if it matters.
Django automatically sets a primary key field called id unless you specify one yourself. So your Car model will already have an id field. It's on the base model class that your model inherits.
In your example, you haven't specified the defaults argument of the get_or_create() method, so Django will only attempt to retrieve an object with the values you've passed in via a get call: https://docs.djangoproject.com/en/1.7/ref/models/querysets/#django.db.models.query.QuerySet.get_or_create
unique constraints can be specified on a field regardless if it's an AutoField or not. See: https://docs.djangoproject.com/en/1.7/ref/models/fields/#unique for more specific information.

How to use unique_together method in django views

class Model1(models.Model):
username = models.CharField(max_length=100,null=False,blank=False,unique=True)
password = models.CharField(max_length=100,null=False,blank=False)
class Model2(models.Model):
name = models.ForeignKey(Model1, null=True)
unique_str = models.CharField(max_length=50,null=False,blank=False,unique=True)
city = models.CharField(max_length=100,null=False,blank=False)
class Meta:
unique_together = (('name', 'unique_str'),)
I've already filled 3 sample username-password in Model1 through django-admin page
In my views I'm getting this list as
userlist = Model1.objects.all()
#print userlist[0].username, userlist[0].password
for user in userlist:
#here I want to get or create model2 object by uniqueness defined in meta class.
#I mean unique_str can belong to multiple user so I'm making name and str together as a unique key but I dont know how to use it here with get_or_create method.
#right now (without using unique_together) I'm doing this (but I dont know if this by default include unique_together functionality )
a,b = Model2.objects.get_or_create(unique_str='f3h6y67')
a.name = user
a.city = "acity"
a.save()
What I think you're saying is that your logical key is a combination of name and unique_together, and that you what to use that as the basis for calls to get_or_create().
First, understand the unique_together creates a database constraint. There's no way to use it, and Django doesn't do anything special with this information.
Also, at this time Django cannot use composite natural primary keys, so your models by default will have an auto-incrementing integer primary key. But you can still use name and unique_str as a key.
Looking at your code, it seems you want to do this:
a, _ = Model2.objects.get_or_create(unique_str='f3h6y67',
name=user.username)
a.city = 'acity'
a.save()
On Django 1.7 you can use update_or_create():
a, _ = Model2.objects.update_or_create(unique_str='f3h6y67',
name=user.username,
defaults={'city': 'acity'})
In either case, the key point is that the keyword arguments to _or_create are used for looking up the object, and defaults is used to provide additional data in the case of a create or update. See the documentation.
In sum, to "use" the unique_together constraint you simply use the two fields together whenever you want to uniquely specify an instance.

Categories