How to convert SQL query to Django query - python

Django model
class Imones(models.Model): # Clients
id = models.AutoField(primary_key=True)
pavadinimas = models.CharField(unique=True, max_length=45) # name
class Priekabos(models.Model): # Products
id = models.AutoField(primary_key=True)
sutarties_nr = models.CharField(unique=True, max_length=45) # contract_number
vin = models.CharField(unique=True, max_length=45, verbose_name='VIN') # vehicle_identification_number
imones = models.ForeignKey(Imones, models.DO_NOTHING, verbose_name='Įmonė') # client_id
class Saskaitos(models.Model): # Invoices
id = models.AutoField(primary_key=True)
apmoketa = models.BooleanField(default=0) # Paid in full
imones = models.ForeignKey(Imones, models.DO_NOTHING) # client_id
MySQL query:
SELECT distinct sutarties_nr, vin, apmoketa
FROM priekabos pr
LEFT OUTER JOIN saskaitos sa
ON pr.imones_id = sa.imones_id
WHERE apmoketa=0 or apmoketa is null
Could someone explain how to translate MySQL query to Django query? I've tried:
obj = Saskaitos.objects.filter(apmoketa=0)
queryset = Priekabos.objects.filter(imones__in=obj.values('imones')).values()
But it doesn't return all values as expected. One more question - how to make Imones.pavadinimas appear in queryset results instead of plain id? Now it looks like that

Related

How can I do a on_conflict_replace work in Django batch_create operation?

The field account and month are unique togather. And I'm tring to batch_insert db data by bulk_create with Django to speed up my db operation.
My db backend is mysql with innodb
below is my base table
# my db table
class MSpendForMonth(models.Model):
created_time = models.DateTimeField(auto_now_add=True)
updated_time = models.DateTimeField(auto_now=True)
system_value = models.DecimalField(max_digits=16, decimal_places=2)
checked_value = models.DecimalField(max_digits=16, decimal_places=2, null=True)
account = models.ForeignKey(MAccount,
models.DO_NOTHING,
related_query_name="account_month",
related_name="account_month"
)
month = models.IntegerField(blank=True, null=True)
class Meta:
db_table = 'spend_for_month'
unique_together = (('account', 'month'),)
# db operation
bulk_data = []
try:
with transaction.atomic():
for spend_data in spend_month_date_sum_queryset:
bulk_data.append(
MSpendForMonth(
account_id=spend_data["account_id"],
month=month,
system_value=spend_data["sum_value"],
)
)
MSpendForMonth.objects.bulk_create(bulk_data, ignore_conflicts=True )
# MSpendForMonth.objects.bulk_update(bulk_data, fields="system_value")
except:
import traceback as tb
tb.print_exc()
And I want to replace system_value with a new value as it sometimes changed.
My question is how can I bulk_create data and replace with new value of system_value if there is a conflict on unique key account-month.
It should be something like insert_many().on_conflict_replace() -- peewee
Great thanks.

django 1.11.x -> 2.x migration. I got the incorrect 'group by' fields

