How to Use annotate function to in django for below condition? - django

class Surface(models.Model):
name = models.CharField(max_length=100)
surface_class = models.ManyToManyField(SurfaceClass, default=None)
class SurfaceGeometry(models.Model):
surface = models.ForeignKey(Surface, on_delete=models.DO_NOTHING)
geometry_parameter = models.ForeignKey(SurfaceGeometryParameters, on_delete=models.CASCADE)
value = models.FloatField()
class SurfaceGeometryParameters(models.Model):
name = models.CharField(max_length=30, unique=True)
Surface.objects.prefetch_related('surface_class',Prefetch('surfacecorrelationcontroller_set'),Prefetch('surfacegeometry_set')).annotate(height=?).order_by('surface_class__name','-height')
I want to take height(value) from SurfaceGeomentry model where Height is name of geometry parameter from SurfaceGeometryParameters models for Surface.
I can get a height from SurfaceGeometry like this.
SurfaceGeometry.objects.get(surface__id = 1, geometry_parameter__name__iexact= 'Height')
where surfcace__id's value 1 should come from parent query.
How I can achieve the this?

Final Answer of this question after too many attempt is
surface_height_query = SurfaceGeometry.objects.filter(surface=OuterRef('pk'),geometry_parameter__name__iexact='Height') \
.values_list('value', flat=True)
return Surface.objects.annotate(height=Subquery(surface_height_query)).order_by('surface_class__name','height')
Django Documentation for the same

Related

Create object in model having foreigkey relation

I want to create an entry in this Something model in python manage.py shell using this
Someting.objects.create(discussion_title="General", user_username="admin", content="Hello")
models example
class Discussion(models.Model):
title = models.CharField(max_length=255, unique=True, blank=False,)
users = models.ManyToManyField(User, blank=True, )
class Something(models.Model):
user = models.ForeignKey(User,
on_delete=models.CASCADE)
discussion = models.ForeignKey(Discussion, on_delete=models.CASCADE)
timestamp = models.DateTimeField(auto_now_add=True)
content = models.TextField(unique=False, blank=False)
I am getting this error
TypeError: Something() got an unexpected keyword argument 'discussion_title'
First, you have to use double under bar __ to use django's model relation expression.
Someting.objects.get(discussion__title="General", user__username="admin", content="Hello")
Second, you can't use double under bar relation expression when create an object.
if you want to create an object in relation, you have to create in step by step. follow #Nicolas Appriou 's answer
Your Something model does not have a discussion_title field. You need to create a Discussion instance for this.
This model does not have a user_username model either.
discussion = Discussion.objects.create(title="Foobar")
discussion.users.add(User.objects.create(username="Ham")
Something.objects.create(
discussion=discussion,
)

Django query based on another query results

I have 4 models in my simplified design
class modelA(models.Model):
name = models.CharField()
class modelsUser(model.Model):
username = models.CharField()
class bridge(models.Model):
user = models.ForeignKey(modelUser, on_delete=models.CASCADE, related_name='bridges')
modelA = models.ForeignKey(modelA, on_delete=models.CASCADE, related_name='bridges')
class subModelA(models.Model):
modelA = models.ForeignKey(modelA, on_delete=models.CASCADE, related_name='subModelAs')
value = models.IntegerField()
class subModelB(models.Model):
modelA = models.ForeignKey(modelA, on_delete=models.CASCADE, related_name='subModelBs')
text = models.TextField()
What I am trying to to is to get all subModelBs and subModelAs that are for modelAs for which given modelUser have bridge.
I've started with this:
user = modelUser.objects.get(pk=1)
bridges = user.bridges.all()
What I've been thinking is something like this:
subModelBs = subModelB.objects.filter(modelA__in=bridges__modelA)
but unfortunately it doesn't work because of error that __modelA is not defined.
Is there any proper way to do this?
Find first the modelAs and then do two other queries:
modelAs = bridge.objects.filter(user__pk=1).values_list('modelA', flat=True)
subModelAs = subModelA.object.filter(modelA__in=modelAs)
subModelBs = subModelB.object.filter(modelA__in=modelAs)
A good question first of all!
Tried reproducing on my system, the following worked for me:
user = modelUser.objects.get(pk=1)
bridges = user.bridges.all()
subModelAs = subModelA.objects.filter(
modelA_id__in=[x.modelA_id for x in list(bridges)]
)
And similarly for subModelBs. Hope this helps you well.

Is there any possible solution for getting more than one value inside function in django?

I am creating a blog application using Django and I am also very much new to django.
This is the models I created
class categories(models.Model):
Title = models.CharField(max_length=40, default='GST')
class Blog(models.Model):
User = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE,null=True,blank=True)
Date = models.DateTimeField(default=datetime.now)
Blog_title = models.CharField(max_length=255)
likes = models.ManyToManyField(settings.AUTH_USER_MODEL,related_name='likes',blank=True)
Description = RichTextUploadingField(blank=True, null=True,config_name='special')
Blog_image = models.ImageField(upload_to='blog_image', null=True, blank=True)
Category = models.ForeignKey(categories,on_delete=models.CASCADE,related_name='blogs')
I was wondering How to count the total no of blog present under a particular category?
I want to track a specific count rate for all Categories...
Done something like this in my model
def categories_count(self):
for a in categories.objects.all():
categories_count = Blog.objects.filter(Category__Title=a.Title).count()
return categories_count
But it is returning only one value...Can anyone suggest me with some suitable codes to resolve this...
Thank you
You can get a list of tuples of category title and blog count with the following query:
categories.objects.annotate(blog_count=Count('Categories')).values_list('Title', 'blog_count')

