Use F value as dict key for ordering django - python

I am developing a Django website and I have the following models (simplified):
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
opinions = JSONField(default=default_opinions)
class Author(models.Model):
name = models.CharField(max_length=50, unique=True)
class Book(models.Model):
author = models.ForeignKey(Author, on_delete=models.CASCADE, default='0')
with the opinions field being the opinion that a specific user has of the different authors:
Exemple:
{
Shakespeare: 0.5,
Voltaire: 0.6
}
Then I have a listView BookListView, in which I want to query the Book database, and order them by the opinion the currently logged in user has of their author.
In the previous example it would be all the Voltaire's books first, then the Shakespeare's ones.
So I came up with this in my listView:
def get_queryset(self):
user_opinions = self.request.user.profile.opinions
queryset = Book.objects.order_by(user_opinions[F("author__name")])
return queryset
The problem is the F value is computed after the get_queryset(), so I get a F("author__name") key does not exist error.
I thought about iterating through the dict keys and values but I don't see how that could work since opinions are floats (and thus can take any values).
Thanks in advance ^^

F expressions doesn't support JSON field lookup,that's why you are getting error key does not exist, because it is trying to find field named with that and running join on that field,
Can you elaborate more, on what key and value pair are there in json Field

Related

DJANGO get objects in sql like join

Context: I'm forcing my self to learn django, I already wrote a small php based website, so I'm basically porting over the pages and functions to learn how django works.
I have 2 models
from django.db import models
class Site(models.Model):
name = models.CharField(max_length=50, unique=True)
def __str__(self):
return self.name
class Combo(models.Model):
username = models.CharField(max_length=50)
password = models.CharField(max_length=50)
dead = models.BooleanField(default=False)
timestamp = models.DateTimeField(auto_now_add=True)
siteID = models.ForeignKey(Site, on_delete=models.PROTECT)
class Meta:
unique_together = ('username','siteID')
def __str__(self):
return f"{self.username}:{self.password}#{self.siteID.name}"
When creating a view, I want to get the Combo objects, but I want to sort them first by site name, then username.
I tried to create the view, but get errors about what fields I can order by Cannot resolve keyword 'Site' into field. Choices are: dead, id, password, siteID, siteID_id, timestamp, username
def current(request):
current = Combo.objects.filter(dead=False).order_by('Site__name','username')
return render(request, 'passwords/current.html',{'current':current})
Since I'm not necissarily entering the sites into the database in alphabetical order, ordering by siteID wouldn't be useful. Looking for some help to figure out how to return back the list of Combo objects ordered by the Site name object then the username.
You can order this by siteID__name:
def current(request):
current = Combo.objects.filter(dead=False).order_by('siteID__name','username')
return render(request, 'passwords/current.html',{'current':current})
since that is the name of the ForeignKey. But that being said, normally ForeignKeys are not given names that end with an ID, since Django already adds an _id suffix at the end for the database field.
Normally one uses:
class Combo(models.Model):
# …
site = models.ForeignKey(Site, on_delete=models.PROTECT)
if you want to give the database column a different name, you can specify that with the db_column=… parameter [Django-doc]:
class Combo(models.Model):
# …
site = models.ForeignKey(
Site,
on_delete=models.PROTECT,
db_column='siteID'
)

Filtering by Field on Foreign Key

I've got two models that are related to one another
class IndustryService(models.Model):
title = models.CharField(max_length=120)
pricingisarate = models.BooleanField(default=False)
class UserService(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
title = models.ForeignKey(IndustryService, on_delete=models.CASCADE, null=True, blank=True)
Within a view, I'm trying to develop a queryset of UserService instances that
a) belongs to a user
b) on the foreign key, has pricingisarate == True
I've tried the following query, but it doesn't work:
services = UserService.objects.filter(user=user, industryservice__pricingisarate__is=True)
Thanks for your help!!!
Got it!
services = UserService.objects.filter(user=user, title__pricingisarate=True)
You can filtering Foreign-Keys fields by using double underline between foreign-key defined name and sub field name that you want filtering by this, for your case it is similar below:
title__pricingisarate
And your query must change as below:
services = UserService.objects.filter(user=user, title__pricingisarate=True)
Some formal examples of Django about this article is available...
services = UserService.objects.filter(user=user, title__pricingisarate=True)
Because UserService is related to IndustryService model using lookup title.
Please refer to this link - https://docs.djangoproject.com/en/2.1/topics/db/queries/#lookups-that-span-relationships

django db_index for foreign key reverse lookup

I've read that django creates db_index automatically for all foreign keys. However, does that db_index improve the performance of the reverse lookup as well?
For example, if B has a foreign key to A and I use a.b_set.all(), do I enjoy the performance boost from the db index or not?
And if not, is there a way to make the foreign key reverse lookup faster with db index?
Thanks,
Let's say the you have a simple model structure:
class Author(models.Model):
name = models.CharField(max_length=70)
email = models.EmailField()
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.ForeignKey(Author)
As you mention Book.author already have index, because it's a ForeignKey
Now querying:
author_books = Book.objects.filter(author=a)
or
author_books = a.book_set.all()
produce the exact same query, therefore the book.author index will be used in both situations.

Python Django how to retrieve specific objects

