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')
Related
I want to be able to do queries involving multiple inner joins using Django ORM, here's my model (showing only relevant fields)
class Students(models.Model):
class Status(models.IntegerChoices):
preRegistered = 0 #No ha aceptado terminos y condiciones
Enabled = 1
Disabled = 2
Suspended = 3
Test = 4
id = models.AutoField(primary_key=True)
user = models.ForeignKey(Users, on_delete=models.CASCADE)
trainingPath = models.ForeignKey(trainingPaths, on_delete=models.CASCADE)
status = models.IntegerField(choices=Status.choices, default=0)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
class Meta():
db_table = 'Students'
class trainingPaths(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=70, blank=False, null=False)
shortName = models.CharField(max_length=10, blank=True)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
class Meta():
db_table = 'Training_Path'
class Courses(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=70, blank=False, null=False)
path = models.URLField(max_length=500, blank=True, null=True)
shortName = models.CharField(max_length=6, blank=True)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
course_image = models.URLField(max_length=200, blank=True)
class Meta():
db_table = 'Courses'
class CoursesXTrainingP(models.Model):
id = models.AutoField(primary_key=True)
trainingPath = models.ForeignKey(trainingPaths, on_delete=models.CASCADE)
course = models.ForeignKey(Courses, on_delete=models.CASCADE)
alternativeName = models.CharField(max_length=70, blank=True)
order = models.PositiveIntegerField(blank=False)
creationDate = models.DateTimeField(auto_now_add=True)
modificationDate = models.DateTimeField(auto_now=True)
class Meta():
db_table = 'Courses_X_Training_Paths'
I want to get the information of the courses that a student has according to the value of the "trainingPath".
this is my SQL query
select
courses.id, courses.`name`, courses.course_image
from
students
join
courses_x_training_paths
on
students.trainingPath_id = courses_x_training_paths.trainingPath_id
join
courses
on
courses_x_training_paths.course_id = courses.id
where
students.trainingPath_id=1;
I have tried several ways and none of them have worked, could you please help me?
You can filter with:
Courses.objects.filter(
coursesxtrainingp__trainingPath_id=1
)
The join on the Students model is not necessary, since we already know that the trainingPath_id is one by filtering on the CoursesXTrainingP model.
Note: normally a Django model is given a singular name, so Student instead of Students.
Note: normally the name of the fields in a Django model are written in snake_case, not PascalCase, so it should be: modification_date instead of modificationDate.
I have following models, with many to many table, for which I would like to get first 20 news from every category in single response.
class Category(models.Model):
code = models.CharField(primary_key=True, max_length=45)
name = models.CharField(max_length=200, blank=True, null=True)
is_active = models.TextField(blank=True, null=True) # This field type is a guess.
class Meta:
managed = False
db_table = 'category'
verbose_name_plural = 'Categories'
class News(models.Model):
source_code = models.CharField(max_length=45, blank=True, null=True)
title = models.CharField(max_length=1000, blank=True, null=True)
image = models.CharField(max_length=2000, blank=True, null=True)
link = models.CharField(max_length=1000, blank=True, null=True)
published_at = models.DateTimeField(blank=True, null=True)
scraped_at = models.DateTimeField(blank=True, null=True)
is_active = models.TextField(blank=True, null=True) # This field type is a guess.
categories = models.ManyToManyField('Category', through='NewsCategory')
class Meta:
managed = False
db_table = 'news'
verbose_name_plural = 'News'
class NewsCategory(models.Model):
news_id = models.ForeignKey(News, db_column='news_id', on_delete=models.CASCADE)
category_code = models.ForeignKey(Category, db_column='category_code', on_delete=models.CASCADE)
class Meta:
managed = False
db_table = 'news_category'
unique_together = (('news_id', 'category_code'),)
verbose_name_plural = 'NewsCategory'
My view class looks like this, and here I would like to add some logic to return 20 rows for each category, for example if I have 5 categories it should return 100 news in single request.
class NewsViewSet(viewsets.ModelViewSet):
http_method_names = ['get']
serializer_class = NewsSerializer
def get_queryset(self):
queryset = News.objects.all().order_by('-published_at')
sources = self.request.query_params.getlist('sources')
if len(sources) > 0:
queryset = queryset.filter(source_code__in=sources)
return queryset
The typical way to do this is to use a window function. Django has support for them but I don't think they allow filtering on the output of them. I think this is further complicated by the m2m field. Given it's not too complex and doesn't seem to involve user input, you might just want to use a raw query.
Here's what it might look like:
SELECT *
FROM (
SELECT
*,
ROW_NUMBER() OVER (PARTITION BY c.code ORDER BY n.published_at DESC) AS row_num
FROM appname_news n
JOIN appname_newscategory nc
ON n.id = c.news_id
JOIN appname_category c
ON nc.category_code = c.code
) sub
WHERE
row_num <= 20
And see here for Django's guide on how to actually implement this in a view:
https://docs.djangoproject.com/en/3.2/topics/db/sql/#executing-custom-sql-directly
The query to be implemented with ORM is as follows,
SELECT t2.*
FROM sub_menu AS t1
INNER JOIN sub_menu AS t2 ON (t1.sub_menu_id = t2.parent_sub_menu_id)
WHERE t1.sub_menu_id = 1;
The model is as follows,
class SubMenu(models.Model):
sub_menu_id = models.AutoField(primary_key=True)
menu = models.ForeignKey('commons.MainMenu', related_name='sub_menus', on_delete=models.CASCADE)
parent_sub_menu_id = models.IntegerField(blank=True, null=True)
name = models.CharField(max_length=50)
en_name = models.CharField(max_length=50, blank=True)
ord = models.IntegerField()
api = models.CharField(max_length=255, blank=True)
api_method = models.CharField(max_length=7, blank=True)
api_detail = models.CharField(max_length=255, blank=True)
menu_type_cd = models.CharField(max_length=5, blank=True)
menu_auth_type_cd = models.CharField(max_length=5)
is_common = models.BooleanField(default=False)
is_ns = models.BooleanField(default=False)
spc_auth = models.BooleanField(default=False)
spc_auth_cd = models.CharField(max_length=5, blank=True)
create_dt = models.DateTimeField(auto_now_add=True)
update_dt = models.DateTimeField(auto_now=True)
class Meta:
db_table = 'sub_menu'
unique_together = ('api', 'api_method',)
Not using a raw method, Is it possible to implement with Django's ORM?
Thank you.
You should do the relationship correctly on your model: https://docs.djangoproject.com/en/3.0/ref/models/fields/#module-django.db.models.fields.related. Then the parent_sub_menu should be:
class Submenu:
parent_sub_menu = models.ForeignKey('self', null=True, blank=True, on_delete=models.CASCADE)
Then run generate & DB migration. The query below should work.
And never declare relationship like you are doing right now, use Model instead via the documentation I sent.
Django does it for you already. You can just filter the related field.
https://docs.djangoproject.com/en/3.0/topics/db/queries/#lookups-that-span-relationships
SubMenu.objects.filter(parent_sub_menu__sub_menu_id=1)
I'm using the django_tables2 to show a list of "repair details". So far so good. However I want to add a new field (it's not in the model): a list of service reports. The relation is 1 to many. and show the serial number which is in another model. It's quite difficult since I add the field but the render_NEW_FIELD doesn't work and i couldn't reach the list of service reports since in the table model I have just access to the record and not to the repair_detail model. I'm using django_tables 0.15
repair/models.py
class RepairDetail(models.Model):
repair = models.ForeignKey('Repair')
repair_detail_number = models.IntegerField()
article_code = models.CharField(max_length=30)
registered_date = models.DateField(null=True)
registered_uid = models.IntegerField(null=True)
registered_initials = models.CharField(max_length=2, null=True)
customer_reference = models.CharField(max_length=20, null=True)
db2_recnum = models.IntegerField()
def __unicode__(self):
return str(self.repair_detail_number)
class ServiceReport(models.Model):
repair_detail = models.ForeignKey('RepairDetail')
status = models.ForeignKey('ServiceReportStatus', on_delete=models.PROTECT)
serial_number = models.ForeignKey('core.SerialNumber')
customer = models.ForeignKey('core.Company')
contact = models.ForeignKey('core.Contact', null=True, on_delete=models.SET_NULL)
project = models.ForeignKey('core.Project')
project_code = models.CharField(max_length=4)
identifier = models.CharField(max_length=1)
repair_date = models.DateField(null=True)
repair_uid = models.IntegerField(null=True)
repair_initials = models.CharField(max_length=2, null=True)
booking_date = models.DateField(null=True)
core/models.py
class SerialNumber(models.Model):
product = models.ForeignKey("Product")
panel = models.ForeignKey("Panel", null=True, blank=True, default = None)
serial_number = models.CharField(max_length=30, default='')
manifest = models.TextField(null=True)
def __unicode__(self):
return self.serial_number
repair/tables.py
class RepairDetailTable(tables.Table):
#serials = tables.Column(accessor='servicereport.serialnumber.serialnumber')
serial = tables.Column()
def __init__(self, *args, **kwargs):
super(RepairDetailTable, self).__init__(*args, **kwargs)
class Meta(object):
model = RepairDetail
fields = ('id', 'repair_detail_number', 'article_code', 'registered_date', 'registered_initials', 'customer_reference', 'serials')
attrs = {'class': 'table table-striped table-bordered protonic'}
empty_text = "No records found."
If you want (1:N instead of N:1) to concatenate all related models in the table cell try to do this in your model layer by setting property, something like this:
class RepairDetail(models.Model):
# ...
#property
def service_reports_list(self):
return self.servicereport_set.all()
Define your own column (inherit tables.Column) and override render method
Add it to your table class:
class RepairDetailTable(tables.Table):
# ...
service_reports_list = YourOwnColumn(some_kwargs)
# ...
Im new to django. I have this model, In tblperson, only the forgein keys of type and status are saved. How do I join all tables to display their value not their forgein key? For example.
TblPerson.objects.raw('SELECT * FROM "Tblperson" INNER JOIN "Tblstatus" ON ("TblPerson"."Status" = "Tblstatus"."ID")'):
Thanks.
class TblPerson(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'ID')
Type = models.IntegerField(null=True, db_column=u'Type', blank=True)
Status = models.IntegerField(null=True, db_column=u'Status', blank=True)
class Meta:
db_table = u'tblPerson'
class Tblstatus(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'statStatusID')
Status = models.CharField(max_length=25, db_column=u'statStatus', blank=True)
class Meta:
db_table = u'tblStatus'
class Tbltype(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'typTypeID')
Type = models.CharField(max_length=25, db_column=u'typType', blank=True)
class Meta:
db_table = u'tblType'
The power of Django is in the ORM, which means you should be writing very little SQL if at all.
class Person(models.Model):
#don't use this because id is generated automatically
#ID = models.AutoField(primary_key=True, db_column=u'ID')
type = models.ForeignKey(Type)
status = models.ForeignKey(Status)
#Type,Status analogous
#filter like this
selected = Person.objects.filter(type=SomeType)
for p in selected:
print p.id,p.type,p.status
I would suggest you to re-write your models. So, that your TblPerson has a many to one relationship with Tblstatus
class TblPerson(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'ID')
Type = models.IntegerField(null=True, db_column=u'Type', blank=True)
Status = models.ForeignKey(Tblstatus, null=True, db_column=u'Status', blank=True)
class Meta:
db_table = u'tblPerson'
class Tblstatus(models.Model):
ID = models.AutoField(primary_key=True, db_column=u'statStatusID')
Status = models.CharField(max_length=25, db_column=u'statStatus', blank=True)
class Meta:
db_table = u'tblStatus'
Using this you would be able to query for TblPerson objects for which Tblstatus exists like this
TblPerson.objects.filter(Status__isnull=False)