I just upgraded the Django version. The model or code has not been modified in my app.
But... I get different results QuerySet.
Fields specified in 'Group by' are different when printing a 'query'.
Model:
class Content(models.Model):
id_field = models.AutoField(db_column='id_', primary_key=True)
...
collections = models.ManyToManyField('Collection',
through='CollectionMap',
through_fields=('contentid', 'collectionid'))
class CollectionMap(models.Model):
field_index = models.AutoField(db_column='_index', primary_key=True)
collectionid = models.ForeignKey(Collection, on_delete=models.CASCADE, db_column='collectionid')
contentid = models.ForeignKey(Content, on_delete=models.CASCADE, db_column='contentid')
field_time = models.DateTimeField(db_column='_time')
class Collection(models.Model):
field_index = models.AutoField(db_column='_index', primary_key=True)
name = models.CharField(unique=True, max_length=50)
collectionorder = models.IntegerField(db_column='collectionOrder', blank=True, null=True)
active = models.IntegerField(blank=True, null=True)
field_time = models.DateTimeField(db_column='_time')
Code:
Content.objects\
.annotate(count=Count('id_field')\
.values('id_field', 'collections__name')
Query:
1.11.X
SELECT
Content.id_, Collection. name
FROM Content
LEFT OUTER JOIN Collection_Map ON (Content.id_ = Collection_Map.contentid)
LEFT OUTER JOIN Collection ON (Collection_Map.collectionid = Collection._index)
GROUP BY Content.id_
ORDER BY Content.itemOrder DESC
LIMIT 50;
2.X
SELECT
Content.id_, Collection. name
FROM Content
LEFT OUTER JOIN Collection_Map ON (Content.id_ = Collection_Map.contentid)
LEFT OUTER JOIN Collection ON (Collection_Map.collectionid = Collection._index)
GROUP BY Content.id_, Collection. name
ORDER BY Content.itemOrder DESC
LIMIT 50;
Group By fields:
Version 1.11.X : GROUP BY Content.id
Version 2.X : GROUP BY Content.id, Collection.Name
I want this... '... GROUP BY Content.id ...'
What should I do??

Django - filtering out already rated restaurants in yelp like app

Consider the following database model:
class User:
id = models.BigAutoField(primary_key=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
class Restaurant:
id = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=50)
class Rating:
id = models.BigAutoField(primary_key=True)
by_user = models.ForeignKey(to='User',
on_delete=models.PROTECT,
related_name='written_ratings')
for_restaurant = models.ForeignKey(to='Restaurant',
on_delete=models.PROTECT,
related_name='received_ratings')
score = models.SmallIntegerField()
# make sure only one vote per user per restaurant
class Meta:
unique_together = ('by_user', 'for_restaurant')
For a given User, we can obtain a list of Restaurant that we have not yet rated by performing the following query (that I have learned from my last post)
eligible_restaurants = Restaurant.objects.exclude(rating__by_user_id=my_id)
But what happens when the Ratings don't point directly at the Restaurants - but rather at an intermediate Profile object?
class User:
id = models.BigAutoField(primary_key=True)
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
class Restaurant:
id = models.BigAutoField(primary_key=True)
title = models.CharField(max_length=50)
current_profile = models.OneToOneField(to='Profile',
on_delete=models.PROTECT,
related_name='+')
# the `+` means to not generate a related name
class Profile:
# this is here acting as an intermediate between
# `Restaurant` and `Rating` so that we can keep track
# of all reviews - deleting/remaking would simply be
# creating a new `Profile` and setting the `Restaurant`
# to point to it instead - the old one will act as a
# historical record
id = models.BigAutoField(primary_key=True)
by_restaurant = models.ForeignKey(to='Restaurant',
on_delete=models.PROTECT,
related_name='written_profiles')
picture_url = models.CharField(max_length=500)
picture_desc = models.CharField(max_length=500)
class Rating:
id = models.BigAutoField(primary_key=True)
by_user = models.ForeignKey(to='User',
on_delete=models.PROTECT,
related_name='written_ratings')
for_profile = models.ForeignKey(to='Profile',
on_delete=models.PROTECT,
related_name='received_ratings')
score = models.SmallIntegerField()
# make sure only one vote per user per restaurant
class Meta:
unique_together = ('by_user', 'for_profile')
How would I query for eligible restaurants now?
You could filter them starting with restaurants
restaurant_ids = Rating.objects.filter(by_user=user).values_list('for_profile__by_restaurant', flat=True).distinct()
eligible_restaurants = Restaurant.objects.exclude(id__in=restaurant_ids)
Note: this will generate only one query because django's querysets are lazy.

how to select columns from multiple models in django?

models.py
class Custom_user_model(User):
daily_target = models.IntegerField()
monthly_target = models.IntegerField()
yearly_target = models.IntegerField()
weekly_target = models.IntegerField()
call_target = models.IntegerField()
email_target = models.IntegerField()
meeting_target = models.IntegerField()
added_under = models.IntegerField()
profile_pic = models.TextField()
doj = models.DateTimeField(default='')
location_id = models.IntegerField()
locked = models.BooleanField()
default_currency = models.IntegerField()
date_change_permission = models.BooleanField()
deal_back_log = models.BooleanField()
created_date=models.DateTimeField(auto_now_add=True)
role_id=models.ForeignKey('user_Roles')
profile_pic = models.FileField(upload_to='.')
objects = UserManager()
class Deal(models.Model):
a_choices = ((0,'yes'),(1,'no'))
approved = models.IntegerField(choices=a_choices,default=1)
user_id = models.ForeignKey('Custom_user_model')
company_id = models.IntegerField()
contact_id = models.IntegerField()
deal_title=models.CharField(max_length=200)
deal_value = models.CharField(max_length=20)
currency_id = models.IntegerField()
process_id = models.IntegerField()
expected_close_date = models.DateField(default='')
closed_date = models.DateField()
deal_milestone=models.IntegerField()
created=models.DateTimeField(auto_now_add=True)
last_modified=models.DateTimeField(auto_now_add=True)
s_choices = ((0,'active'),(1,'won'),(2,'junk'),(3,'lost'))
status = models.IntegerField(choices=a_choices,default=0)
type = models.CharField(max_length=50, default='deal')
class user_Roles(models.Model):
code = models.CharField(max_length=20)
description = models.CharField(max_length=30)
permitted_menus = models.CharField(max_length=200)
created = models.DateTimeField(auto_now_add=True)
views.py
Here, i wrote the code to get columns from three models. But
Deal.objects.filter(user_id__role_id_id=1).select_related() returned nothing and Deal.objects.filter(user_id__role_id_id=1).select_related().values() returned the fields from deal model only. It shows 'no fields error', when specifying relationship as values('Custom_user_model__doj').How can i select fields from multiple models?
def get_all_normal_users(request,start_date=None,end_date=None):
query = Deal.objects.filter(user_id__role_id_id=1).select_related().values()
start_date_range = (
# The start_date with the minimum possible time
datetime.datetime.combine(start_date, datetime.time.min),
# The start_date with the maximum possible time
datetime.datetime.combine(end_date, datetime.time.max)
)
query = query.filter(created__range=start_date_range).values()
data_dict = ValuesQuerySetToDict(query)
data_json = json.dumps(data_dict)
return json_response({'status':data_json})
If you want to select related values you have to specify all parameters you want in values(). Otherwise you will get only the foreignkey to your user model. Try adding the values you want from your user model with __:
query = query.filter(created__range=start_date_range).values('approved', ..., 'user_id__daily_target', 'user_id__username')
Btw if you are creating an API you should have a look at django-rest-framework
try this,
Deal.objects.filter(user_id__role_id_id=1, created__range=start_date_range).select_related('user_id').values()
or specify required fields as parameters to values().

Convert SQL QUERY to django QUERY

I am trying to convert sql query to django query but failed to do this, can anyone help me
select id,name,round(value::numeric,2) as value, st_transform(geometry, 3857) as geometry
from net_rest
where state_id in (1,2) and name = 'height'
union
(select d.id,d.restriction,d.value, st_transform(d.geometry, 3857) as geometry from display_rest d
where d.restriction='height' and condition_id not in (select condition_id
from net_rest_conditions where version_id = 2)
OR This
select id,name,value as value, geometry
from net_rest
where state_id in (1,2) and name = 'height'
union
(select d.id,d.restriction,d.value,geometry from display_rest d
where d.restriction='height' and condition_id not in (select condition_id
from net_rest_conditions where version_id = 2)
Updated the question fro here
I am using django django rest framework serialize net_rest Model, basically i am working on project related to GIS where i have to make rest api to expose data
Here is some of my models
class net_rest(models.Model):
name = models.CharField(max_length=50, blank=True)
value = models.FloatField()
state_id = models.IntegerField(null=True, blank=True)
geometry = models.GeometryField(null=True, blank=True)
objects = models.GeoManager()
class Meta:
db_table = u'tbl_net_rest'
def __unicode__(self):
return '%s' % self.name
class display_rest(models.Model):
restriction = models.CharField(max_length=45, blank=True)
link_id = models.IntegerField(blank=True, null=True)
condition_id = models.IntegerField(blank=True, null=True)
value = models.FloatField(blank=True, null=True)
geometry = models.GeometryField(blank=True, null=True)
class Meta:
db_table = u'tbl_display_rest'
class net_rest_conditions(models.Model):
condition_id = models.IntegerField()
version_id = models.IntegerField(blank=True, null=True)
class Meta:
db_table = u'tbl_net_rest_conditions'
class networkSerializer(serializers.GeoModelSerializer):
class Meta:
model = net_rest
fields = ('id', 'name', 'value', 'geometry')
Here is view
class networkSerializerViewSet(viewsets.ModelViewSet):
q1 = display_rest.objects.values_list('id', 'name', 'value', 'geometry').filter(restriction='height')\
.exclude(condition_id__in=net_rest_conditions.objects.filter(version_id=2).values_list('condition_id',flat=True))
q2 = net_rest.objects.all().filter(Q(name="height"), Q(state_id=1) | Q(state_id=2)).values_list('id', 'value', 'geometry')
queryset = q1 | q2
serializer_class = networkSerializer
More complex queries are not possible in django , You can use raw queries instead.
<OBJECT>.objects.raw('sql statement goes here')

Categories

Resources