Django create_or_update(), unique_together, unique, and primary - python

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.

Related

How to make a username as a foreign key of another model in django

I am very new to Django. I want to link a model which has 2 field 'username' and 'password'. I want to make 'username' field as as Foreign in another model. But as per Django we can only pass the whole Model Object, who is referring to as it's foreign key.
am I wrong somewhere? please give me any solution regarding this basic problem.
No you can link to any unique field of a Django model. So if your models look like:
class Target(models.Model):
name = models.CharField(max_length=128, unique=True)
class SourceModel(models.Model):
target = models.ForeignKey(Target, to_field='name', on_delete=models.CASCADE)
You can assign the value of the target column to the target_id then. So for example:
Target.objects.create(name='target1')
SourceModel.objects.create(target_id='target1')
So you do not need to pass a Target object itself. You can use the …_id "twin" field to use the target column value. The database will normally enforce referential integrity, and thus will prevent passing a non-existing value to the foreign key column.

Django models: set default IntegerField to number of instances

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']

How can I store history of ManyToManyField using django-simple-history.

How can I store history of ManyToManyField using django-simple-history. I used HistoricalRecords with attribute m2m_filds but it is throwing error: unexpected keyword argument 'm2m_fields'
I'm macro1 on GitHub, and I guess de facto maintainer of django-simple-history.
From your question it seems that you're just asking about general ManyToManyField support compared with other fields. The short answer is that we do not currently support it.
ManyToManyFields actually create an in-between model that represents the relationship between the two models you're working with.
If you want tracking on that relationship I would suggest making a 'through' model representing the relationship and passing that into the ManyToManyField constructor. You could then register that through model to have its history tracked. If you get errors like "unexpected keyword argument 'm2m_fields'" with that set up please open an issue in our tracker.
Even though django-simple-history does not allow to have history tables for many to many relations there is actually a way to achieve this.
What you can do is that you manually create the many to many table and instead of using djangos add and remove you simply create and delete the relations. If you look at it with an example we would have:
class Class(models.Model):
name = models.CharField(max_length=255)
surname = models.CharField(max_length=255)
history = HistoricalRecords()
class Student(models.Model):
name = models.CharField(max_length=255)
surname = models.CharField(max_length=255)
classes = models.ManyToManyField(Class)
history = HistoricalRecords()
you can manually create the many to many table with:
class Class(models.Model):
name = models.CharField(max_length=255)
surname = models.CharField(max_length=255)
history = HistoricalRecords()
class Student(models.Model):
name = models.CharField(max_length=255)
surname = models.CharField(max_length=255)
history = HistoricalRecords()
class StudentClasses(models.Model):
student = models.ForeignKey(Student)
class = models.ForeignKey(Class)
history = HistoricalRecords()
if you now use:
StudentClasses.objects.create(student=student, class=class) instead of student.classes.add(class) and delete() instead of student.classes.remove(class) you will have everything tracked in a history table and the same many to many table.
As the author of django-simple-history says this isn't possible to detect change in only specific fields because
As you already know simple-history doesn't look at the values being
saved at all. It blindly saves a new historical version on every save
or delete signal.
He also says it may be possible Field Tracker do this job.

Why should I set default value of foreign key, django

For example, we have this code:
class Foo(models.Model):
a = models.CharField(max_length=10)
class Bar(models.Model):
b = models.CharField(max_length=10)
a = models.ForeignKey(Foo)
And when I run makemigrations, i see that I need set default of a(Bar)
Can anyone explain me, why should I do it?
Thanks!
It seems that you already have some data in your database (or you have made a migration before adding the ForeignKey field). In order for the migration to work you will need to "tell" Django what data should be in the a column of the Bar table for rows that already exist.
Either delete your whole database/earlier migrations, or provide a default value of your choice:
a = models.ForeignKey(Foo, default=None) # or any other default value

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

Categories