Django query extended USER table - python

I have a profile table which have a foreign key of the user.
class Profile(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
image = models.CharField(max_length=100)
user = models.ForeignKey(User)
I also have a COMMENT table which have a foreign key of the user.
class Comment(models.Model):
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
content = models.TextField()
user = models.ForeignKey(User)
I want to query the table COMMENT and also I want to get the image of the user which is in the PROFILE table. How can I query this in most effective way in django?.
thanks

If you are okay with changing ForeignKey to OneToOneField on Profile model then you can do it like,
Comment.objects.all().select_related('user__profile')
The above one selecting additional related-object data when it executes its query. This is a performance booster which results in a single more complex query but means later use of foreign-key relationships won’t require database queries.
Otherwise you can get it this way
for comment in Comment.objects.all():
print comment.user.profile_set.all()[0].image

If you're using Django = <1.4 the following is best practice:
comment = Comment.objects.get(pk=1)
comment.user.get_profile().image
Following the deprecation of native Profile model support (Django 1.5+) the following is still possible:
comment = Comment.objects.get(pk=1)
comment.user.profile.image
Django 1.5+ introduces custom auth models so you can do the following:
comment = Comment.objects.get(pk=1)
comment.user.image
At very least you should change your ForeignKey to a OneToOne relation for the user column on Profile, as Django =< 1.4 expects only one User Profile to be associated with a User.
References:
Django 1.4 get_profile: https://docs.djangoproject.com/en/1.4/topics/auth/#django.contrib.auth.models.User.get_profile
Django 1.5+ extending the user model:
https://docs.djangoproject.com/en/1.9/topics/auth/customizing/#extending-the-existing-user-model

Related

Effecient way to fetch related models count in Django ORM

I'm working on Django 1.10 and PostgreSQL9.6
I have two models in my project: Order and Customer. Also I'm using Django's auth.User to store login credentials.
Here is a code snipped:
from django.contrib.auth.models import User
from django.db import models
class Order(models.Model):
created_by = models.ForeignKey(User, null=True, on_delete=models.SET_NULL, related_name='created_orders')
# ... other fields ...
class Customer(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
# ... other fields ...
Now, I need to show a table of customers and show a number of orders created by each of them.
The staight forward code is:
for customer in Customer.objects.all():
print(customer.user.created_orders.count())
Now I need to avoid N+1 problem and make Django to fetch all data with constant number of queries.
I've tried to write something like:
query = Customer.objects.select_related('user').annotate(
orders_count=Count('user.created_orders')
)
But this gives me an error like Cannot resolve keyword 'user.created_orders' into field.
Can you help me with this?
You should not use a dot (.) here, but two consecutive underscores (__):
query = Customer.objects.select_related('user').annotate(
orders_count=Count('user__created_orders')
)
Note that you do not need to .select_related('user') in order to annotate a queryset. If you however plan to use the .user later in your logic, it can indeed boost performance.

How To Separate Objects In Django Admin?

I have an app called 'Product' with the following models.py:
class Product(models.Model):
product_id = models.CharField(max_length=50)
pub_date = models.DateTimeField(default=datetime.now)
title = models.CharField(max_length=255)
price = models.DecimalField(max_digits=8, decimal_places=2)
user = models.ForeignKey(User, on_delete=models.CASCADE)
featured = models.BooleanField(default=False)
I want to have two separate sections in Django Admin: Products and Featured Products, depending if featured = True or False.
So by default all products are listed under the Products section. But if featured = True they will be moved to Featured Products section. Can you please help me how to do that? Thanks in advance.
Three steps:
Write a proxy model for model Product.
Change the default manager to only returns featured products.
Register your proxy model in the admin like any other model.
You can read more about it here: Using Proxy Models to Customize the Django Admin
There are a couple of ways to do this. The simplest perhaps is to create a database view, and then encapsulate it using a django model. You can create a view like so in your database console:
CREATE VIEW view_name AS
SELECT columns
FROM tables
[WHERE conditions];
Once you have done that, you can reference the view in django like so:
class FeaturedProduct(modes.Model):
attr1 = models.CharField()
class Meta:
managed = False
db_table = '<name of your view here>'
Make sure that managed is set to False. Here is the relevant documentation for that. You want to do that because django is not creating this model for you, but rather you are creating it yourself.
Another way to do this would be to create a custom Manager. These managers allow you to modify the objects attribute of your model, allowing you to set a queryset that you want. I think you'd want to take a look at the Manager documentation and you can take a look at defining custom querysets for your objects.

How to get relevant data from a parent model in Django?

I have 2 database tables, Prospects and Profile. They're related by a One-to-one foreign key relationship
Model.py
class Prospect(models.Model):
profile = models.OneToOneField(Profile, on_delete=models.CASCADE, null=True, blank=True, related_name="profile_prospects")
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE, related_name="profile")
In my view.py
prospects = prospects[:50]
I have a QuerySet of prospects (prospects is working correctly, exactly what I want), and I would like to retrieve a QuerySet of profiles based on the database model above. I tried
profiles = Profile.objects.filter(profile_prospects__in = prospects)
It returns an error of
django.db.utils.ProgrammingError: subquery has too many columns
How can I get all the relevant profiles?
You have spaces in
profiles = Profile.objects.filter(profile_prospects__in = prospects)
Sorry, I might be confused here. But isn't the profile automatically inherited by the prospect since it's a one-to-one relationship?
When you have the prospect you should be able to get the profile like this
prospect.profile
Again, I might have gotten the question wrong.

Django Rest Framework not saving foreign key for a small number of requests

I am using Django Rest Framework to provide API to a mobile app. I have two models, Order and User. Order has a foreign key relation to User.
For about 1% or so of all my order objects, the User field is null. I've been testing this behavior using cURL.
If I do a cURL without a user object, it tells me "This field is required".
If done with a wrong user object, it tells me that the object does not exist. Both of these are the intended and expected behaviors.
I'm trying to figure out how it is possible for some of the Order objects to be saved without a user field. Is there something I'm not taking into account?
My views:
class OrderList (generics.ListCreateAPIView):
model = Order
serializer_class = OrderSerializer
And serializer:
class OrderSerializer (serializers.ModelSerializer):
user = serializers.SlugRelatedField(slug_field = 'user')
partial = True
class Meta:
model = Order
Models:
class User (models.Model):
uid = models.CharField(max_length =200, unique=True)
class Order (models.Model):
uid = models.ForeignKey (User, related_name = "orders", verbose_name = "User",blank=True, null=True)
You could use two different ModelSerializer classes, one for creation, that makes sure, that an Order object can't be created without a related User and one for updating orders, that passes required=False to the related field's constructor, so that you still can save existing orders that haven't a related User.
Try adding default=None to your models.ForeignKey declaration. You could also just create an anonymous user in the users table and when the user isn't specified it could set the anonymous user instead.

django orm: retrieve object and check if it has a relation in one query

I have an application where users can set a post as their favorite. Models are defined like this:
class UserProfile(models.Model):
user = models.OneToOneField(User)
favorites = models.ManyToManyField('Post', through='Favorite', related_name='favorited_by')
class Post(models.Model):
created_by = models.ForeignKey(UserProfile)
body = models.TextField()
class Favorite(models.Model):
created_by = models.ForeignKey(UserProfile)
post = models.ForeignKey(Post)
Now I'm looking for an easy way to query a post and at the same time check if the post is favorited by the current user. Currently I'm using the following, far from elegant, solution:
query = """
SELECT p.id, p.body, p.created_by_id, f.created_by_id AS favorited
FROM main_post p LEFT OUTER JOIN main_favorite f
ON
p.id = f.post_id AND
f.created_by_id = %s
""";
posts = Post.objects.raw(query, [request.user.userprofile.id])
This results in a column named 'favorited' with either a null value if the post is not favorited by the current user or with the id of the current user if the post is favorited.
Is there anyway this could be done simpler and more elegant using django's ORM?
Django provides with the contenttypes framework which might be useful in your case. And it is also does the same work in a more elegant way using generic foreign keys for this.
**Check the examples at https://docs.djangoproject.com/en/dev/ref/contrib/contenttypes/ they are very similar to what you're trying to achieve

Categories