Overcoming 'choices' must be an iterable containing (actual value, human readable name) tuples without Foreign Key?

I'm hoping this has been done before - essentially, and hopefully I explain this correctly, what I'd like is a model with some choices (as below).
I want to circumnavigate the 'choices' must be an iterable containing (actual value, human readable name) tuples error when adding a third or fourth value to the choice tuple for a model.
Those choices not only effect directly the field for which you're selecting from, but also another few fields. I've seen things where the slug field is auto populated from e.g., a blog post title, but does any method exist for tying multiple fields to a certain choice?
class Location(models.Model):
SERVICE_CHOICES = (
('bus_station', 'Bus Station', '#cdcdcd'),
('cafe', 'Café', '#cdcdcd'),
('cinema', 'Cinema', '#cdcdcd'),
('gardens', 'Public Gardens', '#cdcdcd'),
('library', 'Library'),
('public_services', 'Public Services'),
('railway_station', 'Railway Station'),
('restaurant', 'Restaurant'),
('school', 'School'),
('shop', 'Shop'),
('supermarket', 'Supermarket'),
('tourist_attractions', 'Tourist Attractions'),
('transit_station', 'Transit Station'),
('walks', 'Walks'),
('woodland', 'Woodland'),
)
locale_descriptor = models.CharField("Locale Descriptor", max_length=50, default='')
latitude = models.DecimalField("Latitude", max_digits=10, decimal_places=7)
longitude = models.DecimalField("Longitude", max_digits=10, decimal_places=7)
title = models.CharField("Title", max_length=60, default='')
description = models.TextField("Description")
service_type = models.CharField("Service Type", max_length=80,choices=SERVICE_CHOICES, default='public_service')
Would anyone know how to auto populate a field dependent on these choices??
I'm not getting a perfectly clear picture of what you're trying to do, but it sounds like what you need is a ForeignKey relationship instead of trying to augment the choices tuple. Something like this:
class ServiceType(models.Model):
def __unicode__(self):
return self.service_name
service_name = modes.CharField(max_length=80)
color = modes.CharField(max_length=7)
class Location(models.Model):
locale_descriptor = models.CharField("Locale Descriptor", max_length=50, default='')
latitude = models.DecimalField("Latitude", max_digits=10, decimal_places=7)
longitude = models.DecimalField("Longitude", max_digits=10, decimal_places=7)
title = models.CharField("Title", max_length=60, default='')
description = models.TextField("Description")
service_type = models.ForeignKey(ServiceType)
Not sure how you want to affect the other fields, but this can be done by overwriting the save() method or implementing a clean() method. One example: "Django. Override save for model".

Django substract two fields from related model

With this models:
class Vine(models.Model):
autor = models.ForeignKey(Viner,related_name='autor')
titulo = models.CharField(max_length=450)
estado = models.CharField(choices=ESTADOS_VINE, max_length=30)
objects = models.Manager()
custom_object = managers.VineManager()
and the model for the votes
class Voto(models.Model):
user = models.ForeignKey(MyUser)
submit_date = models.DateTimeField(auto_now_add=True)
vine = models.ForeignKey(Vine)
valoracion = models.BooleanField(default=False)
and the class for the Favorites (This is working fine yet)
class Favorito(models.Model):
date = models.DateTimeField(auto_now_add=True)
user = models.ForeignKey(settings.AUTH_USER_MODEL, related_name='favoritos')
I have this 'query' in Django.
vines = Vine.custom_object.filter(estado=2).\
annotate(favoritosCount=Count('favoritos', distinct=True)).\
filter(voto__valoracion=False).annotate(disLikesCount=Count('voto', distinct=True))\
.annotate(likesCount=Count('voto', distinct=True)).filter(voto__valoracion=True)
But the second filter is not working because of the first.
Basically what I want is to get the sum of 'positive votes' - 'negative votes' as a field and order by it.
Could anyone please help me?
Thank you in advance
AFAIK you can't do that query with the ORM. You might be able to do it with a raw query.
I think It's easier if you add a count field to your Vine model and order by it. Then update that count field every time there's a new Voto.
Something like this:
from django.db.models import F
class Vine(models.Model):
...
votos = models.IntegerField()
class Meta:
ordering = ('votos',)
class Voto(models.Model):
...
def save(self):
"""When saving new Voto instance, update related Vine."""
if not self.pk:
new_vote = 1 if self.valoracion else -1
self.vine.update(votos=F('votos') + new_vote)
return super(Voto, self).save()
PS: If you want to know more about that F expression.