I've got this Post model at the moment:
class Post(models.Model):
title = models.CharField(max_length = 140)
body = models.TextField()
date = models.DateTimeField()
def __unicode__(self):
return self.title
If I've got different parts of a website (or a forum rather) that contain different posts, e.g. Discussion about basketball, and Discussion about football, if I wanted to return just posts concerning basketball or just posts concerning football, is the easiest way to just make a specific basketball_post model/football_post model or is there a more efficient way? Should I perhaps be storing the values differently?
Thanks
Django has a really good tutorial. It is about making a Poll app. In the first chapter the thing you want is discussed. It is about a Question that can have multiple Choices.:
class Question(models.Model):
question_text = models.CharField(max_length=200)
pub_date = models.DateTimeField('date published')
class Choice(models.Model):
question = models.ForeignKey(Question)
choice_text = models.CharField(max_length=200)
votes = models.IntegerField(default=0)
The foreignKey creates a relation between two models. The same can be done for a blog:
class Category(models.Model):
title = models.CharField(max_length=200)
class Post(models.Model):
category = models.ForeignKey(Category) # This is the important part.
title = models.CharField(max_length=200)
body = models.TextField()
date = models.DateTimeField()
def __unicode__(self):
return self.title
The ForeignKey relation lets you do really nice things:
basketball_posts = Post.objects.filter(category_title='Basketball')
But before we all tell you how it is done, I really recommend to do the tutorial. It introduces you to all important Django concepts: https://docs.djangoproject.com/en/1.7/intro/tutorial01/
Update
If you have a fixed set of categories that are not likely to change, than you can hardcode them and use field choices:
class Post(models.Model):
FOOTBALL = 'F' # Variable name and db_value
CRICKET = 'C'
INTRODUCTION = 'I'
CATEGORY_CHOICES = (
(FOOTBALL, 'Soccer'), # Variable name and display value
(CRICKET, 'Cricket'),
(INTRODUCTION, 'Hello my name is'),
)
category = models.CharField(max_length=1,
choices=CATEGORY_CHOICES,
default=INTRODUCTION)
...
https://docs.djangoproject.com/en/dev/ref/models/fields/#choices
One of the advantages of this 'choice machinery' over a CharField without pre defined choices is that you are sure what values end up in your database. This lets you query them, without worrying if your data is sane:
Post.objects.filter(category=Post.CRICKET)
Use the extra table if you need the freedom to create new categories in the future. Use field choices if you don't want (or need) that freedom.
I would suggest to just add a field which makes the post relevant to that certain topic:
class Post(models.Model):
title = models.CharField(max_length = 140)
body = models.TextField()
date = models.DateTimeField()
type = models.CharField(max_length=20) #<--- new field: e.g 'basketball','hockey'..
def __unicode__(self):
return self.title
example query:
#basketball posts
qs = Post.objects.filter(type__icontains="basketball")
then you dont need to have multiple models which also would be redundant.
Assuming all of the posts are in the same format, you could add another field to your model like "type". Different discussion forums could send a different values for that field when the post is added.
type = models.CharField(max_length=140, choices=['Football', 'Basketball', 'Baseball'])
Storing this would make it easy to filter which posts are which.
Post.objects.filter(type = 'Football')
Assuming that one post can be about only one sport, the better approach would be to have a foreign key relation between a model that stores data about a post with another model that stores the data about sports.
Something like this
class Sport(models.Model):
name = models.CharField(max_length = 200)
description = models.TextField()
def __unicode__(self):
return self.name
class Post(models.Model):
title = models.CharField(max_length = 140)
body = models.TextField()
date = models.DateTimeField()
sport = models.ForeignKey(Sport)
def __unicode__(self):
return self.title
This gives you the advantage of isolating the 'Sport' and the 'Post' models.You can add as many sports as you want, without any posts referring to it.
One more advantage is that you can add relevant information to the relevant models.
Eg:Suppose you want to add the information about "how many players are there in a team for sport x?". You can easily achieve this by adding a field "number_of_players" in the 'Sport' model without affecting the 'Post' model.
If you had to do this in one model, 'Post', then it would create lot of issues in terms of data consistency and other undesirable things.
Also, the query will look something like this:
posts = Post.objects.filter(sport__name = "Basketball")
PS:If your requirement is that a post can be tagged to multiple sports, then you can use ManyToMany field instead of a simple foreign key.
https://docs.djangoproject.com/en/dev/topics/db/examples/many_to_many/
You could assign your posts tags or category, and filter on those.
If you use the model approach what happens when you add more sports? You'll need manually add the sports in your code, using a tags or category approach allows you to handle it in the db, and would then allow you to filter on the tags/categories in your system

Django one-to-many, add fields dynamically in Admin

I have the following code:
class Item(models.Model):
name = models.CharField(max_length=100)
keywords = models.CharField(max_length=255)
type = models.ForeignKey(Type)
class Meta:
abstract = True
class Variant(models.Model):
test_field = models.CharField(max_length=255)
class Product(Item):
price = models.DecimalField(decimal_places=2, max_digits=8,null=True, blank=True)
brand = models.ForeignKey(Brand)
variant = models.ForeignKey(Variant)
def get_fields(self):
return [(field.name, field.value_to_string(self)) for field in Product._meta.fields]
def __unicode__(self):
return self.name
Im using Grappelli.
I want my Product to have multiple Variations. Should I use a manytomanyfield?
I want to be able to add Variants to my Product directly in the Admin. Now I get an empty dropwdown with no variants(because they doesnt exists).
I thought Django did this automatically when u specified a Foreign Key?
How can I get the Variant fields to display directly on my Product page in edit?
I've read someting about inline fields in Admin?
Well, it's the other way around :)
1/ Place the foreign key field in your Variant, not in your Product (what you describe is actually a OneToMany relationship).
2/ Link the Variant to your Product in the relative ProductAdmin in admin.py as an inline (i.e VariantInline).
See the docs for further informations : https://docs.djangoproject.com/en/1.6/ref/contrib/admin/#inlinemodeladmin-objects
Hope this helps !
Regards,

Categories