Django model object with foreign key creation - django

Hi
Suppose I have a simple model class like this:
class TestModel(models.Model):
testkey = models.ForeignKey(TestModel2)
...
When I am creating a TestModel object I have to pass to it an instance of the TestModel2 object to create it:
testkey =TestModel2.objects.get(id=...)
TestModel.objects.create(testkey=testkey)
This results in 2 queries to database I suppose, and I have a list of Foreign key IDs that I need to create objects with.
Is it possible to create objects with foreign keys without initially retrieving the foreign key objects?

What you’re after is:
TestModel.objects.create(testkey_id=1)

In my case TestModel.objects.create(testkey__id=1) didn't work for me so I had to put one underscore instead of two, for example
TestModel.objects.create(testkey_id=1)

In get_or_create it will fail in get. So to make get_or_create work below is the solution:
TestModel.objects.get_or_create(testkey=TestModel2(id=1))
Reference:
https://code.djangoproject.com/ticket/13915

Related

how to pass null value to just one specific key of the one object using same DRF serializer

I'm just passing the same object 2 times in the same serializer but I want to pass key: "retweet": null in one object and in another object I want to pass some values like some many-to-many field values because key "retweet" is many-to-many field and having data
Thanks in advance!

How can I use Django's update_or_create function for a model with multiple fields?

I have a model with many fields. In order to update my model, I make a query for my DB and using the dictfetchall() from Django I get a list of dicts containing the results from the query (each key in each dict is the column name for 1 object).
class Enterprise(models.Model):
--- primary key here ---
...
--- many other fields here ---
I want to use the Django's function update_or_create() for updating the existing rows with new information or creating new rows if the object already not exists (based on its pk).
But I don't know how to implement this, due to the large number of fields. Furthermore, the dict keys are not equal to the name of the field in my model.
How can I do this?
Than you!
If I simplify the question a little, you have a list of many objects as dicts you and to add to your database. Some are new, and some already exist. You want to update the existing and create the new ones.
You can use django-bulk-update-or-create to do that.
For the example, I'll use inputs as the list of dictionaries containing your new information.
Enterprise.objects.bulk_update_or_create([
Enterprise(**fields)
for fields in input
], ["all_your_fields_here"], match_field="pk")

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 orm - How to use select_related() on the Foreign Key of a Subclass from its Super Class

I've always found the Django orm's handling of subclassing models to be pretty spiffy. That's probably why I run into problems like this one.
Take three models:
class A(models.Model):
field1 = models.CharField(max_length=255)
class B(A):
fk_field = models.ForeignKey('C')
class C(models.Model):
field2 = models.CharField(max_length=255)
So now you can query the A model and get all the B models, where available:
the_as = A.objects.all()
for a in the_as:
print a.b.fk_field.field2 #Note that this throws an error if there is no B record
The problem with this is that you are looking at a huge number of database calls to retrieve all of the data.
Now suppose you wanted to retrieve a QuerySet of all A models in the database, but with all of the subclass records and the subclass's foreign key records as well, using select_related() to limit your app to a single database call. You would write a query like this:
the_as = A.objects.select_related("b", "b__fk_field").all()
One query returns all of the data needed! Awesome.
Except not. Because this version of the query is doing its own filtering, even though select_related is not supposed to filter any results at all:
set_1 = A.objects.select_related("b", "b__fk_field").all() #Only returns A objects with associated B objects
set_2 = A.objects.all() #Returns all A objects
len(set_1) > len(set_2) #Will always be False
I used the django-debug-toolbar to inspect the query and found the problem. The generated SQL query uses an INNER JOIN to join the C table to the query, instead of a LEFT OUTER JOIN like other subclassed fields:
SELECT "app_a"."field1", "app_b"."fk_field_id", "app_c"."field2"
FROM "app_a"
LEFT OUTER JOIN "app_b" ON ("app_a"."id" = "app_b"."a_ptr_id")
INNER JOIN "app_c" ON ("app_b"."fk_field_id" = "app_c"."id");
And it seems if I simply change the INNER JOIN to LEFT OUTER JOIN, then I get the records that I want, but that doesn't help me when using Django's ORM.
Is this a bug in select_related() in Django's ORM? Is there any work around for this, or am I simply going to have to do a direct query of the database and map the results myself? Should I be using something like Django-Polymorphic to do this?
It looks like a bug, specifically it seems to be ignoring the nullable nature of the A->B relationship, if for example you had a foreign key reference to B in A instead of the subclassing, that foreign key would of course be nullable and django would use a left join for it. You should probably raise this in the django issue tracker. You could also try using prefetch_related instead of select_related that might get around your issue.
I found a work around for this, but I will wait a while to accept it in hopes that I can get some better answers.
The INNER JOIN created by the select_related('b__fk_field') needs to be removed from the underlying SQL so that the results aren't filtered by the B records in the database. So the new query needs to leave the b__fk_field parameter in select_related out:
the_as = A.objects.select_related('b')
However, this forces us to call the database everytime a C object is accessed from the A object.
for a in the_as:
#Note that this throws an DoesNotExist error if a doesn't have an
#associated b
print a.b.fk_field.field2 #Hits the database everytime.
The hack to work around this is to get all of the C objects we need from the database from one query and then have each B object reference them manually. We can do this because the database call that accesses the B objects retrieved will have the fk_field_id that references their associated C object:
c_ids = [a.b.fk_field_id for a in the_as] #Get all the C ids
the_cs = C.objects.filter(pk__in=c_ids) #Run a query to get all of the needed C records
for c in the_cs:
for a in the_as:
if a.b.fk_field_id == c.pk: #Throws DoesNotExist if no b associated with a
a.b.fk_field = c
break
I'm sure there's a functional way to write that without the nested loop, but this illustrates what's happening. It's not ideal, but it provides all of the data with the absolute minimum number of database hits - which is what I wanted.

How to get objects out of a distinct() in Django?

I wonder if this query can be modified to return User objects instead of just merchant_id (User).
(User.objects.get(id=merchant['merchant_id']) for merchant in self.user.visits.values('merchant_id').distinct())
You are creating 1 DB query for each User (which is a Merchant?) lookup. Need to brush up on my django ORM but I would do something like:
User.objects.filter(id__in=[ merchant['merchant_id'] for merchant in self.user.visits.values('merchant_id').distinct() ])
How does this sound?
merchants_visited = self.user.visits.merchants.all().distinct()
return User.objects.filter(visits__merchants__in=merchants_visited, profile=self)