Can I safely assume that Django models IDs are unique upon save() - django

I need to store matches in my database and those matches already have a unique ID where they come from. For further assistance and referring, it is best for me to keep this ID:
match = Match(id=my8digitsid)
match.save()
However, incoming matches (not played yet) don't have an ID yet. Can I safely save my match as follow:
match = Match()
match.save
And then, once the match played modify it as such:
match.id = my8digitsid
When I say safely, I mean whether or not that the default ID generated (auto-incremented I guess) is unique and won't have any conflicts with my self-made IDs.

Yes, you can be sure that the ORM will make unique id's as referred in the documentation here. The database is the one calculating the new number.
If a model has an AutoField — an auto-incrementing primary key — then
that auto-incremented value will be calculated and saved as an
attribute on your object the first time you call save():
>>> b2 = Blog(name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b2.id # Returns None, because b doesn't have an ID yet.
>>> b2.save()
>>> b2.id # Returns the ID of your new object. There’s no way to tell what the value of an ID will be before you call save(), because
that value is calculated by your database, not by Django.
For convenience, each model has an AutoField named id by default
unless you explicitly specify primary_key=True on a field in your
model.
You can also provide the Id if you want using this. I copy below the info from Django documentation.
Explicitly specifying auto-primary-key values If a model has an
AutoField but you want to define a new object’s ID explicitly when
saving, just define it explicitly before saving, rather than relying
on the auto-assignment of the ID:
>>> b3 = Blog(id=3, name='Cheddar Talk', tagline='Thoughts on cheese.')
>>> b3.id # Returns 3.
>>> b3.save()
>>> b3.id # Returns 3.
If you assign auto-primary-key values manually, make sure not to use
an already-existing primary-key value! If you create a new object with
an explicit primary-key value that already exists in the database,
Django will assume you’re changing the existing record rather than
creating a new one.
Given the above 'Cheddar Talk' blog example, this example would
override the previous record in the database:
b4 = Blog(id=3, name='Not Cheddar', tagline='Anything but cheese.')
b4.save() # Overrides the previous blog with ID=3!
But I don't recommend You to assign that ID yourself. I think more convenient to create a field of the model with the ID from where they come from.
The reason Why I don't recommend this is because you will have to verify always that the id provided has not been used before before inserting it. As a general rule I try to avoid modifying the standard behaviour of Django as much as possible.

Related

How to get the value of the counter of an AutoField?

How to get the value of the counter of an AutoField, such as the usual id field of most models?
At the moment, I do:
MyModel.objects.latest('id').id
But that does not work when all the objects have been deleted from the database.
Of course, a database-agnostic answer would be best.
EDIT
The accepted answer in Model next available primary key is not very relevant to my question, as I do not intend to use the counter value to create a new object. Also I don't mind if the value I get is not super accurate.
Background.
AFAIK there isn't a database agnostic query. Different databases handle auto increment differently and there rarely is a use case for django to find out what the next possible auto increment ID is.
To elaborate further, in postgresql you could do select nextval('my_sequence') while in mysql you would need to use the last_insert_id() but what this returns is the ID for the last insert and not the next one these two may actually be very different! To get the actual value you would need to use 'SHOW TABLE STATUS'
Solution.
Create a record, save it, inspect it's ID and delete it.
This will change the next id but you have indicated that you need only an approximation.
The alternative is to do a manual transaction with a rollback. This too would alter the next id in case of mysql.
from django.db import transaction
#transaction.atomic
def find_next_val(mymodel):
try:
# ...
obj = mymoel.objects.create(....)
print obj.id
raise IntegrityError
except IntegrityError:
pass

Django annotate a field value to queryset

I want to attach a field value (id) to a QS like below, but Django throws a 'str' object has no attribute 'lookup' error.
Book.objects.all().annotate(some_id='somerelation__id')
It seems I can get my id value using Sum()
Book.objects.all().annotate(something=Sum('somerelation__id'))
I'm wondering is there not a way to simply annotate raw field values to a QS? Using sum() in this case doesn't feel right.
There are at least three methods of accessing related objects in a queryset.
using Django's double underscore join syntax:
If you just want to use the field of a related object as a condition in your SQL query you can refer to the field field on the related object related_object with related_object__field. All possible lookup types are listed in the Django documentation under Field lookups.
Book.objects.filter(related_object__field=True)
using annotate with F():
You can populate an annotated field in a queryset by refering to the field with the F() object. F() represents the field of a model or an annotated field.
Book.objects.annotate(added_field=F("related_object__field"))
accessing object attributes:
Once the queryset is evaluated, you can access related objects through attributes on that object.
book = Book.objects.get(pk=1)
author = book.author.name # just one author, or…
authors = book.author_set.values("name") # several authors
This triggers an additional query unless you're making use of select_related().
My advice is to go with solution #2 as you're already halfway down that road and I think it'll give you exactly what you're asking for. The problem you're facing right now is that you did not specify a lookup type but instead you're passing a string (somerelation_id) Django doesn't know what to do with.
Also, the Django documentation on annotate() is pretty straight forward. You should look into that (again).
You have <somerelation>_id "by default". For example comment.user_id. It works because User has many Comments. But if Book has many Authors, what author_id supposed to be in this case?

How to deal with the required value which does not have a default value in Django model

The version of my Django is 1.7.
I have a model named Booking, it has a Boolean field named is_departure, which is used to describe the booking is departure or arrival.
class Booking(models.Model):
...
is_departure = models.BooleanField()
...
When I migrate my app, it will return me a warning that is_departure does not have a default value.
However, I do not want to add a default value for is_departure. This is a required value and it needs to be filled by user. I do not want to use NullBooleanField neither, because is_departure should not be null.
Is there any good way to remove this warning?
The problem is, what will Django put as a value for all the existing rows that now have a is_departure value that according to you, cannot be null, you can't satisfy this constraint.
If you're still developing, then you can reset the DB and you can indeed use BooleanField without default (since there will be no existing rows violating this)
Otherwise, I'd make the migration put a is_departure value (true or false) on the existing rows, consistent with your business logic

Django replicating a model object causing issue

I have a 2 models with a foreign/Primary key to same model.
model Foo:
FK(Too, pk)
model Coo:
FK(Too, pk)
model Too:
blah = charfield()
In the views I am seeing some very strange behavior. I think I am doing something very wrong.
I want to replicate a object of Too and then save it. For e.g.
too = Too.create(blah="Awesome")
too.save()
foo = Foo.create(too=too)
foo.save()
too.id = None #Copy the original
too.save()
coo = Coo.create(too=too)
coo.save()
print foo.too.id
print coo.too.id
#above 2 print statements give same id
When I check in the admin the both foo and coo have different too object saved. But while printing it is showing the same. Why is that happening. I think I am doing something fundamentally wrong.
Django looks at the primary key to determine uniqueness, so work with that directly:
too.pk = None
too.save()
Setting the primary key to None will cause Django to perform an INSERT, saving a new instance of the model, rather than an UPDATE to the existing instance.
Source: https://stackoverflow.com/a/4736172/1533388
UPDATE: err, using pk and id are interchangeable in this case, so you'll get the same result. My first answer didn't address your question.
The discrepancy here is between what is occurring in python vs. what can be reconstituted from the database.
Your code causes Django to save two unique objects to the database, but you're only working with one python Too instance. When foo.save() occurs, the database entry for 'foo' is created with a reference to the DB entry for the first Too object. When coo.save() occurs, the database entry for 'coo' is created, pointing to the second, unique Too object that was stored via:
too.id = None #Copy the original
too.save()
However, in python, both coo and foo refer to the same object, named 'too', via their respective '.too' attributes. In python, there is only one 'Too' instance. So when you update too.id, you're updating one object, referred to by both coo and foo.
Only when the models are reconstituted from the database (as the admin view does in order to display them) are unique instances created for each foreign key; this is why the admin view shows two unique saved instances.

Django Autoselect Foreign Key Value

I have a model that contains a foreign key value, then in the form generated from this model, I want to auto select the record's key according to the record I'm adding the form's contents to...I've tried the below code, but it tells me QuerySet doesn't contain vehicle
stock = Issues.objects.filter(vehicle=id)
form = IssuesForm(initial={'id_vehicle': stock.vehicle})
I'm a bit new to django btw so any ideas are highly appreciated
filter always gives a QuerySet, which is a set of values. If you just want a single object, you should use get.
However I don't really understand why you need to do the lookup at all. You have the id value already, since you are using it to look up stock. So why don't you just pass id as the value for id_vehicle?