Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django models - assign id instead of object

I apologize if my question turns out to be silly, but I'm rather new to Django, and I could not find an answer anywhere.

I have the following model:

class BlackListEntry(models.Model):
  user_banned = models.ForeignKey(auth.models.User,related_name="user_banned")
  user_banning = models.ForeignKey(auth.models.User,related_name="user_banning")

Now, when i try to create an object like this:

BlackListEntry.objects.create(user_banned=int(user_id),user_banning=int(banning_id))

I get a following error:

Cannot assign "1": "BlackListEntry.user_banned" must be a "User" instance.

Of course, if i replace it with something like this:

user_banned = User.objects.get(pk=user_id)
user_banning = User.objects.get(pk=banning_id)
BlackListEntry.objects.create(user_banned=user_banned,user_banning=user_banning)

everything works fine. The question is:

Does my solution hit the database to retrieve both users, and if yes, is it possible to avoid it, just passing ids?

like image 222
Marcin Kulus Avatar asked Oct 01 '12 22:10

Marcin Kulus


1 Answers

The answer to your question is: YES.

Django will hit the database (at least) 3 times, 2 to retrieve the two User objects and a third one to commit your desired information. This will cause an absolutelly unnecessary overhead.

Just try:

BlackListEntry.objects.create(user_banned_id=int(user_id),user_banning_id=int(banning_id))

These is the default name pattern for the FK fields generated by Django ORM. This way you can set the information directly and avoid the queries.

If you wanted to query for the already saved BlackListEntry objects, you can navigate the attributes with a double underscore, like this:

BlackListEntry.objects.filter(user_banned__id=int(user_id),user_banning__id=int(banning_id))

This is how you access properties in Django querysets. with a double underscore. Then you can compare to the value of the attribute.

Though very similar, they work completely different. The first one sets an atribute directly while the second one is parsed by django, that splits it at the '__', and query the database the right way, being the second part the name of an attribute.

You can always compare user_banned and user_banning with the actual User objects, instead of their ids. But there is no use for this if you don't already have those objects with you.

Hope it helps.

like image 89
Francisco Avatar answered Oct 12 '22 08:10

Francisco