Django query using filters - django

I have 3 models in django:
class Movie(models.Model):
mid = models.IntegerField(primary_key = True)
name = models.CharField(max_length = 100)
class User(models.Model):
username = models.CharField(max_length=128, null=True)
uid = models.CharField(max_length=100)
movie = models.ManyToManyField(Movie, through = "Vote")
class Vote(models.Model):
movie = models.ForeignKey(Movie)
user = models.ForeignKey(User)
rating = models.IntegerField()
here rating = 0/1, 0 means dislike, 1 means like
i want to make some queries using filters:
find out all movies that a current user likes. For that i use this following 2 queries, but none of them work. In both cases it gives erroneous results
ans = Movie.objects.filter(vote__user = self).filter(vote__rating = 1)
ans = Movie.objects.filter(user__uid = self.uid).filter(vote__rating = 1)
I have a list of users in an array ids. I want to find out how many users from this list like a particular movie?
i tried this, but this is also incorrect:
ret = User.objects.filter(uid__in = ids).filter(vote__movie = mov).filter(vote__rating = 1)
can somebody please help me with these 2 queries?

I'd also suggest letting django assign the model's id's but if you are using a legacy database or for some other reason need to assign the id's you can query like so:
# uid is some uid
user = User.objects.get(uid=uid)
likes = Movie.objects.filter(vote__user=user, vote__rating=1)
or
likes = Movie.objects.filter(vote__user__uid=some_uid, vote__rating=1)
count of people in the list of users who like a specific movie:
>>> uids = ['1','2','3']
>>> # if mov is a Movie instance
>>> votes = Vote.objects.filter(user__uid__in=uids, movie=mov, rating=1)
>>> print votes.query
SELECT "so1_vote"."id", "so1_vote"."movie_id", "so1_vote"."user_id", "so1_vote"."rating" FROM "so1_vote" INNER JOIN "so1_user" ON ("so1_vote"."user_id" = "so1_user"."id") WHERE ("so1_user"."uid" IN (1, 2, 3) AND "so1_vote"."movie_id" = 1 AND "so1_vote"."rating" = 1 )
>>> # if mov is a mid for a movie
>>> # get movie instance by using Movie.objects.get(mid=mov)
>>> # or query:
>>> # votes = Vote.objects.filter(user__uid__in=uids, movie__mid=mov, rating=1)
>>> likes_count = votes.count()
>>> print likes_count
0
combined:
likes_count = Votes.objects.filter(user__uid__in=uids, movie=mov, rating=1).count()

Related

Django: get choices key from display value

Let's say I have the following Django model:
class Person(models.Model):
SHIRT_SIZES = (
(0, 'Small'),
(1, 'Medium'),
(2, 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.IntegerField(choices=SHIRT_SIZES)
I can create create a Person instance and get the shirt_size display value very easily:
john = Person(name="John", shirt_size=2)
john.shirt_size # 2
john.get_shirt_size_display() # 'Medium'
How can I do this the other way? That is, given a shirt size of Medium, how can I get the integer value? I there a method for that or should I write my own method on the Person object like so:
class Person(models.Model):
...
#staticmethod
def get_shirt_size_key_from_display_value(display_value):
for (key, value) in Person.SHIRT_SIZES:
if value == display_value:
return key
raise ValueError(f"No product type with display value {display_value}")
The docs recommend the following:
class Person(models.Model):
SMALL = 0
MEDIUM = 1
LARGE = 2
SHIRT_SIZES = (
(SMALL, 'Small'),
(MEDIUM, 'Medium'),
(LARGE, 'Large'),
)
name = models.CharField(max_length=60)
shirt_size = models.IntegerField(choices=SHIRT_SIZES)
Now the name MEDIUM is attached to your model and model instances:
>>> john = Person(name="John", shirt_size=2)
>>> john.shirt_size
2
>>> john.MEDIUM
2
If given a string, you can use getattr:
def get_shirt_size(instance, shirt_size):
return getattr(instance, shirt_size.upper())
choices_dict = {y: x for x, y in shirt_size.choices}
will give you a dictionary with all the ints as values and sizes as keys.
So you can write a function that returns the int of whatever shirt size you put in, or make choices_dict part of your Person object.

get value in table manytomany django

hi I am trying to get the same value in a many to many tables but I don't know how can I achieve that
here is my model:
class Raza(models.Model):
Nombre = models.CharField(max_length=50)
Origen = models.CharField(max_length=45)
Altura = models.CharField(max_length=10)
Peso = models.CharField(max_length=10)
Esperanza_vida = models.CharField(max_length=10)
Actividad_fisica = models.CharField(max_length=45)
Recomendaciones = models.CharField(max_length=500)
Clasificacion_FCI = models.ForeignKey(Clasificacion_FCI,null=True,blank=True,on_delete=models.CASCADE)
Tipo_pelo = models.ManyToManyField(Tipo_pelo,blank=True)
Caracteristicas_fisicas = models.ManyToManyField(Caracteristicas_fisicas,blank=True)
Caracter = models.ManyToManyField(Caracter,blank=True)
Ideal = models.ManyToManyField(Ideal,blank=True)
Tamanio = models.ForeignKey(Tamanio,null=True,blank=True,on_delete=models.CASCADE)
User = models.ManyToManyField(User,blank=True)
I am using the User model that's provided by Django
I have no idea how can I do that
I want do something like that
table user
id_usuario = 1
name = "Juan"
table raza
id_raza = 1
name = "pitbull"
table user_raza
id_user_raza = 1
id_user = 1
id_raza = 1
Please write class attributes with small letters in python.
to your question:
raza = Raza.objects.get(id=1)
tipo_pelos = raza.tipo_pelo.all()
for tp in tipo_pelos:
print(tp.id)
...
...
Django has wonderful documentation for this. Have fun.

how to get a related value from a ForeignKey model django admin

I've a model with a fk, but when save method I need get related value, e.g:
class Pedidos(models.Model):
ped_cliente = models.ForeignKey(Clientes, verbose_name='Cliente')
ped_remetente = models.ForeignKey(Remetentes, verbose_name='Remetente')
ped_produto = models.ForeignKey(Produtos, verbose_name='Produto')
ped_data_pedido = models.DateField(verbose_name='Data Pedido')
ped_quantidade = models.DecimalField(verbose_name='Peso/Volume', max_digits=10, decimal_places=0)
ped_key = models.IntegerField(unique=True, editable=False, verbose_name='Cod. Pedido')
class Pagamentos(models.Model):
pag_cliente = models.ForeignKey(Clientes, verbose_name='Cliente')
pag_key_ped = models.ForeignKey(Pedidos, verbose_name='Cód. Pedido')
pag_vencimento = models.DateField(verbose_name='Data Vencimento')
pag_vlr_total = models.DecimalField(verbose_name='Valor Total', max_digits=10, decimal_places=2)
I need when I save model Pagamentos the value field: pag_key_ped receive Pedidos.ped_key value
How I do to access this value?
You can access it via pag_key_ped.ped_key.
So:
>>> p = Pedidos(ped_key=1)
>>> p.save()
>>> pagamentos = Pagamentos()
>>> pagamentos.pag_key_ped = p
>>> pagamentos.save()
>>> print(pagamentos.pag_key_ped.ped_key)
[out] 1
>>> pagamentos.pag_key_ped = pagamentos.pag_key_ped.ped_key
>>> pagamentos.save()
HOWEVER!: This is a strange thing you want to do. pag_key_ped is already a ForeignKey and you want to override it with another ID. If there is no object with that ID, it will throw an DoesNotExist error.

Django queryset search on multiple models, return the same object

I'm trying to create an advanced search on my website, you are looking at various models related to each one, always returning a list of profiles that meet some parameters
Here are my Models:
class Profile(models.Model):
first_name=models.CharField(max_length=60, blank=False)
last_name=models.CharField(max_length=60, blank=False)
residence=models.CharField(max_length=60, null=True, blank=True)
birthdate=models.DateField(null=True, blank=True)
telephone=models.CharField(max_length=60, null=True, blank=True)
email=models.EmailField(null=True, blank=True)
linkedin=models.URLField(null=True, blank=True)
starred=models.BooleanField(default=False)
created_from = models.ForeignKey(EmployeeUser, related_name='profile_author')
created_on = models.DateField(default=tznow)
internal_id = models.CharField(max_length=5, blank=True)
class Education(models.Model):
almalaurea_id = models.CharField(max_length=60, null=True, blank=True)
profile = models.ForeignKey(Profile, related_name='education_profile')
education_type = models.ForeignKey(Education_type, related_name='education_type')
class Education_type(models.Model):
VALUES = (
(0, 'Altro'),
(1, 'Licenza media'),
(2, 'Diploma'),
(3, 'Laurea Triennale'),
(4, 'Laurea Magistrale'),
)
title = models.CharField(max_length=60)
value = models.IntegerField(choices=VALUES)
I want to search the profiles that meet various results, such as birthdate, residence, starred, education (based on education_type)
This is an example scenario, my research includes other models
These are the research in my view, I thought that having found the results of the two queries, I could extract the profile id and compare them, then run another query by selecting profiles that match, but I think it's not a great idea, the real scenario includes other various models.
filters_profile = []
filters_education = []
year = form.cleaned_data["year"]
residence = form.cleaned_data["residence"]
starred = form.cleaned_data["starred"]
education_type = form.cleaned_data["education_type"]
if year:
filters_profile.append(Q(birthdate__year=year))
if residence:
filters_profile.append(Q(residence__icontains=residence))
if starred:
filters_profile.append(Q(starred=starred))
result_profile = Profile.objects.filter(reduce(lambda q1, q2: q1 & q2, filters_profile)).order_by('first_name')
result_education = None
if education_type:
e = Education_type.objects.filter(title=education_type)
result_education = Education.objects.filter(education_type=e).prefetch_related('profile','education_type')
Any idea?
Many thanks in advance :)
EDIT :
About the solution of #Geo Jacob
Here is the third models:
if valutation:
result_valutation = Status.objects.filter(valutation=valutation).values_list('profile_id', flat=True)
key['id__in'] = result_valutation
Adding this code for my scenario, this solution don't work, as i written in the comments :)
"in practice, the content of key['id__in'] is overwritten when the other model query (this) is executed"
Try this:
key = {}
year = form.cleaned_data["year"]
residence = form.cleaned_data["residence"]
starred = form.cleaned_data["starred"]
education_type = form.cleaned_data["education_type"]
if year:
key['birthdate__year'] = year
if residence:
key['residence__icontains'] = residence
if starred:
key['starred'] = starred
if education_type:
e = Education_type.objects.filter(title=education_type)
result_education = Education.objects.filter(education_type=e).values_list('profile_id', flat=True)
key['id__in'] = result_education
result_profile = Profile.objects.filter(**key).order_by('first_name')
My solution working on more than 2 models, based on #Geo Jacob solution, thank you
I make a check and put in key['id__in'] only matched id from the previous query, so as to intersect the results
key = {}
statokey = 0
year = form.cleaned_data["year"]
residence = form.cleaned_data["residence"]
starred = form.cleaned_data["starred"]
education_type = form.cleaned_data["education_type"]
valutation = form.cleaned_data["valutation"]
if year:
key['birthdate__year'] = year
if residence:
key['residence__icontains'] = residence
if starred:
key['starred'] = starred
if education_type:
e = Education_type.objects.filter(title=education_type)
result_education = Education.objects.filter(education_type=e).values_list('profile_id', flat=True)
if statokey > 0:
for r in result_education:
for k in key['id__in']:
if r == k:
key['id__in'] = str(r)
else:
key['id__in'] = result_education
statokey += 1
if valutation:
result_valutation = Status.objects.filter(valutation=valutation).values_list('profile_id', flat=True)
if statokey > 0:
for r in result_valutation:
for k in key['id__in']:
if r == k:
key['id__in'] = str(r)
else:
key['id__in'] = result_valutation
statokey += 1
result_profile = Profile.objects.filter(**key).order_by('first_name')

Django ORM equivalent for this SQL..calculated field derived from related table

I have the following model structure below:
class Master(models.Model):
name = models.CharField(max_length=50)
mounting_height = models.DecimalField(max_digits=10,decimal_places=2)
class MLog(models.Model):
date = models.DateField(db_index=True)
time = models.TimeField(db_index=True)
sensor_reading = models.IntegerField()
m_master = models.ForeignKey(Master)
The goal is to produce a queryset that returns all the fields from MLog plus a calculated field (item_height) based on the related data in Master
using Django's raw sql:
querySet = MLog.objects.raw('''
SELECT a.id,
date,
time,
sensor_reading,
mounting_height,
(sensor_reading - mounting_height) as item_height
FROM db_mlog a JOIN db_master b
ON a.m_master_id = b.id
''')
How do I code this using Django's ORM?
I can think of two ways to go about this without relying on raw(). The first is pretty much the same as what #tylerl suggested. Something like this:
class Master(models.Model):
name = models.CharField(max_length=50)
mounting_height = models.DecimalField(max_digits=10,decimal_places=2)
class MLog(models.Model):
date = models.DateField(db_index=True)
time = models.TimeField(db_index=True)
sensor_reading = models.IntegerField()
m_master = models.ForeignKey(Master)
def _get_item_height(self):
return self.sensor_reading - self.m_master.mounting_height
item_height = property(_get_item_height)
In this case I am defining a custom (derived) property for MLog called item_height. This property is calculated as the difference of the sensor_reading of an instance and the mounting_height of its related master instance. More on property here.
You can then do something like this:
In [4]: q = MLog.objects.all()
In [5]: q[0]
Out[5]: <MLog: 2010-09-11 8>
In [6]: q[0].item_height
Out[6]: Decimal('-2.00')
The second way to do this is to use the extra() method and have the database do the calculation for you.
In [14]: q = MLog.objects.select_related().extra(select =
{'item_height': 'sensor_reading - mounting_height'})
In [16]: q[0]
Out[16]: <MLog: 2010-09-11 8>
In [17]: q[0].item_height
Out[17]: Decimal('-2.00')
You'll note the use of select_related(). Without this the Master table will not be joined with the query and you will get an error.
I always do the calculations in the app rather than in the DB.
class Thing(models.Model):
foo = models.IntegerField()
bar = models.IntegerField()
#Property
def diff():
def fget(self):
return self.foo - self.bar
def fset(self,value):
self.bar = self.foo - value
Then you can manipulate it just as you would any other field, and it does whatever you defined with the underlying data. For example:
obj = Thing.objects.all()[0]
print(obj.diff) # prints .foo - .bar
obj.diff = 4 # sets .bar to .foo - 4
Property, by the way, is just a standard property decorator, in this case coded as follows (I don't remember where it came from):
def Property(function):
keys = 'fget', 'fset', 'fdel'
func_locals = {'doc':function.__doc__}
def probeFunc(frame, event, arg):
if event == 'return':
locals = frame.f_locals
func_locals.update(dict((k,locals.get(k)) for k in keys))
sys.settrace(None)
return probeFunc
sys.settrace(probeFunc)
function()
return property(**func_locals)